2
0

virtfs-proxy-helper.c 31 KB

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