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

Filippo ARCIDIACONO filippo.arcidiacono at st.com
Fri Dec 14 10:40:05 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 |   22 ++++++++++++++++------
 3 files changed, 21 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..a37751f 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
@@ -186,6 +191,7 @@ static void __check_one_fd(int fd, int mode)
     }
 }
 
+#ifndef SHARED
 static int __check_suid(void)
 {
     uid_t uid, euid;
@@ -202,6 +208,7 @@ static int __check_suid(void)
     return 0; /* we are not suid */
 }
 #endif
+#endif
 
 /* __uClibc_init completely initialize uClibc so it is ready to use.
  *
@@ -313,7 +320,7 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,
 		    char **argv, void (*app_init)(void), void (*app_fini)(void),
 		    void (*rtld_fini)(void), void *stack_end attribute_unused)
 {
-#ifndef __ARCH_HAS_NO_LDSO__
+#if !defined __ARCH_HAS_NO_LDSO__ && !defined SHARED
     unsigned long *aux_dat;
     ElfW(auxv_t) auxvt[AT_EGID + 1];
 #endif
@@ -339,7 +346,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 +361,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 +373,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