[PATCH] Add getenv.so for catching invalid getenv() use via LD_PRELOAD
From: Nguyễn Thái Ngọc Duy <hidden>
Date: 2016-06-15 22:55:39
Subsystem:
the rest · Maintainer:
Linus Torvalds
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
Perhaps this will help the getenv bug hunting (I assume we do the
hunting on Linux platform only). So far it catches this and is stuck
at getenv in git_pager().
diff --git a/exec_cmd.c b/exec_cmd.c
index 125fa6f..d8be5ce 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -97,7 +97,7 @@ static void add_path(struct strbuf *out, const char *path)
void setup_path(void)
{
- const char *old_path = getenv("PATH");
+ char *old_path = xstrdup(getenv("PATH"));
struct strbuf new_path = STRBUF_INIT;
add_path(&new_path, git_exec_path());
@@ -110,6 +110,7 @@ void setup_path(void)
setenv("PATH", new_path.buf, 1);
+ free(old_path);
strbuf_release(&new_path);
}
contrib/getenv/Makefile | 2 ++
contrib/getenv/getenv.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+)
create mode 100644 contrib/getenv/Makefile
create mode 100644 contrib/getenv/getenv.c
diff --git a/contrib/getenv/Makefile b/contrib/getenv/Makefile
new file mode 100644
index 0000000..4881b85
--- /dev/null
+++ b/contrib/getenv/Makefile@@ -0,0 +1,2 @@ +getenv.so: getenv.c + $(CC) -g -shared -fPIC -ldl -o $@ $<
diff --git a/contrib/getenv/getenv.c b/contrib/getenv/getenv.c
new file mode 100644
index 0000000..e351e10
--- /dev/null
+++ b/contrib/getenv/getenv.c@@ -0,0 +1,67 @@ +#include <gnu/lib-names.h> +#include <sys/mman.h> +#include <dlfcn.h> +#include <execinfo.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +/* Global symbols for easy access from gdb */ +static char *getenv_current; +static char *getenv_prev; + +/* + * Intercept standard getenv() via LD_PRELOAD. The return value is + * made inaccessible by the next getenv() call. This helps catch + * places that ignore the statement "The string pointed to may be + * overwritten by a subsequent call to getenv()" [1]. + * + * The backtrace is appended after the env string, which may be + * helpful to identify where this getenv() is called in a core dump. + * + * [1] http://pubs.opengroup.org/onlinepubs/9699919799/functions/getenv.html + */ +char *getenv(const char *name) +{ + static char *(*libc_getenv)(const char*); + char *value; + + if (!libc_getenv) { + void *libc = dlopen(LIBC_SO, RTLD_LAZY); + libc_getenv = dlsym(libc, "getenv"); + } + if (getenv_current) { + mprotect(getenv_current, strlen(getenv_current) + 1, PROT_NONE); + getenv_prev = getenv_current; + getenv_current = NULL; + } + + value = libc_getenv(name); + if (value) { + int len = strlen(value) + 1; + int backtrace_len = 0; + void *buffer[100]; + char **symbols; + int i, n; + + n = backtrace(buffer, 100); + symbols = backtrace_symbols(buffer, n); + if (symbols) { + for (i = 0;i < n; i++) + backtrace_len += strlen(symbols[i]) + 1; /* \n */ + backtrace_len++; /* NULL */ + } + + getenv_current = mmap(NULL, len + backtrace_len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + memcpy(getenv_current, value, len); + value = getenv_current; + + if (symbols) { + char *p = getenv_current + len; + for (i = 0; i < n; i++) + p += sprintf(p, "%s\n", symbols[i]); + } + } + return value; +}
--
1.8.0.rc2.23.g1fb49df