9p-util.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. /*
  2. * 9p utilities
  3. *
  4. * Copyright IBM, Corp. 2017
  5. *
  6. * Authors:
  7. * Greg Kurz <groug@kaod.org>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10. * See the COPYING file in the top-level directory.
  11. */
  12. #ifndef QEMU_9P_UTIL_H
  13. #define QEMU_9P_UTIL_H
  14. #include "qemu/error-report.h"
  15. #ifdef O_PATH
  16. #define O_PATH_9P_UTIL O_PATH
  17. #else
  18. #define O_PATH_9P_UTIL 0
  19. #endif
  20. #if !defined(CONFIG_LINUX)
  21. /*
  22. * Generates a Linux device number (a.k.a. dev_t) for given device major
  23. * and minor numbers.
  24. *
  25. * To be more precise: it generates a device number in glibc's format
  26. * (MMMM_Mmmm_mmmM_MMmm, 64 bits) actually, which is compatible with
  27. * Linux's format (mmmM_MMmm, 32 bits), as described in <bits/sysmacros.h>.
  28. */
  29. static inline uint64_t makedev_dotl(uint32_t dev_major, uint32_t dev_minor)
  30. {
  31. uint64_t dev;
  32. // from glibc sysmacros.h:
  33. dev = (((uint64_t) (dev_major & 0x00000fffu)) << 8);
  34. dev |= (((uint64_t) (dev_major & 0xfffff000u)) << 32);
  35. dev |= (((uint64_t) (dev_minor & 0x000000ffu)) << 0);
  36. dev |= (((uint64_t) (dev_minor & 0xffffff00u)) << 12);
  37. return dev;
  38. }
  39. #endif
  40. /*
  41. * Converts given device number from host's device number format to Linux
  42. * device number format. As both the size of type dev_t and encoding of
  43. * dev_t is system dependant, we have to convert them for Linux guests if
  44. * host is not running Linux.
  45. */
  46. static inline uint64_t host_dev_to_dotl_dev(dev_t dev)
  47. {
  48. #ifdef CONFIG_LINUX
  49. return dev;
  50. #else
  51. return makedev_dotl(major(dev), minor(dev));
  52. #endif
  53. }
  54. /* Translates errno from host -> Linux if needed */
  55. static inline int errno_to_dotl(int err) {
  56. #if defined(CONFIG_LINUX)
  57. /* nothing to translate (Linux -> Linux) */
  58. #elif defined(CONFIG_DARWIN)
  59. /*
  60. * translation mandatory for macOS hosts
  61. *
  62. * FIXME: Only most important errnos translated here yet, this should be
  63. * extended to as many errnos being translated as possible in future.
  64. */
  65. if (err == ENAMETOOLONG) {
  66. err = 36; /* ==ENAMETOOLONG on Linux */
  67. } else if (err == ENOTEMPTY) {
  68. err = 39; /* ==ENOTEMPTY on Linux */
  69. } else if (err == ELOOP) {
  70. err = 40; /* ==ELOOP on Linux */
  71. } else if (err == ENOATTR) {
  72. err = 61; /* ==ENODATA on Linux */
  73. } else if (err == ENOTSUP) {
  74. err = 95; /* ==EOPNOTSUPP on Linux */
  75. } else if (err == EOPNOTSUPP) {
  76. err = 95; /* ==EOPNOTSUPP on Linux */
  77. }
  78. #else
  79. #error Missing errno translation to Linux for this host system
  80. #endif
  81. return err;
  82. }
  83. #ifdef CONFIG_DARWIN
  84. #define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
  85. #else
  86. #define qemu_fgetxattr fgetxattr
  87. #endif
  88. #define qemu_openat openat
  89. #define qemu_fstat fstat
  90. #define qemu_fstatat fstatat
  91. #define qemu_mkdirat mkdirat
  92. #define qemu_renameat renameat
  93. #define qemu_utimensat utimensat
  94. #define qemu_unlinkat unlinkat
  95. static inline void close_preserve_errno(int fd)
  96. {
  97. int serrno = errno;
  98. close(fd);
  99. errno = serrno;
  100. }
  101. /**
  102. * close_if_special_file() - Close @fd if neither regular file nor directory.
  103. *
  104. * @fd: file descriptor of open file
  105. * Return: 0 on regular file or directory, -1 otherwise
  106. *
  107. * CVE-2023-2861: Prohibit opening any special file directly on host
  108. * (especially device files), as a compromised client could potentially gain
  109. * access outside exported tree under certain, unsafe setups. We expect
  110. * client to handle I/O on special files exclusively on guest side.
  111. */
  112. static inline int close_if_special_file(int fd)
  113. {
  114. struct stat stbuf;
  115. if (qemu_fstat(fd, &stbuf) < 0) {
  116. close_preserve_errno(fd);
  117. return -1;
  118. }
  119. if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) {
  120. error_report_once(
  121. "9p: broken or compromised client detected; attempt to open "
  122. "special file (i.e. neither regular file, nor directory)"
  123. );
  124. close(fd);
  125. errno = ENXIO;
  126. return -1;
  127. }
  128. return 0;
  129. }
  130. static inline int openat_dir(int dirfd, const char *name)
  131. {
  132. return qemu_openat(dirfd, name,
  133. O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
  134. }
  135. static inline int openat_file(int dirfd, const char *name, int flags,
  136. mode_t mode)
  137. {
  138. int fd, serrno, ret;
  139. #ifndef CONFIG_DARWIN
  140. again:
  141. #endif
  142. fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
  143. mode);
  144. if (fd == -1) {
  145. #ifndef CONFIG_DARWIN
  146. if (errno == EPERM && (flags & O_NOATIME)) {
  147. /*
  148. * The client passed O_NOATIME but we lack permissions to honor it.
  149. * Rather than failing the open, fall back without O_NOATIME. This
  150. * doesn't break the semantics on the client side, as the Linux
  151. * open(2) man page notes that O_NOATIME "may not be effective on
  152. * all filesystems". In particular, NFS and other network
  153. * filesystems ignore it entirely.
  154. */
  155. flags &= ~O_NOATIME;
  156. goto again;
  157. }
  158. #endif
  159. return -1;
  160. }
  161. if (close_if_special_file(fd) < 0) {
  162. return -1;
  163. }
  164. serrno = errno;
  165. /* O_NONBLOCK was only needed to open the file. Let's drop it. We don't
  166. * do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat()
  167. * ignored it anyway.
  168. */
  169. if (!(flags & O_PATH_9P_UTIL)) {
  170. ret = fcntl(fd, F_SETFL, flags);
  171. assert(!ret);
  172. }
  173. errno = serrno;
  174. return fd;
  175. }
  176. ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
  177. void *value, size_t size);
  178. int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
  179. void *value, size_t size, int flags);
  180. ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
  181. char *list, size_t size);
  182. ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
  183. const char *name);
  184. /*
  185. * Darwin has d_seekoff, which appears to function similarly to d_off.
  186. * However, it does not appear to be supported on all file systems,
  187. * so ensure it is manually injected earlier and call here when
  188. * needed.
  189. */
  190. static inline off_t qemu_dirent_off(struct dirent *dent)
  191. {
  192. #ifdef CONFIG_DARWIN
  193. return dent->d_seekoff;
  194. #else
  195. return dent->d_off;
  196. #endif
  197. }
  198. /**
  199. * qemu_dirent_dup() - Duplicate directory entry @dent.
  200. *
  201. * @dent: original directory entry to be duplicated
  202. * Return: duplicated directory entry which should be freed with g_free()
  203. *
  204. * It is highly recommended to use this function instead of open coding
  205. * duplication of dirent objects, because the actual struct dirent
  206. * size may be bigger or shorter than sizeof(struct dirent) and correct
  207. * handling is platform specific (see gitlab issue #841).
  208. */
  209. static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
  210. {
  211. size_t sz = 0;
  212. #if defined _DIRENT_HAVE_D_RECLEN
  213. /* Avoid use of strlen() if platform supports d_reclen. */
  214. sz = dent->d_reclen;
  215. #endif
  216. /*
  217. * Test sz for zero even if d_reclen is available
  218. * because some drivers may set d_reclen to zero.
  219. */
  220. if (sz == 0) {
  221. /* Fallback to the most portable way. */
  222. sz = offsetof(struct dirent, d_name) +
  223. strlen(dent->d_name) + 1;
  224. }
  225. return g_memdup(dent, sz);
  226. }
  227. /*
  228. * As long as mknodat is not available on macOS, this workaround
  229. * using pthread_fchdir_np is needed. qemu_mknodat is defined in
  230. * os-posix.c. pthread_fchdir_np is weakly linked here as a guard
  231. * in case it disappears in future macOS versions, because it is
  232. * is a private API.
  233. */
  234. #if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP
  235. int pthread_fchdir_np(int fd) __attribute__((weak_import));
  236. #endif
  237. int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
  238. #endif