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

View 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 \

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

View File

@ -28,8 +28,23 @@
#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 */

39
libc/include/sys/auxv.h Normal file
View File

@ -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_ */

View File

@ -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_ */

View 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 \

55
tests/getauxval_test.cpp Normal file
View File

@ -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 */