OSDN Git Service

libc: add getauxval()
authorNick Kralevich <nnk@google.com>
Fri, 11 Jan 2013 22:43:05 +0000 (14:43 -0800)
committerNick Kralevich <nnk@google.com>
Sat, 12 Jan 2013 00:44:15 +0000 (16:44 -0800)
Add support for getauxval().  This method allows a program an easy way
to retrieve information from the kernel auxiliary vector, and will
hopefully replace other clumsy ways of accessing this same information.

This particular function was also added to glibc in glibc 2.16.
See the following URLs for more details.

  * http://lwn.net/Articles/519085/
  * http://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html

This change is a prerequisite for bug 7959813.

Bug: http://code.google.com/p/android/issues/detail?id=38441
Change-Id: Iba19d899df334bddc6f4899077ece2fc87564ea8

libc/Android.mk
libc/bionic/getauxval.cpp [new file with mode: 0644]
libc/bionic/libc_init_common.c
libc/bionic/libc_init_static.c
libc/include/elf.h
libc/include/sys/auxv.h [new file with mode: 0644]
libc/private/bionic_auxv.h [new file with mode: 0644]
tests/Android.mk
tests/getauxval_test.cpp [new file with mode: 0644]

index 360bdc1..c98d2ff 100644 (file)
@@ -275,6 +275,7 @@ libc_bionic_src_files := \
     bionic/dirent.cpp \
     bionic/eventfd.cpp \
     bionic/__fgets_chk.cpp \
+    bionic/getauxval.cpp \
     bionic/getcwd.cpp \
     bionic/libgen.cpp \
     bionic/__memcpy_chk.cpp \
diff --git a/libc/bionic/getauxval.cpp b/libc/bionic/getauxval.cpp
new file mode 100644 (file)
index 0000000..38a05fc
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <sys/cdefs.h>
+#include <sys/auxv.h>
+#include <private/bionic_auxv.h>
+#include <elf.h>
+
+__LIBC_HIDDEN__
+Elf32_auxv_t* __libc_auxv = NULL;
+
+extern "C" unsigned long int getauxval(unsigned long int type) {
+  Elf32_auxv_t* v;
+
+  for (v = __libc_auxv; v->a_type != AT_NULL; v++) {
+    if (v->a_type == type) {
+      return v->a_un.a_val;
+    }
+  }
+
+  return 0;
+}
index fb164f4..86e1eb5 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <bionic_tls.h>
 #include <errno.h>
+#include <private/bionic_auxv.h>
 
 extern unsigned __get_sp(void);
 extern pid_t gettid(void);
@@ -95,6 +96,15 @@ void __libc_init_common(uintptr_t* elf_data) {
   __progname = argv[0] ? argv[0] : "<unknown>";
   environ = envp;
 
+  // The auxiliary vector is at the end of the environment block
+  while(*envp != NULL) {
+    envp++;
+  }
+  /* The end of the environment block is marked by two NULL pointers */
+  envp++;
+
+  __libc_auxv = (Elf32_auxv_t*) envp;
+
   __system_properties_init(); // Requires 'environ'.
 }
 
index ba7f008..bb3a410 100644 (file)
@@ -49,6 +49,7 @@
 #include <bionic_tls.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <sys/auxv.h>
 
 // Returns the address of the page containing address 'x'.
 #define PAGE_START(x)  ((x) & PAGE_MASK)
@@ -65,27 +66,13 @@ static void call_array(void(**list)())
     }
 }
 
