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