You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

431 lines
8.2 KiB

  1. /*
  2. ISC License
  3. Copyright (c) 2024, Antonio SJ Musumeci <trapexit@spawn.link>
  4. Permission to use, copy, modify, and/or distribute this software for any
  5. purpose with or without fee is hereby granted, provided that the above
  6. copyright notice and this permission notice appear in all copies.
  7. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. */
  15. #ifdef __FreeBSD__
  16. #define O_TMPFILE 0
  17. #else
  18. #define _GNU_SOURCE
  19. //#define _POSIX_C_SOURCE 200809L
  20. #endif
  21. #include <assert.h>
  22. #include <dlfcn.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <sys/ioctl.h>
  26. #include <stdarg.h>
  27. #include <sys/stat.h>
  28. #include <sys/types.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. typedef char IOCTL_BUF[4096];
  32. #define IOCTL_APP_TYPE 0xDF
  33. #define IOCTL_FILE_INFO _IOWR(IOCTL_APP_TYPE,0,IOCTL_BUF)
  34. #define LOAD_FUNC(func) \
  35. do \
  36. { \
  37. if(!_libc_##func) \
  38. _libc_##func = (func##_func_t)dlsym(RTLD_NEXT,#func); \
  39. assert(_libc_##func != NULL); \
  40. } \
  41. while(0)
  42. typedef int (*open_func_t)(const char*, int, ...);
  43. typedef int (*open64_func_t)(const char*, int, ...);
  44. typedef int (*openat_func_t)(int, const char*, int, ...);
  45. typedef int (*openat64_func_t)(int, const char*, int, ...);
  46. typedef int (*creat_func_t)(const char*, mode_t);
  47. typedef int (*creat64_func_t)(const char*, mode_t);
  48. typedef FILE* (*fopen_func_t)(const char*, const char*);
  49. typedef FILE* (*fopen64_func_t)(const char*, const char*);
  50. static open_func_t _libc_open = NULL;
  51. static open64_func_t _libc_open64 = NULL;
  52. static openat_func_t _libc_openat = NULL;
  53. static openat64_func_t _libc_openat64 = NULL;
  54. static fopen_func_t _libc_fopen = NULL;
  55. static fopen64_func_t _libc_fopen64 = NULL;
  56. static creat_func_t _libc_creat = NULL;
  57. static creat64_func_t _libc_creat64 = NULL;
  58. static
  59. int
  60. get_underlying_filepath(int fd_,
  61. char *filepath_)
  62. {
  63. int rv;
  64. strcpy(filepath_,"fullpath");
  65. rv = ioctl(fd_,IOCTL_FILE_INFO,filepath_);
  66. if(rv == -1)
  67. return -1;
  68. return rv;
  69. }
  70. static
  71. void
  72. strip_exec(const char *orig_mode_,
  73. char *new_mode_)
  74. {
  75. size_t i;
  76. size_t j;
  77. for(i = j = 0; orig_mode_[i]; i++)
  78. {
  79. if(orig_mode_[i] == 'x')
  80. continue;
  81. new_mode_[j++] = orig_mode_[i];
  82. }
  83. new_mode_[j] = '\0';
  84. }
  85. int
  86. open(const char *pathname_,
  87. int flags_,
  88. ...)
  89. {
  90. int rv;
  91. int fd;
  92. mode_t mode;
  93. struct stat st;
  94. LOAD_FUNC(open);
  95. mode = 0;
  96. if(flags_ & (O_CREAT|O_TMPFILE))
  97. {
  98. va_list args;
  99. va_start(args,flags_);
  100. mode = va_arg(args,mode_t);
  101. va_end(args);
  102. }
  103. fd = _libc_open(pathname_,flags_,mode);
  104. if(fd == -1)
  105. return -1;
  106. if(flags_ & (O_DIRECTORY|O_PATH|O_TMPFILE))
  107. return fd;
  108. rv = fstat(fd,&st);
  109. if(rv == -1)
  110. return fd;
  111. if((st.st_mode & S_IFMT) != S_IFREG)
  112. return fd;
  113. IOCTL_BUF real_pathname;
  114. rv = get_underlying_filepath(fd,real_pathname);
  115. if(rv == -1)
  116. return fd;
  117. flags_ &= ~(O_EXCL|O_CREAT);
  118. rv = _libc_open(real_pathname,flags_,mode);
  119. if(rv == -1)
  120. return fd;
  121. close(fd);
  122. return rv;
  123. }
  124. int
  125. open64(const char *pathname_,
  126. int flags_,
  127. ...)
  128. {
  129. int rv;
  130. int fd;
  131. mode_t mode;
  132. struct stat st;
  133. LOAD_FUNC(open64);
  134. mode = 0;
  135. if(flags_ & (O_CREAT|O_TMPFILE))
  136. {
  137. va_list args;
  138. va_start(args,flags_);
  139. mode = va_arg(args,mode_t);
  140. va_end(args);
  141. }
  142. fd = _libc_open64(pathname_,flags_,mode);
  143. if(fd == -1)
  144. return -1;
  145. if(flags_ & (O_DIRECTORY|O_PATH|O_TMPFILE))
  146. return fd;
  147. rv = fstat(fd,&st);
  148. if(rv == -1)
  149. return fd;
  150. if((st.st_mode & S_IFMT) != S_IFREG)
  151. return fd;
  152. IOCTL_BUF real_pathname;
  153. rv = get_underlying_filepath(fd,real_pathname);
  154. if(rv == -1)
  155. return fd;
  156. flags_ &= ~(O_EXCL|O_CREAT);
  157. rv = _libc_open64(real_pathname,flags_,mode);
  158. if(rv == -1)
  159. return fd;
  160. close(fd);
  161. return rv;
  162. }
  163. int
  164. openat(int dirfd_,
  165. const char *pathname_,
  166. int flags_,
  167. ...)
  168. {
  169. int rv;
  170. int fd;
  171. mode_t mode;
  172. struct stat st;
  173. LOAD_FUNC(openat);
  174. mode = 0;
  175. if(flags_ & (O_CREAT|O_TMPFILE))
  176. {
  177. va_list args;
  178. va_start(args,flags_);
  179. mode = va_arg(args,mode_t);
  180. va_end(args);
  181. }
  182. fd = _libc_openat(dirfd_,pathname_,flags_,mode);
  183. if(fd == -1)
  184. return -1;
  185. if(flags_ & (O_DIRECTORY|O_PATH|O_TMPFILE))
  186. return fd;
  187. rv = fstat(fd,&st);
  188. if(rv == -1)
  189. return fd;
  190. if((st.st_mode & S_IFMT) != S_IFREG)
  191. return fd;
  192. IOCTL_BUF real_pathname;
  193. rv = get_underlying_filepath(fd,real_pathname);
  194. if(rv == -1)
  195. return fd;
  196. flags_ &= ~(O_EXCL|O_CREAT);
  197. rv = _libc_openat(dirfd_,real_pathname,flags_,mode);
  198. if(rv == -1)
  199. return fd;
  200. close(fd);
  201. return rv;
  202. }
  203. int
  204. openat64(int dirfd_,
  205. const char *pathname_,
  206. int flags_,
  207. ...)
  208. {
  209. int rv;
  210. int fd;
  211. mode_t mode;
  212. struct stat st;
  213. LOAD_FUNC(openat64);
  214. mode = 0;
  215. if(flags_ & (O_CREAT|O_TMPFILE))
  216. {
  217. va_list args;
  218. va_start(args,flags_);
  219. mode = va_arg(args,mode_t);
  220. va_end(args);
  221. }
  222. fd = _libc_openat64(dirfd_,pathname_,flags_,mode);
  223. if(fd == -1)
  224. return -1;
  225. if(flags_ & (O_DIRECTORY|O_PATH|O_TMPFILE))
  226. return fd;
  227. rv = fstat(fd,&st);
  228. if(rv == -1)
  229. return fd;
  230. if((st.st_mode & S_IFMT) != S_IFREG)
  231. return fd;
  232. IOCTL_BUF real_pathname;
  233. rv = get_underlying_filepath(fd,real_pathname);
  234. if(rv == -1)
  235. return fd;
  236. flags_ &= ~(O_EXCL|O_CREAT);
  237. rv = _libc_openat64(dirfd_,real_pathname,flags_,mode);
  238. if(rv == -1)
  239. return fd;
  240. close(fd);
  241. return rv;
  242. }
  243. FILE*
  244. fopen(const char *pathname_,
  245. const char *mode_)
  246. {
  247. int fd;
  248. int rv;
  249. FILE *f;
  250. FILE *f2;
  251. struct stat st;
  252. LOAD_FUNC(fopen);
  253. f = _libc_fopen(pathname_,mode_);
  254. if(f == NULL)
  255. return NULL;
  256. fd = fileno(f);
  257. if(fd == -1)
  258. return f;
  259. rv = fstat(fd,&st);
  260. if(rv == -1)
  261. return f;
  262. if((st.st_mode & S_IFMT) != S_IFREG)
  263. return f;
  264. IOCTL_BUF real_pathname;
  265. rv = get_underlying_filepath(fd,real_pathname);
  266. if(rv == -1)
  267. return f;
  268. char new_mode[64];
  269. strip_exec(mode_,new_mode);
  270. f2 = _libc_fopen(real_pathname,new_mode);
  271. if(f2 == NULL)
  272. return f;
  273. fclose(f);
  274. return f2;
  275. }
  276. FILE*
  277. fopen64(const char *pathname_,
  278. const char *mode_)
  279. {
  280. int fd;
  281. int rv;
  282. FILE *f;
  283. FILE *f2;
  284. struct stat st;
  285. LOAD_FUNC(fopen64);
  286. f = _libc_fopen64(pathname_,mode_);
  287. if(f == NULL)
  288. return NULL;
  289. fd = fileno(f);
  290. if(fd == -1)
  291. return f;
  292. rv = fstat(fd,&st);
  293. if(rv == -1)
  294. return f;
  295. if((st.st_mode & S_IFMT) != S_IFREG)
  296. return f;
  297. IOCTL_BUF real_pathname;
  298. rv = get_underlying_filepath(fd,real_pathname);
  299. if(rv == -1)
  300. return f;
  301. char new_mode[64];
  302. strip_exec(mode_,new_mode);
  303. f2 = _libc_fopen64(real_pathname,new_mode);
  304. if(f2 == NULL)
  305. return f;
  306. fclose(f);
  307. return f2;
  308. }
  309. int
  310. creat(const char *pathname_,
  311. mode_t mode_)
  312. {
  313. int fd;
  314. int rv;
  315. LOAD_FUNC(creat);
  316. fd = _libc_creat(pathname_,mode_);
  317. if(fd == -1)
  318. return -1;
  319. IOCTL_BUF real_pathname;
  320. rv = get_underlying_filepath(fd,real_pathname);
  321. if(rv == -1)
  322. return fd;
  323. rv = _libc_creat(real_pathname,mode_);
  324. if(rv == -1)
  325. return fd;
  326. close(fd);
  327. return rv;
  328. }
  329. int
  330. creat64(const char *pathname_,
  331. mode_t mode_)
  332. {
  333. int fd;
  334. int rv;
  335. LOAD_FUNC(creat64);
  336. fd = _libc_creat64(pathname_,mode_);
  337. if(fd == -1)
  338. return -1;
  339. IOCTL_BUF real_pathname;
  340. rv = get_underlying_filepath(fd,real_pathname);
  341. if(rv == -1)
  342. return fd;
  343. rv = _libc_creat64(real_pathname,mode_);
  344. if(rv == -1)
  345. return fd;
  346. close(fd);
  347. return rv;
  348. }