virtfs-proxy-helper.c 31 KB

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