diff options
author | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2022-10-17 01:44:03 -0500 |
---|---|---|
committer | A. Wilcox <AWilcox@Wilcox-Tech.com> | 2022-10-17 01:44:03 -0500 |
commit | f23fb58690246d0526f42316c9a35274e34ffaf9 (patch) | |
tree | 970744993ef13e84433a72cb774c6ad7b6435671 /libgcompat | |
parent | 158f2b53d81c9a453df0124a7ac2153c3f8286da (diff) | |
download | gcompat-f23fb58690246d0526f42316c9a35274e34ffaf9.tar.gz gcompat-f23fb58690246d0526f42316c9a35274e34ffaf9.tar.bz2 gcompat-f23fb58690246d0526f42316c9a35274e34ffaf9.tar.xz gcompat-f23fb58690246d0526f42316c9a35274e34ffaf9.zip |
stdio: Hook fopen(3) to intercept /proc/self/exe
Unfortunately, we do have a potential race if the binary is renamed
between the call to readlink and the real fopen.
Fixes: #349
Diffstat (limited to 'libgcompat')
-rw-r--r-- | libgcompat/stdio.c | 33 |
1 files changed, 32 insertions, 1 deletions
diff --git a/libgcompat/stdio.c b/libgcompat/stdio.c index f0b248a..dbadb25 100644 --- a/libgcompat/stdio.c +++ b/libgcompat/stdio.c @@ -1,8 +1,12 @@ #define _GNU_SOURCE /* fgets_unlocked */ #include <assert.h> /* assert */ +#include <dlfcn.h> /* dlsym, RTLD_NEXT */ +#include <errno.h> /* errno, ENOSYS */ +#include <limits.h> /* PATH_MAX */ #include <stdarg.h> /* va_list, va_start, va_end */ #include <stddef.h> /* NULL, size_t */ -#include <stdio.h> /* feof, fgets, fread, puts, v*printf */ +#include <stdio.h> /* feof, fgets, fopen, fread, puts, v*printf */ +#include <string.h> /* strcmp */ int __vasprintf_chk(char **strp, int flag, const char *format, va_list ap); int __vfprintf_chk(FILE *stream, int flag, const char *format, va_list ap); @@ -77,6 +81,33 @@ char *__fgets_unlocked_chk(char *s, size_t slen, int n, FILE *stream) } /** + * Open a stream. + */ + +ssize_t readlink(const char *path, char *buf, size_t len); +static FILE *(*real_fopen)(const char *, const char *); + +FILE *fopen(const char *restrict pathname, const char *restrict mode) +{ + if (real_fopen == NULL) { + real_fopen = dlsym(RTLD_NEXT, "fopen"); + if (real_fopen == NULL) { + errno = ENOSYS; + return NULL; + } + } + + if (!strcmp(pathname, "/proc/self/exe")) { + char real_self[PATH_MAX]; + if (readlink("/proc/self/exe", real_self, PATH_MAX) == -1) { + return NULL; + } + return real_fopen(real_self, mode); + } + return real_fopen(pathname, mode); +} + +/** * Convert formatted output, with stack checking. * * LSB 5.0: LSB-Core-generic/baselib---fprintf-chk-1.html |