libc: add getauxval()

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
This commit is contained in:
Nick Kralevich
2013-01-11 14:43:05 -08:00
parent 69c89942db
commit 2c5153b043
9 changed files with 214 additions and 28 deletions

48
libc/bionic/getauxval.cpp Normal file
View File

@@ -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;
}

View 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'.
}

View 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));
}