Use the AT_SECURE auxv flag to determine whether to enable secure mode.
The Linux kernel provides an AT_SECURE auxv flag to inform userspace
whether or not a security transition has occurred. This is more reliable
than directly checking the uid/gid against the euid/egid, because it covers
not only setuid/setgid but also file capabilities, SELinux, and AppArmor
security transitions. It is also a more efficient test since it does
not require any additional system calls.
Change-Id: I9752a4f6da452273258d2876d13b05e402fb0409
diff --git a/linker/linker.c b/linker/linker.c
index 17008f8..2722501 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -2085,7 +2085,7 @@
int argc = (int) *elfdata;
char **argv = (char**) (elfdata + 1);
- unsigned *vecs = (unsigned*) (argv + argc + 1);
+ unsigned *vecs = (unsigned*) (argv + argc + 1), *v;
soinfo *si;
struct link_map * map;
const char *ldpath_env = NULL;
@@ -2113,12 +2113,23 @@
*/
__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);
+ /* Check auxv for AT_SECURE first to see if program is setuid, setgid,
+ has file caps, or caused a SELinux/AppArmor domain transition. */
+ for (v = vecs; v[0]; v += 2) {
+ if (v[0] == AT_SECURE) {
+ /* kernel told us whether to enable secure mode */
+ program_is_setuid = v[1];
+ goto sanitize;
+ }
+ }
+
+ /* Kernel did not provide AT_SECURE - fall back on legacy test. */
+ program_is_setuid = (getuid() != geteuid()) || (getgid() != getegid());
+
+sanitize:
/* Sanitize environment if we're loading a setuid program */
if (program_is_setuid)
linker_env_secure();