1 /* 2 * Helper for QEMU Proxy FS Driver 3 * Copyright IBM, Corp. 2011 4 * 5 * Authors: 6 * M. Mohan Kumar <mohan@in.ibm.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2. See 9 * the COPYING file in the top-level directory. 10 */ 11 12 /* 13 * NOTE: The 9p 'proxy' backend is deprecated (since QEMU 8.1) and will be 14 * removed in a future version of QEMU! 15 */ 16 17 #include "qemu/osdep.h" 18 #include <glib/gstdio.h> 19 #include <sys/resource.h> 20 #include <getopt.h> 21 #include <syslog.h> 22 #include <sys/fsuid.h> 23 #include <sys/vfs.h> 24 #include <sys/ioctl.h> 25 #include <linux/fs.h> 26 #ifdef CONFIG_LINUX_MAGIC_H 27 #include <linux/magic.h> 28 #endif 29 #include <cap-ng.h> 30 #include "qemu/sockets.h" 31 #include "qemu/xattr.h" 32 #include "9p-iov-marshal.h" 33 #include "hw/9pfs/9p-proxy.h" 34 #include "hw/9pfs/9p-util.h" 35 #include "fsdev/9p-iov-marshal.h" 36 37 #define PROGNAME "virtfs-proxy-helper" 38 39 #ifndef XFS_SUPER_MAGIC 40 #define XFS_SUPER_MAGIC 0x58465342 41 #endif 42 #ifndef EXT2_SUPER_MAGIC 43 #define EXT2_SUPER_MAGIC 0xEF53 44 #endif 45 #ifndef REISERFS_SUPER_MAGIC 46 #define REISERFS_SUPER_MAGIC 0x52654973 47 #endif 48 #ifndef BTRFS_SUPER_MAGIC 49 #define BTRFS_SUPER_MAGIC 0x9123683E 50 #endif 51 52 static const struct option helper_opts[] = { 53 {"fd", required_argument, NULL, 'f'}, 54 {"path", required_argument, NULL, 'p'}, 55 {"nodaemon", no_argument, NULL, 'n'}, 56 {"socket", required_argument, NULL, 's'}, 57 {"uid", required_argument, NULL, 'u'}, 58 {"gid", required_argument, NULL, 'g'}, 59 {}, 60 }; 61 62 static bool is_daemon; 63 static bool get_version; /* IOC getversion IOCTL supported */ 64 static char *prog_name; 65 66 static void G_GNUC_PRINTF(2, 3) do_log(int loglevel, const char *format, ...) 67 { 68 va_list ap; 69 70 va_start(ap, format); 71 if (is_daemon) { 72 vsyslog(LOG_CRIT, format, ap); 73 } else { 74 vfprintf(stderr, format, ap); 75 } 76 va_end(ap); 77 } 78 79 static void do_perror(const char *string) 80 { 81 if (is_daemon) { 82 syslog(LOG_CRIT, "%s:%s", string, strerror(errno)); 83 } else { 84 fprintf(stderr, "%s:%s\n", string, strerror(errno)); 85 } 86 } 87 88 static int init_capabilities(void) 89 { 90 /* helper needs following capabilities only */ 91 int cap_list[] = { 92 CAP_CHOWN, 93 CAP_DAC_OVERRIDE, 94 CAP_FOWNER, 95 CAP_FSETID, 96 CAP_SETGID, 97 CAP_MKNOD, 98 CAP_SETUID, 99 }; 100 int i; 101 102 capng_clear(CAPNG_SELECT_BOTH); 103 for (i = 0; i < ARRAY_SIZE(cap_list); i++) { 104 if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, 105 cap_list[i]) < 0) { 106 do_perror("capng_update"); 107 return -1; 108 } 109 } 110 if (capng_apply(CAPNG_SELECT_BOTH) < 0) { 111 do_perror("capng_apply"); 112 return -1; 113 } 114 115 /* Prepare effective set for setugid. */ 116 for (i = 0; i < ARRAY_SIZE(cap_list); i++) { 117 if (cap_list[i] == CAP_DAC_OVERRIDE) { 118 continue; 119 } 120 121 if (capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, 122 cap_list[i]) < 0) { 123 do_perror("capng_update"); 124 return -1; 125 } 126 } 127 return 0; 128 } 129 130 static int socket_read(int sockfd, void *buff, ssize_t size) 131 { 132 ssize_t retval, total = 0; 133 134 while (size) { 135 retval = read(sockfd, buff, size); 136 if (retval == 0) { 137 return -EIO; 138 } 139 if (retval < 0) { 140 if (errno == EINTR) { 141 continue; 142 } 143 return -errno; 144 } 145 size -= retval; 146 buff += retval; 147 total += retval; 148 } 149 return total; 150 } 151 152 static int socket_write(int sockfd, void *buff, ssize_t size) 153 { 154 ssize_t retval, total = 0; 155 156 while (size) { 157 retval = write(sockfd, buff, size); 158 if (retval < 0) { 159 if (errno == EINTR) { 160 continue; 161 } 162 return -errno; 163 } 164 size -= retval; 165 buff += retval; 166 total += retval; 167 } 168 return total; 169 } 170 171 static int read_request(int sockfd, struct iovec *iovec, ProxyHeader *header) 172 { 173 int retval; 174 175 /* 176 * read the request header. 177 */ 178 iovec->iov_len = 0; 179 retval = socket_read(sockfd, iovec->iov_base, PROXY_HDR_SZ); 180 if (retval < 0) { 181 return retval; 182 } 183 iovec->iov_len = PROXY_HDR_SZ; 184 retval = proxy_unmarshal(iovec, 0, "dd", &header->type, &header->size); 185 if (retval < 0) { 186 return retval; 187 } 188 /* 189 * We can't process message.size > PROXY_MAX_IO_SZ. 190 * Treat it as fatal error 191 */ 192 if (header->size > PROXY_MAX_IO_SZ) { 193 return -ENOBUFS; 194 } 195 retval = socket_read(sockfd, iovec->iov_base + PROXY_HDR_SZ, header->size); 196 if (retval < 0) { 197 return retval; 198 } 199 iovec->iov_len += header->size; 200 return 0; 201 } 202 203 static int send_fd(int sockfd, int fd) 204 { 205 struct msghdr msg; 206 struct iovec iov; 207 int retval, data; 208 struct cmsghdr *cmsg; 209 union MsgControl msg_control; 210 211 iov.iov_base = &data; 212 iov.iov_len = sizeof(data); 213 214 memset(&msg, 0, sizeof(msg)); 215 msg.msg_iov = &iov; 216 msg.msg_iovlen = 1; 217 /* No ancillary data on error */ 218 if (fd < 0) { 219 /* fd is really negative errno if the request failed */ 220 data = fd; 221 } else { 222 data = V9FS_FD_VALID; 223 msg.msg_control = &msg_control; 224 msg.msg_controllen = sizeof(msg_control); 225 226 cmsg = &msg_control.cmsg; 227 cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 228 cmsg->cmsg_level = SOL_SOCKET; 229 cmsg->cmsg_type = SCM_RIGHTS; 230 memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 231 } 232 233 do { 234 retval = sendmsg(sockfd, &msg, 0); 235 } while (retval < 0 && errno == EINTR); 236 if (fd >= 0) { 237 close(fd); 238 } 239 if (retval < 0) { 240 return retval; 241 } 242 return 0; 243 } 244 245 static int send_status(int sockfd, struct iovec *iovec, int status) 246 { 247 ProxyHeader header; 248 int retval, msg_size; 249 250 if (status < 0) { 251 header.type = T_ERROR; 252 } else { 253 header.type = T_SUCCESS; 254 } 255 header.size = sizeof(status); 256 /* 257 * marshal the return status. We don't check error. 258 * because we are sure we have enough space for the status 259 */ 260 msg_size = proxy_marshal(iovec, 0, "ddd", header.type, 261 header.size, status); 262 if (msg_size < 0) { 263 return msg_size; 264 } 265 retval = socket_write(sockfd, iovec->iov_base, msg_size); 266 if (retval < 0) { 267 return retval; 268 } 269 return 0; 270 } 271 272 /* 273 * from man 7 capabilities, section 274 * Effect of User ID Changes on Capabilities: 275 * If the effective user ID is changed from nonzero to 0, then the permitted 276 * set is copied to the effective set. If the effective user ID is changed 277 * from 0 to nonzero, then all capabilities are are cleared from the effective 278 * set. 279 * 280 * The setfsuid/setfsgid man pages warn that changing the effective user ID may 281 * expose the program to unwanted signals, but this is not true anymore: for an 282 * unprivileged (without CAP_KILL) program to send a signal, the real or 283 * effective user ID of the sending process must equal the real or saved user 284 * ID of the target process. Even when dropping privileges, it is enough to 285 * keep the saved UID to a "privileged" value and virtfs-proxy-helper won't 286 * be exposed to signals. So just use setresuid/setresgid. 287 */ 288 static int setugid(int uid, int gid, int *suid, int *sgid) 289 { 290 int retval; 291 292 *suid = geteuid(); 293 *sgid = getegid(); 294 295 if (setresgid(-1, gid, *sgid) == -1) { 296 return -errno; 297 } 298 299 if (setresuid(-1, uid, *suid) == -1) { 300 retval = -errno; 301 goto err_sgid; 302 } 303 304 if (uid == 0 && gid == 0) { 305 /* Linux has already copied the permitted set to the effective set. */ 306 return 0; 307 } 308 309 /* 310 * All capabilities have been cleared from the effective set. However 311 * we still need DAC_OVERRIDE because we don't change supplementary 312 * group ids, and hence may be subject to DAC rules. init_capabilities 313 * left the set of capabilities that we want in libcap-ng's state. 314 */ 315 if (capng_apply(CAPNG_SELECT_CAPS) < 0) { 316 retval = -errno; 317 do_perror("capng_apply"); 318 goto err_suid; 319 } 320 return 0; 321 322 err_suid: 323 if (setresuid(-1, *suid, *suid) == -1) { 324 abort(); 325 } 326 err_sgid: 327 if (setresgid(-1, *sgid, *sgid) == -1) { 328 abort(); 329 } 330 return retval; 331 } 332 333 /* 334 * This is used to reset the ugid back with the saved values 335 * There is nothing much we can do checking error values here. 336 */ 337 static void resetugid(int suid, int sgid) 338 { 339 if (setresgid(-1, sgid, sgid) == -1) { 340 abort(); 341 } 342 if (setresuid(-1, suid, suid) == -1) { 343 abort(); 344 } 345 } 346 347 /* 348 * Open regular file or directory. Attempts to open any special file are 349 * rejected. 350 * 351 * returns file descriptor or -1 on error 352 */ 353 static int open_regular(const char *pathname, int flags, mode_t mode) 354 { 355 int fd; 356 357 fd = open(pathname, flags, mode); 358 if (fd < 0) { 359 return fd; 360 } 361 362 if (close_if_special_file(fd) < 0) { 363 return -1; 364 } 365 366 return fd; 367 } 368 369 /* 370 * send response in two parts 371 * 1) ProxyHeader 372 * 2) Response or error status 373 * This function should be called with marshaled response 374 * send_response constructs header part and error part only. 375 * send response sends {ProxyHeader,Response} if the request was success 376 * otherwise sends {ProxyHeader,error status} 377 */ 378 static int send_response(int sock, struct iovec *iovec, int size) 379 { 380 int retval; 381 ProxyHeader header; 382 383 /* 384 * If response size exceeds available iovec->iov_len, 385 * we return ENOBUFS 386 */ 387 if (size > PROXY_MAX_IO_SZ) { 388 size = -ENOBUFS; 389 } 390 391 if (size < 0) { 392 /* 393 * In case of error we would not have got the error encoded 394 * already so encode the error here. 395 */ 396 header.type = T_ERROR; 397 header.size = sizeof(size); 398 proxy_marshal(iovec, PROXY_HDR_SZ, "d", size); 399 } else { 400 header.type = T_SUCCESS; 401 header.size = size; 402 } 403 proxy_marshal(iovec, 0, "dd", header.type, header.size); 404 retval = socket_write(sock, iovec->iov_base, header.size + PROXY_HDR_SZ); 405 if (retval < 0) { 406 return retval; 407 } 408 return 0; 409 } 410 411 /* 412 * gets generation number 413 * returns -errno on failure and sizeof(generation number) on success 414 */ 415 static int do_getversion(struct iovec *iovec, struct iovec *out_iovec) 416 { 417 uint64_t version; 418 int retval = -ENOTTY; 419 #ifdef FS_IOC_GETVERSION 420 int fd; 421 V9fsString path; 422 #endif 423 424 425 /* no need to issue ioctl */ 426 if (!get_version) { 427 version = 0; 428 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "q", version); 429 return retval; 430 } 431 #ifdef FS_IOC_GETVERSION 432 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "s", &path); 433 if (retval < 0) { 434 return retval; 435 } 436 437 fd = open(path.data, O_RDONLY); 438 if (fd < 0) { 439 retval = -errno; 440 goto err_out; 441 } 442 if (ioctl(fd, FS_IOC_GETVERSION, &version) < 0) { 443 retval = -errno; 444 } else { 445 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "q", version); 446 } 447 close(fd); 448 err_out: 449 v9fs_string_free(&path); 450 #endif 451 return retval; 452 } 453 454 static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec) 455 { 456 int size = 0, offset, retval; 457 V9fsString path, name, xattr; 458 459 v9fs_string_init(&xattr); 460 v9fs_string_init(&path); 461 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "ds", &size, &path); 462 if (retval < 0) { 463 return retval; 464 } 465 offset = PROXY_HDR_SZ + retval; 466 467 if (size) { 468 xattr.data = g_malloc(size); 469 xattr.size = size; 470 } 471 switch (type) { 472 case T_LGETXATTR: 473 v9fs_string_init(&name); 474 retval = proxy_unmarshal(iovec, offset, "s", &name); 475 if (retval > 0) { 476 retval = lgetxattr(path.data, name.data, xattr.data, size); 477 if (retval < 0) { 478 retval = -errno; 479 } else { 480 xattr.size = retval; 481 } 482 } 483 v9fs_string_free(&name); 484 break; 485 case T_LLISTXATTR: 486 retval = llistxattr(path.data, xattr.data, size); 487 if (retval < 0) { 488 retval = -errno; 489 } else { 490 xattr.size = retval; 491 } 492 break; 493 } 494 if (retval < 0) { 495 goto err_out; 496 } 497 498 if (!size) { 499 proxy_marshal(out_iovec, PROXY_HDR_SZ, "d", retval); 500 retval = sizeof(retval); 501 } else { 502 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &xattr); 503 } 504 err_out: 505 v9fs_string_free(&xattr); 506 v9fs_string_free(&path); 507 return retval; 508 } 509 510 static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat) 511 { 512 memset(pr_stat, 0, sizeof(*pr_stat)); 513 pr_stat->st_dev = stat->st_dev; 514 pr_stat->st_ino = stat->st_ino; 515 pr_stat->st_nlink = stat->st_nlink; 516 pr_stat->st_mode = stat->st_mode; 517 pr_stat->st_uid = stat->st_uid; 518 pr_stat->st_gid = stat->st_gid; 519 pr_stat->st_rdev = stat->st_rdev; 520 pr_stat->st_size = stat->st_size; 521 pr_stat->st_blksize = stat->st_blksize; 522 pr_stat->st_blocks = stat->st_blocks; 523 pr_stat->st_atim_sec = stat->st_atim.tv_sec; 524 pr_stat->st_atim_nsec = stat->st_atim.tv_nsec; 525 pr_stat->st_mtim_sec = stat->st_mtim.tv_sec; 526 pr_stat->st_mtim_nsec = stat->st_mtim.tv_nsec; 527 pr_stat->st_ctim_sec = stat->st_ctim.tv_sec; 528 pr_stat->st_ctim_nsec = stat->st_ctim.tv_nsec; 529 } 530 531 static void statfs_to_prstatfs(ProxyStatFS *pr_stfs, struct statfs *stfs) 532 { 533 memset(pr_stfs, 0, sizeof(*pr_stfs)); 534 pr_stfs->f_type = stfs->f_type; 535 pr_stfs->f_bsize = stfs->f_bsize; 536 pr_stfs->f_blocks = stfs->f_blocks; 537 pr_stfs->f_bfree = stfs->f_bfree; 538 pr_stfs->f_bavail = stfs->f_bavail; 539 pr_stfs->f_files = stfs->f_files; 540 pr_stfs->f_ffree = stfs->f_ffree; 541 pr_stfs->f_fsid[0] = stfs->f_fsid.__val[0]; 542 pr_stfs->f_fsid[1] = stfs->f_fsid.__val[1]; 543 pr_stfs->f_namelen = stfs->f_namelen; 544 pr_stfs->f_frsize = stfs->f_frsize; 545 } 546 547 /* 548 * Gets stat/statfs information and packs in out_iovec structure 549 * on success returns number of bytes packed in out_iovec structure 550 * otherwise returns -errno 551 */ 552 static int do_stat(int type, struct iovec *iovec, struct iovec *out_iovec) 553 { 554 int retval; 555 V9fsString path; 556 ProxyStat pr_stat; 557 ProxyStatFS pr_stfs; 558 struct stat st_buf; 559 struct statfs stfs_buf; 560 561 v9fs_string_init(&path); 562 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "s", &path); 563 if (retval < 0) { 564 return retval; 565 } 566 567 switch (type) { 568 case T_LSTAT: 569 retval = lstat(path.data, &st_buf); 570 if (retval < 0) { 571 retval = -errno; 572 } else { 573 stat_to_prstat(&pr_stat, &st_buf); 574 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, 575 "qqqdddqqqqqqqqqq", pr_stat.st_dev, 576 pr_stat.st_ino, pr_stat.st_nlink, 577 pr_stat.st_mode, pr_stat.st_uid, 578 pr_stat.st_gid, pr_stat.st_rdev, 579 pr_stat.st_size, pr_stat.st_blksize, 580 pr_stat.st_blocks, 581 pr_stat.st_atim_sec, pr_stat.st_atim_nsec, 582 pr_stat.st_mtim_sec, pr_stat.st_mtim_nsec, 583 pr_stat.st_ctim_sec, pr_stat.st_ctim_nsec); 584 } 585 break; 586 case T_STATFS: 587 retval = statfs(path.data, &stfs_buf); 588 if (retval < 0) { 589 retval = -errno; 590 } else { 591 statfs_to_prstatfs(&pr_stfs, &stfs_buf); 592 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, 593 "qqqqqqqqqqq", pr_stfs.f_type, 594 pr_stfs.f_bsize, pr_stfs.f_blocks, 595 pr_stfs.f_bfree, pr_stfs.f_bavail, 596 pr_stfs.f_files, pr_stfs.f_ffree, 597 pr_stfs.f_fsid[0], pr_stfs.f_fsid[1], 598 pr_stfs.f_namelen, pr_stfs.f_frsize); 599 } 600 break; 601 } 602 v9fs_string_free(&path); 603 return retval; 604 } 605 606 static int do_readlink(struct iovec *iovec, struct iovec *out_iovec) 607 { 608 char *buffer; 609 int size, retval; 610 V9fsString target, path; 611 612 v9fs_string_init(&path); 613 retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sd", &path, &size); 614 if (retval < 0) { 615 v9fs_string_free(&path); 616 return retval; 617 } 618 buffer = g_malloc(size); 619 v9fs_string_init(&target); 620 retval = readlink(path.data, buffer, size - 1); 621 if (retval > 0) { 622 buffer[retval] = '\0'; 623 v9fs_string_sprintf(&target, "%s", buffer); 624 retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &target); 625 } else { 626 retval = -errno; 627 } 628 g_free(buffer); 629 v9fs_string_free(&target); 630 v9fs_string_free(&path); 631 return retval; 632 } 633 634 /* 635 * create other filesystem objects and send 0 on success 636 * return -errno on error 637 */ 638 static int do_create_others(int type, struct iovec *iovec) 639 { 640 dev_t rdev; 641 int retval = 0; 642 int offset = PROXY_HDR_SZ; 643 V9fsString oldpath, path; 644 int mode, uid, gid, cur_uid, cur_gid; 645 646 v9fs_string_init(&path); 647 v9fs_string_init(&oldpath); 648 649 retval = proxy_unmarshal(iovec, offset, "dd", &uid, &gid); 650 if (retval < 0) { 651 return retval; 652 } 653 offset += retval; 654 retval = setugid(uid, gid, &cur_uid, &cur_gid); 655 if (retval < 0) { 656 goto unmarshal_err_out; 657 } 658 switch (type) { 659 case T_MKNOD: 660 retval = proxy_unmarshal(iovec, offset, "sdq", &path, &mode, &rdev); 661 if (retval < 0) { 662 goto err_out; 663 } 664 retval = mknod(path.data, mode, rdev); 665 break; 666 case T_MKDIR: 667 retval = proxy_unmarshal(iovec, offset, "sd", &path, &mode); 668 if (retval < 0) { 669 goto err_out; 670 } 671 retval = g_mkdir(path.data, mode); 672 break; 673 case T_SYMLINK: 674 retval = proxy_unmarshal(iovec, offset, "ss", &oldpath, &path); 675 if (retval < 0) { 676 goto err_out; 677 } 678 retval = symlink(oldpath.data, path.data); 679 break; 680 } 681 if (retval < 0) { 682 retval = -errno; 683 } 684 685 err_out: 686 resetugid(cur_uid, cur_gid); 687 unmarshal_err_out: 688 v9fs_string_free(&path); 689 v9fs_string_free(&oldpath); 690 return retval; 691 } 692 693 /* 694 * create a file and send fd on success 695 * return -errno on error 696 */ 697 static int do_create(struct iovec *iovec) 698 { 699 int ret; 700 V9fsString path; 701 int flags, mode, uid, gid, cur_uid, cur_gid; 702 703 v9fs_string_init(&path); 704 ret = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sdddd", 705 &path, &flags, &mode, &uid, &gid); 706 if (ret < 0) { 707 goto unmarshal_err_out; 708 } 709 ret = setugid(uid, gid, &cur_uid, &cur_gid); 710 if (ret < 0) { 711 goto unmarshal_err_out; 712 } 713 ret = open_regular(path.data, flags, mode); 714 if (ret < 0) { 715 ret = -errno; 716 } 717 718 resetugid(cur_uid, cur_gid); 719 unmarshal_err_out: 720 v9fs_string_free(&path); 721 return ret; 722 } 723 724 /* 725 * open a file and send fd on success 726 * return -errno on error 727 */ 728 static int do_open(struct iovec *iovec) 729 { 730 int flags, ret; 731 V9fsString path; 732 733 v9fs_string_init(&path); 734 ret = proxy_unmarshal(iovec, PROXY_HDR_SZ, "sd", &path, &flags); 735 if (ret < 0) { 736 goto err_out; 737 } 738 ret = open_regular(path.data, flags, 0); 739 if (ret < 0) { 740 ret = -errno; 741 } 742 err_out: 743 v9fs_string_free(&path); 744 return ret; 745 } 746 747 /* create unix domain socket and return the descriptor */ 748 static int proxy_socket(const char *path, uid_t uid, gid_t gid) 749 { 750 int sock, client; 751 struct sockaddr_un proxy, qemu; 752 socklen_t size; 753 754 /* requested socket already exists, refuse to start */ 755 if (!access(path, F_OK)) { 756 do_log(LOG_CRIT, "socket already exists\n"); 757 return -1; 758 } 759 760 if (strlen(path) >= sizeof(proxy.sun_path)) { 761 do_log(LOG_CRIT, "UNIX domain socket path exceeds %zu characters\n", 762 sizeof(proxy.sun_path)); 763 return -1; 764 } 765 766 sock = socket(AF_UNIX, SOCK_STREAM, 0); 767 if (sock < 0) { 768 do_perror("socket"); 769 return -1; 770 } 771 772 /* mask other part of mode bits */ 773 umask(7); 774 775 proxy.sun_family = AF_UNIX; 776 strcpy(proxy.sun_path, path); 777 if (bind(sock, (struct sockaddr *)&proxy, 778 sizeof(struct sockaddr_un)) < 0) { 779 do_perror("bind"); 780 goto error; 781 } 782 if (chown(proxy.sun_path, uid, gid) < 0) { 783 do_perror("chown"); 784 goto error; 785 } 786 if (listen(sock, 1) < 0) { 787 do_perror("listen"); 788 goto error; 789 } 790 791 size = sizeof(qemu); 792 client = accept(sock, (struct sockaddr *)&qemu, &size); 793 if (client < 0) { 794 do_perror("accept"); 795 goto error; 796 } 797 close(sock); 798 return client; 799 800 error: 801 close(sock); 802 return -1; 803 } 804 805 static void usage(void) 806 { 807 fprintf(stderr, "usage: %s\n" 808 " -p|--path <path> 9p path to export\n" 809 " {-f|--fd <socket-descriptor>} socket file descriptor to be used\n" 810 " {-s|--socket <socketname> socket file used for communication\n" 811 " \t-u|--uid <uid> -g|--gid <gid>} - uid:gid combination to give " 812 " access to this socket\n" 813 " \tNote: -s & -f can not be used together\n" 814 " [-n|--nodaemon] Run as a normal program\n", 815 prog_name); 816 } 817 818 static int process_reply(int sock, int type, 819 struct iovec *out_iovec, int retval) 820 { 821 switch (type) { 822 case T_OPEN: 823 case T_CREATE: 824 if (send_fd(sock, retval) < 0) { 825 return -1; 826 } 827 break; 828 case T_MKNOD: 829 case T_MKDIR: 830 case T_SYMLINK: 831 case T_LINK: 832 case T_CHMOD: 833 case T_CHOWN: 834 case T_TRUNCATE: 835 case T_UTIME: 836 case T_RENAME: 837 case T_REMOVE: 838 case T_LSETXATTR: 839 case T_LREMOVEXATTR: 840 if (send_status(sock, out_iovec, retval) < 0) { 841 return -1; 842 } 843 break; 844 case T_LSTAT: 845 case T_STATFS: 846 case T_READLINK: 847 case T_LGETXATTR: 848 case T_LLISTXATTR: 849 case T_GETVERSION: 850 if (send_response(sock, out_iovec, retval) < 0) { 851 return -1; 852 } 853 break; 854 default: 855 return -1; 856 break; 857 } 858 return 0; 859 } 860 861 static int process_requests(int sock) 862 { 863 int flags; 864 int size = 0; 865 int retval = 0; 866 uint64_t offset; 867 ProxyHeader header; 868 int mode, uid, gid; 869 V9fsString name, value; 870 struct timespec spec[2]; 871 V9fsString oldpath, path; 872 struct iovec in_iovec, out_iovec; 873 874 in_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 875 in_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 876 out_iovec.iov_base = g_malloc(PROXY_MAX_IO_SZ + PROXY_HDR_SZ); 877 out_iovec.iov_len = PROXY_MAX_IO_SZ + PROXY_HDR_SZ; 878 879 while (1) { 880 /* 881 * initialize the header type, so that we send 882 * response to proper request type. 883 */ 884 header.type = 0; 885 retval = read_request(sock, &in_iovec, &header); 886 if (retval < 0) { 887 goto err_out; 888 } 889 890 switch (header.type) { 891 case T_OPEN: 892 retval = do_open(&in_iovec); 893 break; 894 case T_CREATE: 895 retval = do_create(&in_iovec); 896 break; 897 case T_MKNOD: 898 case T_MKDIR: 899 case T_SYMLINK: 900 retval = do_create_others(header.type, &in_iovec); 901 break; 902 case T_LINK: 903 v9fs_string_init(&path); 904 v9fs_string_init(&oldpath); 905 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, 906 "ss", &oldpath, &path); 907 if (retval > 0) { 908 retval = link(oldpath.data, path.data); 909 if (retval < 0) { 910 retval = -errno; 911 } 912 } 913 v9fs_string_free(&oldpath); 914 v9fs_string_free(&path); 915 break; 916 case T_LSTAT: 917 case T_STATFS: 918 retval = do_stat(header.type, &in_iovec, &out_iovec); 919 break; 920 case T_READLINK: 921 retval = do_readlink(&in_iovec, &out_iovec); 922 break; 923 case T_CHMOD: 924 v9fs_string_init(&path); 925 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, 926 "sd", &path, &mode); 927 if (retval > 0) { 928 retval = chmod(path.data, mode); 929 if (retval < 0) { 930 retval = -errno; 931 } 932 } 933 v9fs_string_free(&path); 934 break; 935 case T_CHOWN: 936 v9fs_string_init(&path); 937 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sdd", &path, 938 &uid, &gid); 939 if (retval > 0) { 940 retval = lchown(path.data, uid, gid); 941 if (retval < 0) { 942 retval = -errno; 943 } 944 } 945 v9fs_string_free(&path); 946 break; 947 case T_TRUNCATE: 948 v9fs_string_init(&path); 949 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sq", 950 &path, &offset); 951 if (retval > 0) { 952 retval = truncate(path.data, offset); 953 if (retval < 0) { 954 retval = -errno; 955 } 956 } 957 v9fs_string_free(&path); 958 break; 959 case T_UTIME: 960 v9fs_string_init(&path); 961 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sqqqq", &path, 962 &spec[0].tv_sec, &spec[0].tv_nsec, 963 &spec[1].tv_sec, &spec[1].tv_nsec); 964 if (retval > 0) { 965 retval = utimensat(AT_FDCWD, path.data, spec, 966 AT_SYMLINK_NOFOLLOW); 967 if (retval < 0) { 968 retval = -errno; 969 } 970 } 971 v9fs_string_free(&path); 972 break; 973 case T_RENAME: 974 v9fs_string_init(&path); 975 v9fs_string_init(&oldpath); 976 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, 977 "ss", &oldpath, &path); 978 if (retval > 0) { 979 retval = rename(oldpath.data, path.data); 980 if (retval < 0) { 981 retval = -errno; 982 } 983 } 984 v9fs_string_free(&oldpath); 985 v9fs_string_free(&path); 986 break; 987 case T_REMOVE: 988 v9fs_string_init(&path); 989 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "s", &path); 990 if (retval > 0) { 991 retval = remove(path.data); 992 if (retval < 0) { 993 retval = -errno; 994 } 995 } 996 v9fs_string_free(&path); 997 break; 998 case T_LGETXATTR: 999 case T_LLISTXATTR: 1000 retval = do_getxattr(header.type, &in_iovec, &out_iovec); 1001 break; 1002 case T_LSETXATTR: 1003 v9fs_string_init(&path); 1004 v9fs_string_init(&name); 1005 v9fs_string_init(&value); 1006 retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sssdd", &path, 1007 &name, &value, &size, &flags); 1008 if (retval > 0) { 1009 retval = lsetxattr(path.data, 1010 name.data, value.data, size, flags); 1011 if (retval < 0) { 1012 retval = -errno; 1013 } 1014 } 1015 v9fs_string_free(&path); 1016 v9fs_string_free(&name); 1017 v9fs_string_free(&value); 1018 break; 1019 case T_LREMOVEXATTR: 1020 v9fs_string_init(&path); 1021 v9fs_string_init(&name); 1022 retval = proxy_unmarshal(&in_iovec, 1023 PROXY_HDR_SZ, "ss", &path, &name); 1024 if (retval > 0) { 1025 retval = lremovexattr(path.data, name.data); 1026 if (retval < 0) { 1027 retval = -errno; 1028 } 1029 } 1030 v9fs_string_free(&path); 1031 v9fs_string_free(&name); 1032 break; 1033 case T_GETVERSION: 1034 retval = do_getversion(&in_iovec, &out_iovec); 1035 break; 1036 default: 1037 goto err_out; 1038 break; 1039 } 1040 1041 if (process_reply(sock, header.type, &out_iovec, retval) < 0) { 1042 goto err_out; 1043 } 1044 } 1045 err_out: 1046 g_free(in_iovec.iov_base); 1047 g_free(out_iovec.iov_base); 1048 return -1; 1049 } 1050 1051 int main(int argc, char **argv) 1052 { 1053 int sock; 1054 uid_t own_u; 1055 gid_t own_g; 1056 char *rpath = NULL; 1057 char *sock_name = NULL; 1058 struct stat stbuf; 1059 int c, option_index; 1060 #ifdef FS_IOC_GETVERSION 1061 int retval; 1062 struct statfs st_fs; 1063 #endif 1064 1065 fprintf(stderr, "NOTE: The 9p 'proxy' backend is deprecated (since " 1066 "QEMU 8.1) and will be removed in a future version of " 1067 "QEMU!\n"); 1068 1069 prog_name = g_path_get_basename(argv[0]); 1070 1071 is_daemon = true; 1072 sock = -1; 1073 own_u = own_g = -1; 1074 while (1) { 1075 option_index = 0; 1076 c = getopt_long(argc, argv, "p:nh?f:s:u:g:", helper_opts, 1077 &option_index); 1078 if (c == -1) { 1079 break; 1080 } 1081 switch (c) { 1082 case 'p': 1083 rpath = g_strdup(optarg); 1084 break; 1085 case 'n': 1086 is_daemon = false; 1087 break; 1088 case 'f': 1089 sock = atoi(optarg); 1090 break; 1091 case 's': 1092 sock_name = g_strdup(optarg); 1093 break; 1094 case 'u': 1095 own_u = atoi(optarg); 1096 break; 1097 case 'g': 1098 own_g = atoi(optarg); 1099 break; 1100 case '?': 1101 case 'h': 1102 default: 1103 usage(); 1104 exit(EXIT_FAILURE); 1105 } 1106 } 1107 1108 /* Parameter validation */ 1109 if ((sock_name == NULL && sock == -1) || rpath == NULL) { 1110 fprintf(stderr, "socket, socket descriptor or path not specified\n"); 1111 usage(); 1112 return -1; 1113 } 1114 1115 if (sock_name && sock != -1) { 1116 fprintf(stderr, "both named socket and socket descriptor specified\n"); 1117 usage(); 1118 exit(EXIT_FAILURE); 1119 } 1120 1121 if (sock_name && (own_u == -1 || own_g == -1)) { 1122 fprintf(stderr, "owner uid:gid not specified, "); 1123 fprintf(stderr, 1124 "owner uid:gid specifies who can access the socket file\n"); 1125 usage(); 1126 exit(EXIT_FAILURE); 1127 } 1128 1129 if (lstat(rpath, &stbuf) < 0) { 1130 fprintf(stderr, "invalid path \"%s\" specified, %s\n", 1131 rpath, strerror(errno)); 1132 exit(EXIT_FAILURE); 1133 } 1134 1135 if (!S_ISDIR(stbuf.st_mode)) { 1136 fprintf(stderr, "specified path \"%s\" is not directory\n", rpath); 1137 exit(EXIT_FAILURE); 1138 } 1139 1140 if (is_daemon) { 1141 if (daemon(0, 0) < 0) { 1142 fprintf(stderr, "daemon call failed\n"); 1143 exit(EXIT_FAILURE); 1144 } 1145 openlog(PROGNAME, LOG_PID, LOG_DAEMON); 1146 } 1147 1148 do_log(LOG_INFO, "Started\n"); 1149 if (sock_name) { 1150 sock = proxy_socket(sock_name, own_u, own_g); 1151 if (sock < 0) { 1152 goto error; 1153 } 1154 } 1155 1156 if (chroot(rpath) < 0) { 1157 do_perror("chroot"); 1158 goto error; 1159 } 1160 if (chdir("/") < 0) { 1161 do_perror("chdir"); 1162 goto error; 1163 } 1164 1165 get_version = false; 1166 #ifdef FS_IOC_GETVERSION 1167 /* check whether underlying FS support IOC_GETVERSION */ 1168 retval = statfs("/", &st_fs); 1169 if (!retval) { 1170 switch (st_fs.f_type) { 1171 case EXT2_SUPER_MAGIC: 1172 case BTRFS_SUPER_MAGIC: 1173 case REISERFS_SUPER_MAGIC: 1174 case XFS_SUPER_MAGIC: 1175 get_version = true; 1176 break; 1177 } 1178 } 1179 #endif 1180 1181 umask(0); 1182 if (init_capabilities() < 0) { 1183 goto error; 1184 } 1185 1186 process_requests(sock); 1187 error: 1188 g_free(rpath); 1189 g_free(sock_name); 1190 do_log(LOG_INFO, "Done\n"); 1191 closelog(); 1192 return 0; 1193 } 1194