summaryrefslogtreecommitdiff
path: root/libgcompat
diff options
context:
space:
mode:
authorA. Wilcox <AWilcox@Wilcox-Tech.com>2022-10-17 01:44:03 -0500
committerA. Wilcox <AWilcox@Wilcox-Tech.com>2022-10-17 01:44:03 -0500
commitf23fb58690246d0526f42316c9a35274e34ffaf9 (patch)
tree970744993ef13e84433a72cb774c6ad7b6435671 /libgcompat
parent158f2b53d81c9a453df0124a7ac2153c3f8286da (diff)
downloadgcompat-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.c33
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