]> git.proxmox.com Git - mirror_qemu.git/blame - hw/virtio-9p-local.c
virtio-9p: Fix the memset usage
[mirror_qemu.git] / hw / virtio-9p-local.c
CommitLineData
9f107513
AL
1/*
2 * Virtio 9p Posix callback
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
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"
c494dd6f 15#include <arpa/inet.h>
131dcb25
AL
16#include <pwd.h>
17#include <grp.h>
c494dd6f
AL
18#include <sys/socket.h>
19#include <sys/un.h>
758e8e38 20#include <attr/xattr.h>
131dcb25
AL
21
22static 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
1237ad76
VJ
30
31static int local_lstat(FsContext *fs_ctx, const char *path, struct stat *stbuf)
131dcb25 32{
1237ad76
VJ
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;
131dcb25
AL
62}
63
758e8e38 64static int local_set_xattr(const char *path, FsCred *credp)
131dcb25 65{
758e8e38
VJ
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 }
131dcb25 73 }
758e8e38
VJ
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 }
131dcb25 80 }
758e8e38
VJ
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 }
131dcb25 87 }
758e8e38
VJ
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 }
131dcb25 94 }
131dcb25
AL
95 return 0;
96}
97
4750a96f
VJ
98static 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 }
5c0f255d 104 if (lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid) < 0) {
12848bfc
AK
105 /*
106 * If we fail to change ownership and if we are
107 * using security model none. Ignore the error
108 */
109 if (fs_ctx->fs_sm != SM_NONE) {
110 return -1;
111 }
4750a96f
VJ
112 }
113 return 0;
114}
115
879c2813
VJ
116static ssize_t local_readlink(FsContext *fs_ctx, const char *path,
117 char *buf, size_t bufsz)
131dcb25 118{
879c2813
VJ
119 ssize_t tsize = -1;
120 if (fs_ctx->fs_sm == SM_MAPPED) {
121 int fd;
122 fd = open(rpath(fs_ctx, path), O_RDONLY);
123 if (fd == -1) {
124 return -1;
125 }
126 do {
127 tsize = read(fd, (void *)buf, bufsz);
128 } while (tsize == -1 && errno == EINTR);
129 close(fd);
130 return tsize;
12848bfc
AK
131 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
132 (fs_ctx->fs_sm == SM_NONE)) {
879c2813
VJ
133 tsize = readlink(rpath(fs_ctx, path), buf, bufsz);
134 }
135 return tsize;
131dcb25
AL
136}
137
138static int local_close(FsContext *ctx, int fd)
139{
140 return close(fd);
141}
142
143static int local_closedir(FsContext *ctx, DIR *dir)
144{
145 return closedir(dir);
146}
9f107513 147
a6568fe2
AL
148static int local_open(FsContext *ctx, const char *path, int flags)
149{
150 return open(rpath(ctx, path), flags);
151}
152
153static DIR *local_opendir(FsContext *ctx, const char *path)
154{
155 return opendir(rpath(ctx, path));
156}
157
a9231555
AL
158static void local_rewinddir(FsContext *ctx, DIR *dir)
159{
160 return rewinddir(dir);
161}
162
163static off_t local_telldir(FsContext *ctx, DIR *dir)
164{
165 return telldir(dir);
166}
167
168static struct dirent *local_readdir(FsContext *ctx, DIR *dir)
169{
170 return readdir(dir);
171}
172
173static void local_seekdir(FsContext *ctx, DIR *dir, off_t off)
174{
175 return seekdir(dir, off);
176}
177
178static ssize_t local_readv(FsContext *ctx, int fd, const struct iovec *iov,
179 int iovcnt)
180{
181 return readv(fd, iov, iovcnt);
182}
183
184static off_t local_lseek(FsContext *ctx, int fd, off_t offset, int whence)
185{
186 return lseek(fd, offset, whence);
187}
188
8449360c
AL
189static ssize_t local_writev(FsContext *ctx, int fd, const struct iovec *iov,
190 int iovcnt)
191{
192 return writev(fd, iov, iovcnt);
193}
194
e95ead32 195static int local_chmod(FsContext *fs_ctx, const char *path, FsCred *credp)
c494dd6f 196{
e95ead32
VJ
197 if (fs_ctx->fs_sm == SM_MAPPED) {
198 return local_set_xattr(rpath(fs_ctx, path), credp);
12848bfc
AK
199 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
200 (fs_ctx->fs_sm == SM_NONE)) {
e95ead32
VJ
201 return chmod(rpath(fs_ctx, path), credp->fc_mode);
202 }
203 return -1;
c494dd6f
AL
204}
205
1c293312 206static int local_mknod(FsContext *fs_ctx, const char *path, FsCred *credp)
c494dd6f 207{
1c293312
VJ
208 int err = -1;
209 int serrno = 0;
210
211 /* Determine the security model */
212 if (fs_ctx->fs_sm == SM_MAPPED) {
213 err = mknod(rpath(fs_ctx, path), SM_LOCAL_MODE_BITS|S_IFREG, 0);
214 if (err == -1) {
215 return err;
216 }
217 local_set_xattr(rpath(fs_ctx, path), credp);
218 if (err == -1) {
219 serrno = errno;
220 goto err_end;
221 }
12848bfc
AK
222 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
223 (fs_ctx->fs_sm == SM_NONE)) {
1c293312
VJ
224 err = mknod(rpath(fs_ctx, path), credp->fc_mode, credp->fc_rdev);
225 if (err == -1) {
226 return err;
227 }
228 err = local_post_create_passthrough(fs_ctx, path, credp);
229 if (err == -1) {
230 serrno = errno;
231 goto err_end;
232 }
233 }
234 return err;
235
236err_end:
237 remove(rpath(fs_ctx, path));
238 errno = serrno;
239 return err;
c494dd6f
AL
240}
241
00ec5c37 242static int local_mkdir(FsContext *fs_ctx, const char *path, FsCred *credp)
c494dd6f 243{
00ec5c37
VJ
244 int err = -1;
245 int serrno = 0;
246
247 /* Determine the security model */
248 if (fs_ctx->fs_sm == SM_MAPPED) {
249 err = mkdir(rpath(fs_ctx, path), SM_LOCAL_DIR_MODE_BITS);
250 if (err == -1) {
251 return err;
252 }
253 credp->fc_mode = credp->fc_mode|S_IFDIR;
254 err = local_set_xattr(rpath(fs_ctx, path), credp);
255 if (err == -1) {
256 serrno = errno;
257 goto err_end;
258 }
12848bfc
AK
259 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
260 (fs_ctx->fs_sm == SM_NONE)) {
00ec5c37
VJ
261 err = mkdir(rpath(fs_ctx, path), credp->fc_mode);
262 if (err == -1) {
263 return err;
264 }
265 err = local_post_create_passthrough(fs_ctx, path, credp);
266 if (err == -1) {
267 serrno = errno;
268 goto err_end;
269 }
270 }
271 return err;
272
273err_end:
274 remove(rpath(fs_ctx, path));
275 errno = serrno;
276 return err;
c494dd6f
AL
277}
278
1237ad76 279static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
c494dd6f 280{
1237ad76
VJ
281 int err;
282 err = fstat(fd, stbuf);
283 if (err) {
284 return err;
285 }
286 if (fs_ctx->fs_sm == SM_MAPPED) {
287 /* Actual credentials are part of extended attrs */
288 uid_t tmp_uid;
289 gid_t tmp_gid;
290 mode_t tmp_mode;
291 dev_t tmp_dev;
292
293 if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) {
294 stbuf->st_uid = tmp_uid;
295 }
296 if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) {
297 stbuf->st_gid = tmp_gid;
298 }
299 if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) {
300 stbuf->st_mode = tmp_mode;
301 }
302 if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) {
303 stbuf->st_rdev = tmp_dev;
304 }
305 }
306 return err;
c494dd6f
AL
307}
308
4750a96f
VJ
309static int local_open2(FsContext *fs_ctx, const char *path, int flags,
310 FsCred *credp)
c494dd6f 311{
4750a96f
VJ
312 int fd = -1;
313 int err = -1;
314 int serrno = 0;
315
316 /* Determine the security model */
317 if (fs_ctx->fs_sm == SM_MAPPED) {
318 fd = open(rpath(fs_ctx, path), flags, SM_LOCAL_MODE_BITS);
319 if (fd == -1) {
320 return fd;
321 }
322 credp->fc_mode = credp->fc_mode|S_IFREG;
323 /* Set cleint credentials in xattr */
324 err = local_set_xattr(rpath(fs_ctx, path), credp);
325 if (err == -1) {
326 serrno = errno;
327 goto err_end;
328 }
12848bfc
AK
329 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
330 (fs_ctx->fs_sm == SM_NONE)) {
4750a96f
VJ
331 fd = open(rpath(fs_ctx, path), flags, credp->fc_mode);
332 if (fd == -1) {
333 return fd;
334 }
335 err = local_post_create_passthrough(fs_ctx, path, credp);
336 if (err == -1) {
337 serrno = errno;
338 goto err_end;
339 }
340 }
341 return fd;
342
343err_end:
344 close(fd);
345 remove(rpath(fs_ctx, path));
346 errno = serrno;
347 return err;
c494dd6f
AL
348}
349
758e8e38 350
879c2813
VJ
351static int local_symlink(FsContext *fs_ctx, const char *oldpath,
352 const char *newpath, FsCred *credp)
c494dd6f 353{
879c2813
VJ
354 int err = -1;
355 int serrno = 0;
356
357 /* Determine the security model */
358 if (fs_ctx->fs_sm == SM_MAPPED) {
359 int fd;
360 ssize_t oldpath_size, write_size;
361 fd = open(rpath(fs_ctx, newpath), O_CREAT|O_EXCL|O_RDWR,
362 SM_LOCAL_MODE_BITS);
363 if (fd == -1) {
364 return fd;
365 }
366 /* Write the oldpath (target) to the file. */
367 oldpath_size = strlen(oldpath) + 1;
368 do {
369 write_size = write(fd, (void *)oldpath, oldpath_size);
370 } while (write_size == -1 && errno == EINTR);
371
372 if (write_size != oldpath_size) {
373 serrno = errno;
374 close(fd);
375 err = -1;
376 goto err_end;
377 }
378 close(fd);
379 /* Set cleint credentials in symlink's xattr */
380 credp->fc_mode = credp->fc_mode|S_IFLNK;
381 err = local_set_xattr(rpath(fs_ctx, newpath), credp);
382 if (err == -1) {
383 serrno = errno;
384 goto err_end;
385 }
12848bfc
AK
386 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
387 (fs_ctx->fs_sm == SM_NONE)) {
879c2813
VJ
388 err = symlink(oldpath, rpath(fs_ctx, newpath));
389 if (err) {
390 return err;
391 }
392 err = lchown(rpath(fs_ctx, newpath), credp->fc_uid, credp->fc_gid);
393 if (err == -1) {
12848bfc
AK
394 /*
395 * If we fail to change ownership and if we are
396 * using security model none. Ignore the error
397 */
398 if (fs_ctx->fs_sm != SM_NONE) {
399 serrno = errno;
400 goto err_end;
401 } else
402 err = 0;
879c2813
VJ
403 }
404 }
405 return err;
406
407err_end:
408 remove(rpath(fs_ctx, newpath));
409 errno = serrno;
410 return err;
c494dd6f
AL
411}
412
413static int local_link(FsContext *ctx, const char *oldpath, const char *newpath)
414{
415 char *tmp = qemu_strdup(rpath(ctx, oldpath));
416 int err, serrno = 0;
417
418 if (tmp == NULL) {
419 return -ENOMEM;
420 }
421
422 err = link(tmp, rpath(ctx, newpath));
423 if (err == -1) {
424 serrno = errno;
425 }
426
427 qemu_free(tmp);
428
429 if (err == -1) {
430 errno = serrno;
431 }
432
433 return err;
434}
435
8cf89e00
AL
436static int local_truncate(FsContext *ctx, const char *path, off_t size)
437{
438 return truncate(rpath(ctx, path), size);
439}
440
441static int local_rename(FsContext *ctx, const char *oldpath,
442 const char *newpath)
443{
444 char *tmp;
445 int err;
446
447 tmp = qemu_strdup(rpath(ctx, oldpath));
8cf89e00
AL
448
449 err = rename(tmp, rpath(ctx, newpath));
450 if (err == -1) {
451 int serrno = errno;
452 qemu_free(tmp);
453 errno = serrno;
454 } else {
455 qemu_free(tmp);
456 }
457
458 return err;
459
460}
461
f7613bee 462static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
8cf89e00 463{
c79ce737
SK
464 if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
465 (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
466 return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
467 } else if (fs_ctx->fs_sm == SM_MAPPED) {
f7613bee 468 return local_set_xattr(rpath(fs_ctx, path), credp);
12848bfc
AK
469 } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) ||
470 (fs_ctx->fs_sm == SM_NONE)) {
f7613bee
VJ
471 return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
472 }
473 return -1;
8cf89e00
AL
474}
475
74bc02b2
MK
476static int local_utimensat(FsContext *s, const char *path,
477 const struct timespec *buf)
8cf89e00 478{
74bc02b2 479 return utimensat(AT_FDCWD, rpath(s, path), buf, AT_SYMLINK_NOFOLLOW);
8cf89e00
AL
480}
481
5bae1900
AL
482static int local_remove(FsContext *ctx, const char *path)
483{
484 return remove(rpath(ctx, path));
485}
486
8cf89e00
AL
487static int local_fsync(FsContext *ctx, int fd)
488{
489 return fsync(fd);
490}
491
be940c87
MK
492static int local_statfs(FsContext *s, const char *path, struct statfs *stbuf)
493{
494 return statfs(rpath(s, path), stbuf);
495}
496
fa32ef88
AK
497static ssize_t local_lgetxattr(FsContext *ctx, const char *path,
498 const char *name, void *value, size_t size)
499{
61b6c499
AK
500 if ((ctx->fs_sm == SM_MAPPED) &&
501 (strncmp(name, "user.virtfs.", 12) == 0)) {
502 /*
503 * Don't allow fetch of user.virtfs namesapce
504 * in case of mapped security
505 */
506 errno = ENOATTR;
507 return -1;
508 }
509
fa32ef88
AK
510 return lgetxattr(rpath(ctx, path), name, value, size);
511}
512
513static ssize_t local_llistxattr(FsContext *ctx, const char *path,
514 void *value, size_t size)
515{
61b6c499
AK
516 ssize_t retval;
517 ssize_t actual_len = 0;
518 char *orig_value, *orig_value_start;
519 char *temp_value, *temp_value_start;
520 ssize_t xattr_len, parsed_len = 0, attr_len;
521
522 if (ctx->fs_sm != SM_MAPPED) {
523 return llistxattr(rpath(ctx, path), value, size);
524 }
525
526 /* Get the actual len */
527 xattr_len = llistxattr(rpath(ctx, path), value, 0);
528
529 /* Now fetch the xattr and find the actual size */
530 orig_value = qemu_malloc(xattr_len);
531 xattr_len = llistxattr(rpath(ctx, path), orig_value, xattr_len);
532
533 /*
534 * For mapped security model drop user.virtfs namespace
535 * from the list
536 */
537 temp_value = qemu_mallocz(xattr_len);
538 temp_value_start = temp_value;
539 orig_value_start = orig_value;
540 while (xattr_len > parsed_len) {
541 attr_len = strlen(orig_value) + 1;
542 if (strncmp(orig_value, "user.virtfs.", 12) != 0) {
543 /* Copy this entry */
544 strcat(temp_value, orig_value);
545 temp_value += attr_len;
546 actual_len += attr_len;
547 }
548 parsed_len += attr_len;
549 orig_value += attr_len;
550 }
551 if (!size) {
552 retval = actual_len;
553 goto out;
554 } else if (size >= actual_len) {
555 /* now copy the parsed attribute list back */
556 memset(value, 0, size);
557 memcpy(value, temp_value_start, actual_len);
558 retval = actual_len;
559 goto out;
560 }
561 errno = ERANGE;
562 retval = -1;
563out:
564 qemu_free(orig_value_start);
565 qemu_free(temp_value_start);
566 return retval;
fa32ef88
AK
567}
568
10b468bd
AK
569static int local_lsetxattr(FsContext *ctx, const char *path, const char *name,
570 void *value, size_t size, int flags)
571{
61b6c499
AK
572 if ((ctx->fs_sm == SM_MAPPED) &&
573 (strncmp(name, "user.virtfs.", 12) == 0)) {
574 /*
575 * Don't allow fetch of user.virtfs namesapce
576 * in case of mapped security
577 */
578 errno = EACCES;
579 return -1;
580 }
10b468bd
AK
581 return lsetxattr(rpath(ctx, path), name, value, size, flags);
582}
583
9f107513 584FileOperations local_ops = {
131dcb25 585 .lstat = local_lstat,
131dcb25
AL
586 .readlink = local_readlink,
587 .close = local_close,
588 .closedir = local_closedir,
a6568fe2
AL
589 .open = local_open,
590 .opendir = local_opendir,
a9231555
AL
591 .rewinddir = local_rewinddir,
592 .telldir = local_telldir,
593 .readdir = local_readdir,
594 .seekdir = local_seekdir,
595 .readv = local_readv,
596 .lseek = local_lseek,
8449360c 597 .writev = local_writev,
c494dd6f
AL
598 .chmod = local_chmod,
599 .mknod = local_mknod,
c494dd6f
AL
600 .mkdir = local_mkdir,
601 .fstat = local_fstat,
602 .open2 = local_open2,
603 .symlink = local_symlink,
604 .link = local_link,
8cf89e00
AL
605 .truncate = local_truncate,
606 .rename = local_rename,
607 .chown = local_chown,
74bc02b2 608 .utimensat = local_utimensat,
5bae1900 609 .remove = local_remove,
8cf89e00 610 .fsync = local_fsync,
be940c87 611 .statfs = local_statfs,
fa32ef88
AK
612 .lgetxattr = local_lgetxattr,
613 .llistxattr = local_llistxattr,
10b468bd 614 .lsetxattr = local_lsetxattr,
9f107513 615};