virtfs-proxy-helper.c 31 KB

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