|
|
1.1 ! root 1: /* ! 2: * Virtio 9p Posix callback ! 3: * ! 4: * Copyright IBM, Corp. 2010 ! 5: * ! 6: * Authors: ! 7: * Anthony Liguori <[email protected]> ! 8: * ! 9: * This work is licensed under the terms of the GNU GPL, version 2. See ! 10: * the COPYING file in the top-level directory. ! 11: * ! 12: */ ! 13: ! 14: #include "hw/virtio.h" ! 15: #include "virtio-9p.h" ! 16: #include "virtio-9p-xattr.h" ! 17: #include <arpa/inet.h> ! 18: #include <pwd.h> ! 19: #include <grp.h> ! 20: #include <sys/socket.h> ! 21: #include <sys/un.h> ! 22: #include <attr/xattr.h> ! 23: ! 24: ! 25: static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf) ! 26: { ! 27: int err; ! 28: char buffer[PATH_MAX]; ! 29: err = lstat(rpath(fs_ctx, path, buffer), stbuf); ! 30: if (err) { ! 31: return err; ! 32: } ! 33: if (fs_ctx->fs_sm == SM_MAPPED) { ! 34: /* Actual credentials are part of extended attrs */ ! 35: uid_t tmp_uid; ! 36: gid_t tmp_gid; ! 37: mode_t tmp_mode; ! 38: dev_t tmp_dev; ! 39: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.uid", &tmp_uid, ! 40: sizeof(uid_t)) > 0) { ! 41: stbuf->st_uid = tmp_uid; ! 42: } ! 43: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.gid", &tmp_gid, ! 44: sizeof(gid_t)) > 0) { ! 45: stbuf->st_gid = tmp_gid; ! 46: } ! 47: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.mode", ! 48: &tmp_mode, sizeof(mode_t)) > 0) { ! 49: stbuf->st_mode = tmp_mode; ! 50: } ! 51: if (getxattr(rpath(fs_ctx, path, buffer), "user.virtfs.rdev", &tmp_dev, ! 52: sizeof(dev_t)) > 0) { ! 53: stbuf->st_rdev = tmp_dev; ! 54: } ! 55: } ! 56: return err; ! 57: } ! 58: ! 59: static int local_set_xattr(const char *path, FsCred *credp) ! 60: { ! 61: int err; ! 62: if (credp->fc_uid != -1) { ! 63: err = setxattr(path, "user.virtfs.uid", &credp->fc_uid, sizeof(uid_t), ! 64: 0); ! 65: if (err) { ! 66: return err; ! 67: } ! 68: } ! 69: if (credp->fc_gid != -1) { ! 70: err = setxattr(path, "user.virtfs.gid", &credp->fc_gid, sizeof(gid_t), ! 71: 0); ! 72: if (err) { ! 73: return err; ! 74: } ! 75: } ! 76: if (credp->fc_mode != -1) { ! 77: err = setxattr(path, "user.virtfs.mode", &credp->fc_mode, ! 78: sizeof(mode_t), 0); ! 79: if (err) { ! 80: return err; ! 81: } ! 82: } ! 83: if (credp->fc_rdev != -1) { ! 84: err = setxattr(path, "user.virtfs.rdev", &credp->fc_rdev, ! 85: sizeof(dev_t), 0); ! 86: if (err) { ! 87: return err; ! 88: } ! 89: } ! 90: return 0; ! 91: } ! 92: ! 93: static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, ! 94: FsCred *credp) ! 95: { ! 96: char buffer[PATH_MAX]; ! 97: if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) { ! 98: return -1; ! 99: } ! 100: if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, ! 101: credp->fc_gid) < 0) { ! 102: /* ! 103: * If we fail to change ownership and if we are ! 104: * using security model none. Ignore the error ! 105: */ ! 106: if (fs_ctx->fs_sm != SM_NONE) { ! 107: return -1; ! 108: } ! 109: } ! 110: return 0; ! 111: } ! 112: ! 113: static ssize_t local_readlink(FsContext *fs_ctx, const char *path, ! 114: char *buf, size_t bufsz) ! 115: { ! 116: ssize_t tsize = -1; ! 117: char buffer[PATH_MAX]; ! 118: if (fs_ctx->fs_sm == SM_MAPPED) { ! 119: int fd; ! 120: fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); ! 121: if (fd == -1) { ! 122: return -1; ! 123: } ! 124: do { ! 125: tsize = read(fd, (void *)buf, bufsz); ! 126: } while (tsize == -1 && errno == EINTR); ! 127: close(fd); ! 128: return tsize; ! 129: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 130: (fs_ctx->fs_sm == SM_NONE)) { ! 131: tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz); ! 132: } ! 133: return tsize; ! 134: } ! 135: ! 136: static int local_close(FsContext *ctx, int fd) ! 137: { ! 138: return close(fd); ! 139: } ! 140: ! 141: static int local_closedir(FsContext *ctx, DIR *dir) ! 142: { ! 143: return closedir(dir); ! 144: } ! 145: ! 146: static int local_open(FsContext *ctx, const char *path, int flags) ! 147: { ! 148: char buffer[PATH_MAX]; ! 149: return open(rpath(ctx, path, buffer), flags); ! 150: } ! 151: ! 152: static DIR *local_opendir(FsContext *ctx, const char *path) ! 153: { ! 154: char buffer[PATH_MAX]; ! 155: return opendir(rpath(ctx, path, buffer)); ! 156: } ! 157: ! 158: static void local_rewinddir(FsContext *ctx, DIR *dir) ! 159: { ! 160: return rewinddir(dir); ! 161: } ! 162: ! 163: static off_t local_telldir(FsContext *ctx, DIR *dir) ! 164: { ! 165: return telldir(dir); ! 166: } ! 167: ! 168: static struct dirent *local_readdir(FsContext *ctx, DIR *dir) ! 169: { ! 170: return readdir(dir); ! 171: } ! 172: ! 173: static void local_seekdir(FsContext *ctx, DIR *dir, off_t off) ! 174: { ! 175: return seekdir(dir, off); ! 176: } ! 177: ! 178: static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov, ! 179: int iovcnt, off_t offset) ! 180: { ! 181: #ifdef CONFIG_PREADV ! 182: return preadv(fd, iov, iovcnt, offset); ! 183: #else ! 184: int err = lseek(fd, offset, SEEK_SET); ! 185: if (err == -1) { ! 186: return err; ! 187: } else { ! 188: return readv(fd, iov, iovcnt); ! 189: } ! 190: #endif ! 191: } ! 192: ! 193: static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, ! 194: int iovcnt, off_t offset) ! 195: { ! 196: #ifdef CONFIG_PREADV ! 197: return pwritev(fd, iov, iovcnt, offset); ! 198: #else ! 199: int err = lseek(fd, offset, SEEK_SET); ! 200: if (err == -1) { ! 201: return err; ! 202: } else { ! 203: return writev(fd, iov, iovcnt); ! 204: } ! 205: #endif ! 206: } ! 207: ! 208: static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp) ! 209: { ! 210: char buffer[PATH_MAX]; ! 211: if (fs_ctx->fs_sm == SM_MAPPED) { ! 212: return local_set_xattr(rpath(fs_ctx, path, buffer), credp); ! 213: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 214: (fs_ctx->fs_sm == SM_NONE)) { ! 215: return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); ! 216: } ! 217: return -1; ! 218: } ! 219: ! 220: static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp) ! 221: { ! 222: int err = -1; ! 223: int serrno = 0; ! 224: char buffer[PATH_MAX]; ! 225: ! 226: /* Determine the security model */ ! 227: if (fs_ctx->fs_sm == SM_MAPPED) { ! 228: err = mknod(rpath(fs_ctx, path, buffer), ! 229: SM_LOCAL_MODE_BITS|S_IFREG, 0); ! 230: if (err == -1) { ! 231: return err; ! 232: } ! 233: local_set_xattr(rpath(fs_ctx, path, buffer), credp); ! 234: if (err == -1) { ! 235: serrno = errno; ! 236: goto err_end; ! 237: } ! 238: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 239: (fs_ctx->fs_sm == SM_NONE)) { ! 240: err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, ! 241: credp->fc_rdev); ! 242: if (err == -1) { ! 243: return err; ! 244: } ! 245: err = local_post_create_passthrough(fs_ctx, path, credp); ! 246: if (err == -1) { ! 247: serrno = errno; ! 248: goto err_end; ! 249: } ! 250: } ! 251: return err; ! 252: ! 253: err_end: ! 254: remove(rpath(fs_ctx, path, buffer)); ! 255: errno = serrno; ! 256: return err; ! 257: } ! 258: ! 259: static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp) ! 260: { ! 261: int err = -1; ! 262: int serrno = 0; ! 263: char buffer[PATH_MAX]; ! 264: ! 265: /* Determine the security model */ ! 266: if (fs_ctx->fs_sm == SM_MAPPED) { ! 267: err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); ! 268: if (err == -1) { ! 269: return err; ! 270: } ! 271: credp->fc_mode = credp->fc_mode|S_IFDIR; ! 272: err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); ! 273: if (err == -1) { ! 274: serrno = errno; ! 275: goto err_end; ! 276: } ! 277: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 278: (fs_ctx->fs_sm == SM_NONE)) { ! 279: err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); ! 280: if (err == -1) { ! 281: return err; ! 282: } ! 283: err = local_post_create_passthrough(fs_ctx, path, credp); ! 284: if (err == -1) { ! 285: serrno = errno; ! 286: goto err_end; ! 287: } ! 288: } ! 289: return err; ! 290: ! 291: err_end: ! 292: remove(rpath(fs_ctx, path, buffer)); ! 293: errno = serrno; ! 294: return err; ! 295: } ! 296: ! 297: static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) ! 298: { ! 299: int err; ! 300: err = fstat(fd, stbuf); ! 301: if (err) { ! 302: return err; ! 303: } ! 304: if (fs_ctx->fs_sm == SM_MAPPED) { ! 305: /* Actual credentials are part of extended attrs */ ! 306: uid_t tmp_uid; ! 307: gid_t tmp_gid; ! 308: mode_t tmp_mode; ! 309: dev_t tmp_dev; ! 310: ! 311: if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { ! 312: stbuf->st_uid = tmp_uid; ! 313: } ! 314: if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { ! 315: stbuf->st_gid = tmp_gid; ! 316: } ! 317: if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { ! 318: stbuf->st_mode = tmp_mode; ! 319: } ! 320: if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { ! 321: stbuf->st_rdev = tmp_dev; ! 322: } ! 323: } ! 324: return err; ! 325: } ! 326: ! 327: static int local_open2(FsContext *fs_ctx, const char *path, int flags, ! 328: FsCred *credp) ! 329: { ! 330: int fd = -1; ! 331: int err = -1; ! 332: int serrno = 0; ! 333: char buffer[PATH_MAX]; ! 334: ! 335: /* Determine the security model */ ! 336: if (fs_ctx->fs_sm == SM_MAPPED) { ! 337: fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); ! 338: if (fd == -1) { ! 339: return fd; ! 340: } ! 341: credp->fc_mode = credp->fc_mode|S_IFREG; ! 342: /* Set cleint credentials in xattr */ ! 343: err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); ! 344: if (err == -1) { ! 345: serrno = errno; ! 346: goto err_end; ! 347: } ! 348: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 349: (fs_ctx->fs_sm == SM_NONE)) { ! 350: fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); ! 351: if (fd == -1) { ! 352: return fd; ! 353: } ! 354: err = local_post_create_passthrough(fs_ctx, path, credp); ! 355: if (err == -1) { ! 356: serrno = errno; ! 357: goto err_end; ! 358: } ! 359: } ! 360: return fd; ! 361: ! 362: err_end: ! 363: close(fd); ! 364: remove(rpath(fs_ctx, path, buffer)); ! 365: errno = serrno; ! 366: return err; ! 367: } ! 368: ! 369: ! 370: static int local_symlink(FsContext *fs_ctx, const char *oldpath, ! 371: const char *newpath, FsCred *credp) ! 372: { ! 373: int err = -1; ! 374: int serrno = 0; ! 375: char buffer[PATH_MAX]; ! 376: ! 377: /* Determine the security model */ ! 378: if (fs_ctx->fs_sm == SM_MAPPED) { ! 379: int fd; ! 380: ssize_t oldpath_size, write_size; ! 381: fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, ! 382: SM_LOCAL_MODE_BITS); ! 383: if (fd == -1) { ! 384: return fd; ! 385: } ! 386: /* Write the oldpath (target) to the file. */ ! 387: oldpath_size = strlen(oldpath); ! 388: do { ! 389: write_size = write(fd, (void *)oldpath, oldpath_size); ! 390: } while (write_size == -1 && errno == EINTR); ! 391: ! 392: if (write_size != oldpath_size) { ! 393: serrno = errno; ! 394: close(fd); ! 395: err = -1; ! 396: goto err_end; ! 397: } ! 398: close(fd); ! 399: /* Set cleint credentials in symlink's xattr */ ! 400: credp->fc_mode = credp->fc_mode|S_IFLNK; ! 401: err = local_set_xattr(rpath(fs_ctx, newpath, buffer), credp); ! 402: if (err == -1) { ! 403: serrno = errno; ! 404: goto err_end; ! 405: } ! 406: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 407: (fs_ctx->fs_sm == SM_NONE)) { ! 408: err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); ! 409: if (err) { ! 410: return err; ! 411: } ! 412: err = lchown(rpath(fs_ctx, newpath, buffer), credp->fc_uid, ! 413: credp->fc_gid); ! 414: if (err == -1) { ! 415: /* ! 416: * If we fail to change ownership and if we are ! 417: * using security model none. Ignore the error ! 418: */ ! 419: if (fs_ctx->fs_sm != SM_NONE) { ! 420: serrno = errno; ! 421: goto err_end; ! 422: } else ! 423: err = 0; ! 424: } ! 425: } ! 426: return err; ! 427: ! 428: err_end: ! 429: remove(rpath(fs_ctx, newpath, buffer)); ! 430: errno = serrno; ! 431: return err; ! 432: } ! 433: ! 434: static int local_link(FsContext *ctx, const char *oldpath, const char *newpath) ! 435: { ! 436: char buffer[PATH_MAX], buffer1[PATH_MAX]; ! 437: ! 438: return link(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); ! 439: } ! 440: ! 441: static int local_truncate(FsContext *ctx, const char *path, off_t size) ! 442: { ! 443: char buffer[PATH_MAX]; ! 444: return truncate(rpath(ctx, path, buffer), size); ! 445: } ! 446: ! 447: static int local_rename(FsContext *ctx, const char *oldpath, ! 448: const char *newpath) ! 449: { ! 450: char buffer[PATH_MAX], buffer1[PATH_MAX]; ! 451: ! 452: return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1)); ! 453: } ! 454: ! 455: static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp) ! 456: { ! 457: char buffer[PATH_MAX]; ! 458: if ((credp->fc_uid == -1 && credp->fc_gid == -1) || ! 459: (fs_ctx->fs_sm == SM_PASSTHROUGH)) { ! 460: return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, ! 461: credp->fc_gid); ! 462: } else if (fs_ctx->fs_sm == SM_MAPPED) { ! 463: return local_set_xattr(rpath(fs_ctx, path, buffer), credp); ! 464: } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || ! 465: (fs_ctx->fs_sm == SM_NONE)) { ! 466: return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, ! 467: credp->fc_gid); ! 468: } ! 469: return -1; ! 470: } ! 471: ! 472: static int local_utimensat(FsContext *s, const char *path, ! 473: const struct timespec *buf) ! 474: { ! 475: char buffer[PATH_MAX]; ! 476: return qemu_utimensat(AT_FDCWD, rpath(s, path, buffer), buf, ! 477: AT_SYMLINK_NOFOLLOW); ! 478: } ! 479: ! 480: static int local_remove(FsContext *ctx, const char *path) ! 481: { ! 482: char buffer[PATH_MAX]; ! 483: return remove(rpath(ctx, path, buffer)); ! 484: } ! 485: ! 486: static int local_fsync(FsContext *ctx, int fd, int datasync) ! 487: { ! 488: if (datasync) { ! 489: return qemu_fdatasync(fd); ! 490: } else { ! 491: return fsync(fd); ! 492: } ! 493: } ! 494: ! 495: static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf) ! 496: { ! 497: char buffer[PATH_MAX]; ! 498: return statfs(rpath(s, path, buffer), stbuf); ! 499: } ! 500: ! 501: static ssize_t local_lgetxattr(FsContext *ctx, const char *path, ! 502: const char *name, void *value, size_t size) ! 503: { ! 504: return v9fs_get_xattr(ctx, path, name, value, size); ! 505: } ! 506: ! 507: static ssize_t local_llistxattr(FsContext *ctx, const char *path, ! 508: void *value, size_t size) ! 509: { ! 510: return v9fs_list_xattr(ctx, path, value, size); ! 511: } ! 512: ! 513: static int local_lsetxattr(FsContext *ctx, const char *path, const char *name, ! 514: void *value, size_t size, int flags) ! 515: { ! 516: return v9fs_set_xattr(ctx, path, name, value, size, flags); ! 517: } ! 518: ! 519: static int local_lremovexattr(FsContext *ctx, ! 520: const char *path, const char *name) ! 521: { ! 522: return v9fs_remove_xattr(ctx, path, name); ! 523: } ! 524: ! 525: ! 526: FileOperations local_ops = { ! 527: .lstat = local_lstat, ! 528: .readlink = local_readlink, ! 529: .close = local_close, ! 530: .closedir = local_closedir, ! 531: .open = local_open, ! 532: .opendir = local_opendir, ! 533: .rewinddir = local_rewinddir, ! 534: .telldir = local_telldir, ! 535: .readdir = local_readdir, ! 536: .seekdir = local_seekdir, ! 537: .preadv = local_preadv, ! 538: .pwritev = local_pwritev, ! 539: .chmod = local_chmod, ! 540: .mknod = local_mknod, ! 541: .mkdir = local_mkdir, ! 542: .fstat = local_fstat, ! 543: .open2 = local_open2, ! 544: .symlink = local_symlink, ! 545: .link = local_link, ! 546: .truncate = local_truncate, ! 547: .rename = local_rename, ! 548: .chown = local_chown, ! 549: .utimensat = local_utimensat, ! 550: .remove = local_remove, ! 551: .fsync = local_fsync, ! 552: .statfs = local_statfs, ! 553: .lgetxattr = local_lgetxattr, ! 554: .llistxattr = local_llistxattr, ! 555: .lsetxattr = local_lsetxattr, ! 556: .lremovexattr = local_lremovexattr, ! 557: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.