virtfs-proxy-helper.c 31 KB

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