virtfs-proxy-helper.c 30 KB

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