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