diff --git a/tools/linuxfs/preload/netif.c b/tools/linuxfs/preload/netif.c index 078f6a301..41775e135 100644 --- a/tools/linuxfs/preload/netif.c +++ b/tools/linuxfs/preload/netif.c @@ -483,12 +483,12 @@ static FILE *synthesize(const char *table) { } /* tracer.c */ -int bl_status_without_tracer(const char *path, int flags) __attribute__((visibility("hidden"))); +int bl_status_without_tracer(const char *path, int flags, const void *caller) __attribute__((visibility("hidden"))); static FILE *open_stream(const char *symbol, const char *path, const char *mode) { typedef FILE *(*fopen_fn)(const char *, const char *); int status = mode && mode[0] == 'r' && !strchr(mode, '+') - ? bl_status_without_tracer(path, O_RDONLY | O_CLOEXEC) : -1; + ? bl_status_without_tracer(path, O_RDONLY | O_CLOEXEC, NULL) : -1; if (status >= 0) { FILE *copy = fdopen(status, "r"); if (copy == NULL) close(status); diff --git a/tools/linuxfs/preload/opens.c b/tools/linuxfs/preload/opens.c index 4c8b6e165..497d0d865 100644 --- a/tools/linuxfs/preload/opens.c +++ b/tools/linuxfs/preload/opens.c @@ -33,7 +33,7 @@ #include #include -int bl_status_without_tracer(const char *path, int flags) __attribute__((visibility("hidden"))); +int bl_status_without_tracer(const char *path, int flags, const void *caller) __attribute__((visibility("hidden"))); int bl_writable_retry(int dirfd, const char *path, int flags) __attribute__((visibility("hidden"))); static int retry_without_noatime(int fd, int flags) { @@ -60,7 +60,7 @@ int open(const char *path, int flags, ...) { errno = EACCES; return -1; } - if ((fd = bl_status_without_tracer(path, flags)) >= 0) return fd; + if ((fd = bl_status_without_tracer(path, flags, __builtin_return_address(0))) >= 0) return fd; if (real_open == NULL) real_open = dlsym(RTLD_NEXT, "open"); if (real_open == NULL) { errno = ENOSYS; @@ -86,7 +86,7 @@ int openat(int dirfd, const char *path, int flags, ...) { errno = EACCES; return -1; } - if ((fd = bl_status_without_tracer(path, flags)) >= 0) return fd; + if ((fd = bl_status_without_tracer(path, flags, __builtin_return_address(0))) >= 0) return fd; if (real_openat == NULL) real_openat = dlsym(RTLD_NEXT, "openat"); if (real_openat == NULL) { errno = ENOSYS; diff --git a/tools/linuxfs/preload/tracer.c b/tools/linuxfs/preload/tracer.c index 3fe6a8ca1..b7eaf52e3 100644 --- a/tools/linuxfs/preload/tracer.c +++ b/tools/linuxfs/preload/tracer.c @@ -18,6 +18,7 @@ */ #define _GNU_SOURCE #include +#include #include #include #include @@ -48,14 +49,20 @@ static int is_status_path(const char *path) { } /* Chromium stands its hang watchdogs down when it sees a tracer, and the client's web helper does - * not come up within their patience here: it is left reading the truth. Not so for the x86-64 - * client under FEX (BL_WEBHELPER_HIDE_TRACER=1, set by bannerlator-steam-x64): its tier0 breaks - * into the supposed debugger with int3 on the first failed assertion, and the web helper dies of - * SIGTRAP a second after it starts. */ -static int is_web_helper(void) { + * not come up within their patience here: it is left reading the truth. Chromium also traps when a + * status descriptor it opened turns out not to be procfs. The x86-64 client under FEX + * (BL_WEBHELPER_HIDE_TRACER=1, set by bannerlator-steam-x64) still needs its tier0 told: tier0 + * reads the status, sees the tracer, and breaks into the supposed debugger with int3 on the first + * failed assertion - the web helper died of SIGTRAP a second after it started. There tier0's own + * opens (by caller) get the copy and Chromium's the real file. */ +static int is_web_helper(const void *caller) { if (strcmp(program_invocation_short_name, "steamwebhelper") != 0) return 0; const char *hide = getenv("BL_WEBHELPER_HIDE_TRACER"); - return !(hide && hide[0] == '1'); + Dl_info info; + if (hide && hide[0] == '1' && caller && dladdr(caller, &info) && info.dli_fname + && strstr(info.dli_fname, "libtier0_s.so")) + return 0; + return 1; } static int write_all(int fd, const char *data, size_t len) { @@ -71,13 +78,13 @@ static int write_all(int fd, const char *data, size_t len) { /* The descriptor to hand back for a read-only open of a status file, or -1 with errno untouched * when the path is something else or the copy cannot be made, and the real open should run. */ -__attribute__((visibility("hidden"))) int bl_status_without_tracer(const char *path, int flags) { +__attribute__((visibility("hidden"))) int bl_status_without_tracer(const char *path, int flags, const void *caller) { char text[STATUS_MAX]; size_t len = 0; int saved = errno; int out = -1; - if ((flags & O_ACCMODE) != O_RDONLY || !is_status_path(path) || is_web_helper()) return -1; + if ((flags & O_ACCMODE) != O_RDONLY || !is_status_path(path) || is_web_helper(caller)) return -1; int in = (int)syscall(SYS_openat, AT_FDCWD, path, O_RDONLY | O_CLOEXEC); if (in < 0) goto done; for (;;) {