From 131ba72ee52b106eb5084d141ee296cecf4a5b80 Mon Sep 17 00:00:00 2001 From: The412Banner Date: Fri, 2 Oct 2026 16:28:43 -0400 Subject: [PATCH] x86-64 client: hide the tracer only from tier0's status reads Hiding it from the whole x86 web helper got it past tier0 (message loop, BrowserCreated) but then Chromium trapped on the status descriptor it opened itself, now a memfd copy - which is the other reason the shim leaves the web helper alone. With BL_WEBHELPER_HIDE_TRACER=1 only opens called from libtier0_s.so get the copy; Chromium's get procfs. --- tools/linuxfs/preload/netif.c | 4 ++-- tools/linuxfs/preload/opens.c | 6 +++--- tools/linuxfs/preload/tracer.c | 23 +++++++++++++++-------- 3 files changed, 20 insertions(+), 13 deletions(-) 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 (;;) {