From f23fb58690246d0526f42316c9a35274e34ffaf9 Mon Sep 17 00:00:00 2001 From: "A. Wilcox" Date: Mon, 17 Oct 2022 01:44:03 -0500 Subject: 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 --- libgcompat/stdio.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'libgcompat') 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 */ +#include /* dlsym, RTLD_NEXT */ +#include /* errno, ENOSYS */ +#include /* PATH_MAX */ #include /* va_list, va_start, va_end */ #include /* NULL, size_t */ -#include /* feof, fgets, fread, puts, v*printf */ +#include /* feof, fgets, fopen, fread, puts, v*printf */ +#include /* 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); @@ -76,6 +80,33 @@ char *__fgets_unlocked_chk(char *s, size_t slen, int n, FILE *stream) return fgets_unlocked(s, n, 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. * -- cgit v1.2.3-70-g09d2