-/*
- * Find the value of the AT_* variable passed to us by the kernel.
- */
-static unsigned find_aux(unsigned *vecs, unsigned type) {
-    while (vecs[0]) {
-        if (vecs[0] == type) {
-            return vecs[1];
-        }
-        vecs += 2;
-    }
-
-    return 0; // should never happen
-}
-
-static void apply_gnu_relro(unsigned *vecs) {
+static void apply_gnu_relro() {
     Elf32_Phdr *phdr_start;
-    unsigned phdr_ct;
+    unsigned long int phdr_ct;
     Elf32_Phdr *phdr;
 
-    phdr_start = (Elf32_Phdr *) find_aux(vecs, AT_PHDR);
-    phdr_ct    = find_aux(vecs, AT_PHNUM);
+    phdr_start = (Elf32_Phdr *) getauxval(AT_PHDR);
+    phdr_ct    = getauxval(AT_PHNUM);
 
     for (phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) {
         if (phdr->p_type != PT_GNU_RELRO)
@@ -108,7 +95,6 @@ __noreturn void __libc_init(uintptr_t *elfdata,
 {
     int  argc;
     char **argv, **envp;
-    unsigned *vecs;
 
     __libc_init_tls(NULL);
 
@@ -129,14 +115,6 @@ __noreturn void __libc_init(uintptr_t *elfdata,
     argv = (char**)(elfdata + 1);
     envp = argv + argc + 1;
 
-    // The auxiliary vector is at the end of the environment block
-    vecs = (unsigned *) envp;
-    while (vecs[0] != 0) {
-        vecs++;
-    }
-    /* The end of the environment block is marked by two NULL pointers */
-    vecs++;
-
     /* The executable may have its own destructors listed in its .fini_array
      * so we need to ensure that these are called when the program exits
      * normally.
@@ -144,6 +122,6 @@ __noreturn void __libc_init(uintptr_t *elfdata,
     if (structors->fini_array)
         __cxa_atexit(__libc_fini,structors->fini_array,NULL);
 
-    apply_gnu_relro(vecs);
+    apply_gnu_relro();
     exit(slingshot(argc, argv, envp));
 }
index c3e3226..ac0f1d2 100644 (file)
 #ifndef _ELF_H
 #define _ELF_H
 
+#include <stdint.h>
 #include <linux/auxvec.h>
 #include <sys/exec_elf.h>
 
+typedef struct {
+  uint32_t a_type;
+  union {
+    uint32_t a_val;
+  } a_un;
+} Elf32_auxv_t;
+
+typedef struct {
+  uint64_t a_type;
+  union {
+    uint64_t a_val;
+  } a_un;
+} Elf64_auxv_t;
+
 #endif /* _ELF_H */
 
diff --git a/libc/include/sys/auxv.h b/libc/include/sys/auxv.h
new file mode 100644 (file)
index 0000000..918442f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _SYS_AUXV_H_
+#define _SYS_AUXV_H_
+
+#include <linux/auxvec.h>
+
+__BEGIN_DECLS
+
+unsigned long int getauxval(unsigned long int type);
+
+__END_DECLS
+
+#endif /* _SYS_AUXV_H_ */
diff --git a/libc/private/bionic_auxv.h b/libc/private/bionic_auxv.h
new file mode 100644 (file)
index 0000000..d3b0038
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _SYS_AUXV_H_
+#define _SYS_AUXV_H_
+
+#include <elf.h>
+
+__BEGIN_DECLS
+
+extern Elf32_auxv_t* __libc_auxv;
+
+__END_DECLS
+
+#endif /* _SYS_AUXV_H_ */
index 635c021..25da120 100644 (file)
@@ -55,6 +55,7 @@ test_c_flags = \
 test_src_files = \
     dirent_test.cpp \
     fenv_test.cpp \
+    getauxval_test.cpp \
     getcwd_test.cpp \
     libgen_test.cpp \
     pthread_test.cpp \
diff --git a/tests/getauxval_test.cpp b/tests/getauxval_test.cpp
new file mode 100644 (file)
index 0000000..01c11c3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/cdefs.h>
+#include <features.h>
+#include <gtest/gtest.h>
+
+// getauxval() was only added as of glibc version 2.16.
+// See: http://lwn.net/Articles/519085/
+// Don't try to compile this code on older glibc versions.
+
+#if defined(__BIONIC__)
+  #define GETAUXVAL_CAN_COMPILE 1
+#elif defined(__GLIBC_PREREQ)
+  #if __GLIBC_PREREQ(2, 16)
+    #define GETAUXVAL_CAN_COMPILE 1
+  #endif
+#endif
+
+#if defined(GETAUXVAL_CAN_COMPILE)
+
+#include <sys/auxv.h>
+
+TEST(getauxval, expected_values) {
+  ASSERT_EQ((unsigned long int) 0, getauxval(AT_SECURE));
+  ASSERT_EQ(getuid(), getauxval(AT_UID));
+  ASSERT_EQ(geteuid(), getauxval(AT_EUID));
+  ASSERT_EQ(getgid(), getauxval(AT_GID));
+  ASSERT_EQ(getegid(), getauxval(AT_EGID));
+  ASSERT_EQ((unsigned long int) getpagesize(), getauxval(AT_PAGESZ));
+
+  ASSERT_NE((unsigned long int) 0, getauxval(AT_PHDR));
+  ASSERT_NE((unsigned long int) 0, getauxval(AT_PHNUM));
+  ASSERT_NE((unsigned long int) 0, getauxval(AT_ENTRY));
+  ASSERT_NE((unsigned long int) 0, getauxval(AT_PAGESZ));
+}
+
+TEST(getauxval, unexpected_values) {
+  ASSERT_EQ((unsigned long int) 0, getauxval(0xdeadbeef));
+}
+
+#endif /* GETAUXVAL_CAN_COMPILE */