[PATCH] libc: deal with aux vect inside __uClibc_main only if !SHARED

Filippo ARCIDIACONO filippo.arcidiacono at st.com
Thu Dec 13 11:34:39 UTC 2012


It's not safe to use the aux vect inside __uClibc_main if we are running
with shared libraries, because it could have been already modified.
For example, if some constructor plays with environment variables by
using unsetenv, the modifications done into the stack to unset an
environment variable, have impacts on the aux vect due to the extra NULL
entries added.
Due to this, __uClibc_main is not able to detect where the aux vect
starts, so all the entries that are used by __uClibc_main (AT_UID,
AT_EUID, AT_GID, AT_EGID, AT_PAGESZ and possibly other arch specific)
are impacted.

Same side effect on the aux vect is caused by the ld.so when running a
SUID program with some of the unsecure environment variables set, that
will be unset by the ld.so itself.

In order to fix this issue, it needs to handle aux vect entries into
__uClibc_main only if SHARED is not defined.
In SHARED case, libc refers to __dl_secure and _dl_pagesize as initialised
by the ld.so where the aux vext is still untouched.

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono at st.com>
Reviewed-by: Carmelo Amoroso <carmelo.amoroso at st.com>
---
 ldso/ldso/ldso.c                    |    2 +-
 libc/misc/elf/dl-support.c          |    4 ++++
 libc/misc/internals/__uClibc_main.c |   20 ++++++++++++++------
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index becabd3..29bf5b0 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -64,7 +64,7 @@ struct elf_resolve *_dl_trace_prelink_map    = NULL;	/* Library module for preli
 bool _dl_verbose				= true;					/* On by default */
 bool prelinked					= false;
 #endif
-static int _dl_secure = 1; /* Are we dealing with setuid stuff? */
+int _dl_secure = 1; /* Are we dealing with setuid stuff? */
 
 #ifdef __SUPPORT_LD_DEBUG__
 char *_dl_debug           = NULL;
diff --git a/libc/misc/elf/dl-support.c b/libc/misc/elf/dl-support.c
index f194692..ae77f52 100644
--- a/libc/misc/elf/dl-support.c
+++ b/libc/misc/elf/dl-support.c
@@ -28,6 +28,7 @@ void (*_dl_init_static_tls) (struct link_map *) = &_dl_nothread_init_static_tls;
 
 ElfW(Phdr) *_dl_phdr;
 size_t _dl_phnum;
+size_t _dl_pagesize;
 
 void internal_function _dl_aux_init (ElfW(auxv_t) *av);
 void internal_function _dl_aux_init (ElfW(auxv_t) *av)
@@ -37,6 +38,9 @@ void internal_function _dl_aux_init (ElfW(auxv_t) *av)
 
    /* Get the number of program headers from the aux vect */
    _dl_phnum = (size_t) av[AT_PHNUM].a_un.a_val;
+
+   /* Get the pagesize from the aux vect */
+   _dl_pagesize = (av[AT_PAGESZ].a_un.a_val) ? (size_t) av[AT_PAGESZ].a_un.a_val : PAGE_SIZE;
 }
 
 #if defined(USE_TLS) && USE_TLS
diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c
index 8a3646c..09580d7 100644
--- a/libc/misc/internals/__uClibc_main.c
+++ b/libc/misc/internals/__uClibc_main.c
@@ -140,6 +140,11 @@ extern void (*__fini_array_end []) (void) attribute_hidden;
 # endif
 #endif
 
+#ifdef SHARED
+extern int _dl_secure;
+#endif
+extern size_t _dl_pagesize;
+
 const char *__uclibc_progname = "";
 #if !defined __UCLIBC_HAS___PROGNAME__ && defined __USE_GNU && defined __UCLIBC_HAS_PROGRAM_INVOCATION_NAME__
 # define __progname program_invocation_short_name
@@ -168,7 +173,7 @@ size_t __pagesize = 0;
 # define O_NOFOLLOW	0
 #endif
 
-#ifndef __ARCH_HAS_NO_LDSO__
+#if !defined __ARCH_HAS_NO_LDSO__ && !defined SHARED
 static void __check_one_fd(int fd, int mode)
 {
     /* Check if the specified fd is already open */
@@ -339,7 +344,7 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
 	__environ = &argv[argc];
     }
 
-#ifndef __ARCH_HAS_NO_LDSO__
+#if !defined __ARCH_HAS_NO_LDSO__ && !defined SHARED
     /* Pull stuff from the ELF header when possible */
     memset(auxvt, 0x00, sizeof(auxvt));
     aux_dat = (unsigned long*)__environ;
@@ -354,13 +359,11 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
 	}
 	aux_dat += 2;
     }
-#ifndef SHARED
     /* Get the program headers (_dl_phdr) from the aux vector
        It will be used into __libc_setup_tls. */
 
     _dl_aux_init (auxvt);
 #endif
-#endif
 
     /* We need to initialize uClibc.  If we are dynamically linked this
      * may have already been completed by the shared lib loader.  We call
@@ -368,15 +371,20 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
     __uClibc_init();
 
 #ifndef __ARCH_HAS_NO_LDSO__
-    /* Make certain getpagesize() gives the correct answer */
-    __pagesize = (auxvt[AT_PAGESZ].a_un.a_val)? auxvt[AT_PAGESZ].a_un.a_val : PAGE_SIZE;
+    /* Make certain getpagesize() gives the correct answer.
+     * _dl_pagesize is defined into ld.so if SHARED or into libc.a otherwise. */
+    __pagesize = _dl_pagesize;
 
+#ifndef SHARED
     /* Prevent starting SUID binaries where the stdin. stdout, and
      * stderr file descriptors are not already opened. */
     if ((auxvt[AT_UID].a_un.a_val == (size_t)-1 && __check_suid()) ||
 	    (auxvt[AT_UID].a_un.a_val != (size_t)-1 &&
 	    (auxvt[AT_UID].a_un.a_val != auxvt[AT_EUID].a_un.a_val ||
 	     auxvt[AT_GID].a_un.a_val != auxvt[AT_EGID].a_un.a_val)))
+#else
+    if (_dl_secure)
+#endif
     {
 	__check_one_fd (STDIN_FILENO, O_RDONLY | O_NOFOLLOW);
 	__check_one_fd (STDOUT_FILENO, O_RDWR | O_NOFOLLOW);
-- 
1.7.7.6



More information about the uClibc mailing list