From 8f3a28e453f30c04185478864860c72afff6669e Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sat, 3 Jul 2010 17:34:50 +0200 Subject: [PATCH] Avoid getenv() - dlsym() - calloc() - getenv() race This causes new firefox to hang; the first getenv() call comes from calloc(), but this means a nasty race condition; setup up_getenv in a constructor instead, and give an empty string to getenv() from the calloc() of up_getenv dlsym(). Ugh. --- screenenv.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/screenenv.c b/screenenv.c index 48f19b9..f1145c0 100644 --- a/screenenv.c +++ b/screenenv.c @@ -27,6 +27,24 @@ const static char *grabenv[] = { }; +/* getenv() upcall setup. */ + +static char *(*up_getenv)(const char *); +static int in_screen = 0; + +static void __attribute__((constructor)) +up_getenv_setup(void) +{ + /* XXX: We do this here instead of lazily on first call, since + * there is a possibility of dlsym()-malloc() race when called + * within a getenv() call. */ + up_getenv = dlsym(RTLD_NEXT, "getenv"); + + char *term = up_getenv("TERM"); + in_screen = term && !strcmp(term, "screen"); +} + + /* The cached environment. */ struct env { @@ -149,16 +167,13 @@ next_data: __attribute__((visibility("default"))) char * getenv(const char *env) { - static char *(*up_getenv)(const char *); - if (__builtin_expect(!up_getenv, 0)) - up_getenv = dlsym(RTLD_NEXT, "getenv"); + /* We may be called by a crazy + * up_getenv_setup() -> dlsym() -> calloc() -> getenv() + * sequence. */ + if (__builtin_expect(up_getenv == NULL, 0)) + return ""; /* XXX */ /* The fast way out, not to hog non-screen processes. */ - static int in_screen = -1; - if (__builtin_expect(in_screen < 0, 0)) { - char *term = up_getenv("TERM"); - in_screen = term && !strcmp(term, "screen"); - } if (__builtin_expect(!in_screen, 1)) return up_getenv(env); -- 2.11.4.GIT