2
0

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