linker: Remove unsecure env. variable for setuid programs.
This removes several unsecure environment variables from the
environment block when the program being loaded is setuid. The
list of env. variables is the same than what GLibc uses at this
point.
Change-Id: I456d3ea0880fe0d4de0d3c5dd51871dd36e87fd6
diff --git a/linker/linker.c b/linker/linker.c
index 42a5205..c4f54f7 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -48,6 +48,7 @@
#include "linker.h"
#include "linker_debug.h"
+#include "linker_environ.h"
#include "linker_format.h"
#include "ba.h"
@@ -123,6 +124,9 @@
int debug_verbosity;
static int pid;
+/* This boolean is set if the program being loaded is setuid */
+static int program_is_setuid;
+
#if STATS
struct _link_stats linker_stats;
#endif
@@ -286,7 +290,7 @@
/* Make sure we get a clean block of soinfo */
memset(si, 0, sizeof(soinfo));
- strcpy((char*) si->name, name);
+ strlcpy((char*) si->name, name, sizeof(si->name));
sonext->next = si;
si->ba_index = -1; /* by default, prelinked */
si->next = NULL;
@@ -314,7 +318,7 @@
return;
}
- /* prev will never be NULL, because the first entry in solist is
+ /* prev will never be NULL, because the first entry in solist is
always the static libdl_info.
*/
prev->next = si->next;
@@ -1232,8 +1236,8 @@
return init_library(si);
}
-/* TODO:
- * notify gdb of unload
+/* TODO:
+ * notify gdb of unload
* for non-prelinked libraries, find a way to decrement libbase
*/
static void call_destructors(soinfo *si);
@@ -1765,14 +1769,14 @@
}
#endif
if (phdr->p_type == PT_LOAD) {
- /* For the executable, we use the si->size field only in
- dl_unwind_find_exidx(), so the meaning of si->size
- is not the size of the executable; it is the last
+ /* For the executable, we use the si->size field only in
+ dl_unwind_find_exidx(), so the meaning of si->size
+ is not the size of the executable; it is the last
virtual address of the loadable part of the executable;
since si->base == 0 for an executable, we use the
- range [0, si->size) to determine whether a PC value
+ range [0, si->size) to determine whether a PC value
falls within the executable section. Of course, if
- a value is below phdr->p_vaddr, it's not in the
+ a value is below phdr->p_vaddr, it's not in the
executable section, but a) we shouldn't be asking for
such a value anyway, and b) if we have to provide
an EXIDX for such a value, then the executable's
@@ -1927,7 +1931,7 @@
}
}
- DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
+ DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
pid, si->base, si->strtab, si->symtab);
if((si->strtab == 0) || (si->symtab == 0)) {
@@ -2033,7 +2037,7 @@
ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
*/
- if (getuid() != geteuid() || getgid() != getegid())
+ if (program_is_setuid)
nullify_closed_stdio ();
call_constructors(si);
notify_gdb_of_load(si);
@@ -2045,7 +2049,7 @@
return -1;
}
-static void parse_library_path(char *path, char *delim)
+static void parse_library_path(const char *path, char *delim)
{
size_t len;
char *ldpaths_bufp = ldpaths_buf;
@@ -2068,7 +2072,7 @@
}
}
-static void parse_preloads(char *path, char *delim)
+static void parse_preloads(const char *path, char *delim)
{
size_t len;
char *ldpreloads_bufp = ldpreloads_buf;
@@ -2110,8 +2114,8 @@
unsigned *vecs = (unsigned*) (argv + argc + 1);
soinfo *si;
struct link_map * map;
- char *ldpath_env = NULL;
- char *ldpreload_env = NULL;
+ const char *ldpath_env = NULL;
+ const char *ldpreload_env = NULL;
/* Setup a temporary TLS area that is used to get a working
* errno for system calls.
@@ -2135,20 +2139,32 @@
*/
__tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
+ /* Are we setuid? */
+ program_is_setuid = (getuid() != geteuid()) || (getgid() != getegid());
+
+ /* Initialize environment functions, and get to the ELF aux vectors table */
+ vecs = linker_env_init(vecs);
+
+ /* Sanitize environment if we're loading a setuid program */
+ if (program_is_setuid)
+ linker_env_secure();
+
debugger_init();
- /* skip past the environment */
- while(vecs[0] != 0) {
- if(!strncmp((char*) vecs[0], "DEBUG=", 6)) {
- debug_verbosity = atoi(((char*) vecs[0]) + 6);
- } else if(!strncmp((char*) vecs[0], "LD_LIBRARY_PATH=", 16)) {
- ldpath_env = (char*) vecs[0] + 16;
- } else if(!strncmp((char*) vecs[0], "LD_PRELOAD=", 11)) {
- ldpreload_env = (char*) vecs[0] + 11;
+ /* Get a few environment variables */
+ {
+ const char* env;
+ env = linker_env_get("DEBUG"); /* XXX: TODO: Change to LD_DEBUG */
+ if (env)
+ debug_verbosity = atoi(env);
+
+ /* Normally, these are cleaned by linker_env_secure, but the test
+ * against program_is_setuid doesn't cost us anything */
+ if (!program_is_setuid) {
+ ldpath_env = linker_env_get("LD_LIBRARY_PATH");
+ ldpreload_env = linker_env_get("LD_PRELOAD");
}
- vecs++;
}
- vecs++;
INFO("[ android linker & debugger ]\n");
DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
@@ -2176,7 +2192,7 @@
* is. Don't use alloc_info(), because the linker shouldn't
* be on the soinfo list.
*/
- strcpy((char*) linker_soinfo.name, "/system/bin/linker");
+ strlcpy((char*) linker_soinfo.name, "/system/bin/linker", sizeof linker_soinfo.name);
linker_soinfo.flags = 0;
linker_soinfo.base = 0; // This is the important part; must be zero.
insert_soinfo_into_debug_map(&linker_soinfo);
@@ -2206,10 +2222,10 @@
si->refcount = 1;
/* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
- if (ldpath_env && getuid() == geteuid() && getgid() == getegid())
+ if (ldpath_env)
parse_library_path(ldpath_env, ":");
- if (ldpreload_env && getuid() == geteuid() && getgid() == getegid()) {
+ if (ldpreload_env) {
parse_preloads(ldpreload_env, " :");
}