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.

427 lines
8.0 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. #define _GNU_SOURCE
  16. #define _POSIX_C_SOURCE 200809L
  17. #include <assert.h>
  18. #include <dlfcn.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <sys/ioctl.h>
  22. #include <stdarg.h>
  23. #include <sys/stat.h>
  24. #include <sys/types.h>
  25. #include <unistd.h>
  26. #include <fcntl.h>
  27. typedef char IOCTL_BUF[4096];
  28. #define IOCTL_APP_TYPE 0xDF
  29. #define IOCTL_FILE_INFO _IOWR(IOCTL_APP_TYPE,0,IOCTL_BUF)
  30. #define LOAD_FUNC(func) \
  31. do \
  32. { \
  33. if(!_libc_##func) \
  34. _libc_##func = (func##_func_t)dlsym(RTLD_NEXT,#func); \
  35. assert(_libc_##func != NULL); \
  36. } \
  37. while(0)
  38. typedef int (*open_func_t)(const char*, int, ...);
  39. typedef int (*open64_func_t)(const char*, int, ...);
  40. typedef int (*openat_func_t)(int, const char*, int, ...);
  41. typedef int (*openat64_func_t)(int, const char*, int, ...);
  42. typedef int (*creat_func_t)(const char*, mode_t);
  43. typedef int (*creat64_func_t)(const char*, mode_t);
  44. typedef FILE* (*fopen_func_t)(const char*, const char*);
  45. typedef FILE* (*fopen64_func_t)(const char*, const char*);
  46. static open_func_t _libc_open = NULL;
  47. static open64_func_t _libc_open64 = NULL;
  48. static openat_func_t _libc_openat = NULL;
  49. static openat64_func_t _libc_openat64 = NULL;
  50. static fopen_func_t _libc_fopen = NULL;
  51. static fopen64_func_t _libc_fopen64 = NULL;
  52. static creat_func_t _libc_creat = NULL;
  53. static creat64_func_t _libc_creat64 = NULL;
  54. static
  55. int
  56. get_underlying_filepath(int fd_,
  57. char *filepath_)
  58. {
  59. int rv;
  60. strcpy(filepath_,"fullpath");
  61. rv = ioctl(fd_,IOCTL_FILE_INFO,filepath_);
  62. if(rv == -1)
  63. return -1;
  64. return rv;
  65. }
  66. static
  67. void
  68. strip_exec(const char *orig_mode_,
  69. char *new_mode_)
  70. {
  71. size_t i;
  72. size_t j;
  73. for(i = j = 0; orig_mode_[i]; i++)
  74. {
  75. if(orig_mode_[i] == 'x')
  76. continue;
  77. new_mode_[j++] = orig_mode_[i];
  78. }
  79. new_mode_[j] = '\0';
  80. }
  81. int
  82. open(const char *pathname_,
  83. int flags_,
  84. ...)
  85. {
  86. int rv;
  87. int fd;
  88. mode_t mode;
  89. struct stat st;
  90. LOAD_FUNC(open);
  91. mode = 0;
  92. if(flags_ & O_CREAT)
  93. {
  94. va_list args;
  95. va_start(args,flags_);
  96. mode = va_arg(args,mode_t);
  97. va_end(args);
  98. }
  99. fd = _libc_open(pathname_,flags_,mode);
  100. if(fd == -1)
  101. return -1;
  102. if(flags_ & (O_DIRECTORY|O_PATH))
  103. return fd;
  104. rv = fstat(fd,&st);
  105. if(rv == -1)
  106. return fd;
  107. if((st.st_mode & S_IFMT) != S_IFREG)
  108. return fd;
  109. IOCTL_BUF real_pathname;
  110. rv = get_underlying_filepath(fd,real_pathname);
  111. if(rv == -1)
  112. return fd;
  113. flags_ &= ~(O_EXCL|O_CREAT);
  114. rv = _libc_open(real_pathname,flags_,mode);
  115. if(rv == -1)
  116. return fd;
  117. close(fd);
  118. return rv;
  119. }
  120. int
  121. open64(const char *pathname_,
  122. int flags_,
  123. ...)
  124. {
  125. int rv;
  126. int fd;
  127. mode_t mode;
  128. struct stat st;
  129. LOAD_FUNC(open64);
  130. mode = 0;
  131. if(flags_ & O_CREAT)
  132. {
  133. va_list args;
  134. va_start(args,flags_);
  135. mode = va_arg(args,mode_t);
  136. va_end(args);
  137. }
  138. fd = _libc_open64(pathname_,flags_,mode);
  139. if(fd == -1)
  140. return -1;
  141. if(flags_ & (O_DIRECTORY|O_PATH))
  142. return fd;
  143. rv = fstat(fd,&st);
  144. if(rv == -1)
  145. return fd;
  146. if((st.st_mode & S_IFMT) != S_IFREG)
  147. return fd;
  148. IOCTL_BUF real_pathname;
  149. rv = get_underlying_filepath(fd,real_pathname);
  150. if(rv == -1)
  151. return fd;
  152. flags_ &= ~(O_EXCL|O_CREAT);
  153. rv = _libc_open64(real_pathname,flags_,mode);
  154. if(rv == -1)
  155. return fd;
  156. close(fd);
  157. return rv;
  158. }
  159. int
  160. openat(int dirfd_,
  161. const char *pathname_,
  162. int flags_,
  163. ...)
  164. {
  165. int rv;
  166. int fd;
  167. mode_t mode;
  168. struct stat st;
  169. LOAD_FUNC(openat);
  170. mode = 0;
  171. if(flags_ & O_CREAT)
  172. {
  173. va_list args;
  174. va_start(args,flags_);
  175. mode = va_arg(args,mode_t);
  176. va_end(args);
  177. }
  178. fd = _libc_openat(dirfd_,pathname_,flags_,mode);
  179. if(fd == -1)
  180. return -1;
  181. if(flags_ & (O_DIRECTORY|O_PATH))
  182. return fd;
  183. rv = fstat(fd,&st);
  184. if(rv == -1)
  185. return fd;
  186. if((st.st_mode & S_IFMT) != S_IFREG)
  187. return fd;
  188. IOCTL_BUF real_pathname;
  189. rv = get_underlying_filepath(fd,real_pathname);
  190. if(rv == -1)
  191. return fd;
  192. flags_ &= ~(O_EXCL|O_CREAT);
  193. rv = _libc_openat(dirfd_,real_pathname,flags_,mode);
  194. if(rv == -1)
  195. return fd;
  196. close(fd);
  197. return rv;
  198. }
  199. int
  200. openat64(int dirfd_,
  201. const char *pathname_,
  202. int flags_,
  203. ...)
  204. {
  205. int rv;
  206. int fd;
  207. mode_t mode;
  208. struct stat st;
  209. LOAD_FUNC(openat64);
  210. mode = 0;
  211. if(flags_ & O_CREAT)
  212. {
  213. va_list args;
  214. va_start(args,flags_);
  215. mode = va_arg(args,mode_t);
  216. va_end(args);
  217. }
  218. fd = _libc_openat64(dirfd_,pathname_,flags_,mode);
  219. if(fd == -1)
  220. return -1;
  221. if(flags_ & (O_DIRECTORY|O_PATH))
  222. return fd;
  223. rv = fstat(fd,&st);
  224. if(rv == -1)
  225. return fd;
  226. if((st.st_mode & S_IFMT) != S_IFREG)
  227. return fd;
  228. IOCTL_BUF real_pathname;
  229. rv = get_underlying_filepath(fd,real_pathname);
  230. if(rv == -1)
  231. return fd;
  232. flags_ &= ~(O_EXCL|O_CREAT);
  233. rv = _libc_openat64(dirfd_,real_pathname,flags_,mode);
  234. if(rv == -1)
  235. return fd;
  236. close(fd);
  237. return rv;
  238. }
  239. FILE*
  240. fopen(const char *pathname_,
  241. const char *mode_)
  242. {
  243. int fd;
  244. int rv;
  245. FILE *f;
  246. FILE *f2;
  247. struct stat st;
  248. LOAD_FUNC(fopen);
  249. f = _libc_fopen(pathname_,mode_);
  250. if(f == NULL)
  251. return NULL;
  252. fd = fileno(f);
  253. if(fd == -1)
  254. return f;
  255. rv = fstat(fd,&st);
  256. if(rv == -1)
  257. return f;
  258. if((st.st_mode & S_IFMT) != S_IFREG)
  259. return f;
  260. IOCTL_BUF real_pathname;
  261. rv = get_underlying_filepath(fd,real_pathname);
  262. if(rv == -1)
  263. return f;
  264. char new_mode[64];
  265. strip_exec(mode_,new_mode);
  266. f2 = _libc_fopen(real_pathname,new_mode);
  267. if(f2 == NULL)
  268. return f;
  269. fclose(f);
  270. return f2;
  271. }
  272. FILE*
  273. fopen64(const char *pathname_,
  274. const char *mode_)
  275. {
  276. int fd;
  277. int rv;
  278. FILE *f;
  279. FILE *f2;
  280. struct stat st;
  281. LOAD_FUNC(fopen64);
  282. f = _libc_fopen64(pathname_,mode_);
  283. if(f == NULL)
  284. return NULL;
  285. fd = fileno(f);
  286. if(fd == -1)
  287. return f;
  288. rv = fstat(fd,&st);
  289. if(rv == -1)
  290. return f;
  291. if((st.st_mode & S_IFMT) != S_IFREG)
  292. return f;
  293. IOCTL_BUF real_pathname;
  294. rv = get_underlying_filepath(fd,real_pathname);
  295. if(rv == -1)
  296. return f;
  297. char new_mode[64];
  298. strip_exec(mode_,new_mode);
  299. f2 = _libc_fopen64(real_pathname,new_mode);
  300. if(f2 == NULL)
  301. return f;
  302. fclose(f);
  303. return f2;
  304. }
  305. int
  306. creat(const char *pathname_,
  307. mode_t mode_)
  308. {
  309. int fd;
  310. int rv;
  311. LOAD_FUNC(creat);
  312. fd = _libc_creat(pathname_,mode_);
  313. if(fd == -1)
  314. return -1;
  315. IOCTL_BUF real_pathname;
  316. rv = get_underlying_filepath(fd,real_pathname);
  317. if(rv == -1)
  318. return fd;
  319. rv = _libc_creat(real_pathname,mode_);
  320. if(rv == -1)
  321. return fd;
  322. close(fd);
  323. return rv;
  324. }
  325. int
  326. creat64(const char *pathname_,
  327. mode_t mode_)
  328. {
  329. int fd;
  330. int rv;
  331. LOAD_FUNC(creat64);
  332. fd = _libc_creat64(pathname_,mode_);
  333. if(fd == -1)
  334. return -1;
  335. IOCTL_BUF real_pathname;
  336. rv = get_underlying_filepath(fd,real_pathname);
  337. if(rv == -1)
  338. return fd;
  339. rv = _libc_creat64(real_pathname,mode_);
  340. if(rv == -1)
  341. return fd;
  342. close(fd);
  343. return rv;
  344. }