Merge commit '7d545233acf6c4d73a623c16ca96cb7d4b9f5db7' into honeycomb-release-to-dalvik-dev

This commit is contained in:
Brian Carlstrom 2011-01-25 14:32:09 -08:00
commit c7703c481a
20 changed files with 453 additions and 369 deletions

View File

@ -398,6 +398,7 @@ libc_common_src_files += \
arch-x86/bionic/_exit_with_stack_teardown.S \
arch-x86/bionic/setjmp.S \
arch-x86/bionic/_setjmp.S \
arch-x86/bionic/sigsetjmp.S \
arch-x86/bionic/vfork.S \
arch-x86/bionic/syscall.S \
arch-x86/string/bcopy_wrapper.S \

View File

@ -0,0 +1,92 @@
/* $OpenBSD: sigsetjmp.S,v 1.7 2005/08/07 11:30:38 espie Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* William Jolitz.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 <machine/asm.h>
ENTRY(sigsetjmp)
movl 4(%esp),%ecx
movl 8(%esp),%eax
movl %eax,28(%ecx)
testl %eax,%eax
jz 1f
PIC_PROLOGUE
pushl $0
#ifdef PIC
call PIC_PLT(_C_LABEL(sigblock))
#else
call _C_LABEL(sigblock)
#endif
addl $4,%esp
PIC_EPILOGUE
movl 4(%esp),%ecx
movl %eax,24(%ecx)
1: movl 0(%esp),%edx
movl %edx, 0(%ecx)
movl %ebx, 4(%ecx)
movl %esp, 8(%ecx)
movl %ebp,12(%ecx)
movl %esi,16(%ecx)
movl %edi,20(%ecx)
xorl %eax,%eax
ret
ENTRY(siglongjmp)
movl 4(%esp),%edx
cmpl $0,28(%edx)
jz 1f
PIC_PROLOGUE
pushl 24(%edx)
#ifdef PIC
call PIC_PLT(_C_LABEL(sigsetmask))
#else
call _C_LABEL(sigsetmask)
#endif
addl $4,%esp
PIC_EPILOGUE
1: movl 4(%esp),%edx
movl 8(%esp),%eax
movl 0(%edx),%ecx
movl 4(%edx),%ebx
movl 8(%edx),%esp
movl 12(%edx),%ebp
movl 16(%edx),%esi
movl 20(%edx),%edi
testl %eax,%eax
jnz 2f
incl %eax
2: movl %ecx,0(%esp)
ret

View File

@ -31,14 +31,14 @@
#if defined(_KERNEL) && !defined(I386_CPU)
#define __swap32md(x) ({ \
u_int32_t __swap32md_x = (x); \
uint32_t __swap32md_x = (x); \
\
__asm ("bswap %1" : "+r" (__swap32md_x)); \
__swap32md_x; \
})
#else
#define __swap32md(x) ({ \
u_int32_t __swap32md_x = (x); \
uint32_t __swap32md_x = (x); \
\
__asm ("rorw $8, %w1; rorl $16, %1; rorw $8, %w1" : \
"+r" (__swap32md_x)); \
@ -47,13 +47,13 @@
#endif /* _KERNEL && !I386_CPU */
#define __swap64md(x) ({ \
u_int64_t __swap64md_x = (x); \
uint64_t __swap64md_x = (x); \
\
(u_int64_t)__swap32md(__swap64md_x >> 32) | \
(u_int64_t)__swap32md(__swap64md_x & 0xffffffff) << 32; \
(uint64_t)__swap32md(__swap64md_x >> 32) | \
(uint64_t)__swap32md(__swap64md_x & 0xffffffff) << 32; \
})
#define __swap16md(x) ({ \
u_int16_t __swap16md_x = (x); \
uint16_t __swap16md_x = (x); \
\
__asm ("rorw $8, %w1" : "+r" (__swap16md_x)); \
__swap16md_x; \

View File

@ -36,8 +36,8 @@
#define _I386__TYPES_H_
/* the kernel defines size_t as unsigned int, but g++ wants it to be unsigned long */
#ifndef _SIZE_T
# define _SIZE_T
#ifndef _SIZE_T_DEFINED_
# define _SIZE_T_DEFINED_
# ifdef ANDROID
typedef unsigned int size_t;
# else
@ -54,9 +54,6 @@ typedef long int ssize_t;
typedef long ptrdiff_t;
#endif
#define _OFF_T_DEFINED_
#define _SIZE_T_DEFINED_
#include <linux/types.h>
/* 7.18.1.1 Exact-width integer types */

View File

@ -1858,7 +1858,13 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
*/
int ret, old_errno = errno;
ret = __rt_sigprocmask(how, set, oset, _NSIG / 8);
/* Use NSIG which corresponds to the number of signals in
* our 32-bit sigset_t implementation. As such, this function, or
* anything that deals with sigset_t cannot manage real-time signals
* (signo >= 32). We might want to introduce sigset_rt_t as an
* extension to do so in the future.
*/
ret = __rt_sigprocmask(how, set, oset, NSIG / 8);
if (ret < 0)
ret = errno;

View File

@ -16,6 +16,9 @@ Differences between current and Android 2.3:
- <unistd.h>: Add ftruncate64().
- <signal.h>: Changed the definition of SIGRTMAX to 64. However, note that
sigset_t is only 32-bit and cannot deal with real-time signals.
-------------------------------------------------------------------------------
Differences between Android 2.3 and Android 2.2:

View File

@ -60,6 +60,10 @@
#define IN6_IS_ADDR_SITELOCAL(a) \
(((a)->s6_addr[0] == 0xfe) && (((a)->s6_addr[1] & 0xc0) == 0xc0))
/* RFC 4193. */
#define IN6_IS_ADDR_ULA(a) \
(((a)->s6_addr[0] & 0xfe) == 0xfc)
#define IN6_IS_ADDR_MULTICAST(a) \
(((__const uint8_t *) (a))[0] == 0xff)

View File

@ -42,12 +42,15 @@ __BEGIN_DECLS
typedef int sig_atomic_t;
/* crepy NIG / _NSIG handling, just to be safe */
#ifndef NSIG
# define NSIG _NSIG
#endif
/* _NSIG is used by the SIGRTMAX definition under <asm/signal.h>, however
* its definition is part of a #if __KERNEL__ .. #endif block in the original
* kernel headers and is thus not part of our cleaned-up versions.
*
* Looking at the current kernel sources, it is defined as 64 for all
* architectures except for the 'mips' one which set it to 128.
*/
#ifndef _NSIG
# define _NSIG NSIG
# define _NSIG 64
#endif
extern const char * const sys_siglist[];

View File

@ -22,7 +22,7 @@ static inline __attribute_const__ __u32 ___arch__swab32(__u32 x)
#ifndef __thumb__
if (!__builtin_constant_p(x)) {
asm ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x));
__asm__ ("eor\t%0, %1, %1, ror #16" : "=r" (t) : "r" (x));
} else
#endif
t = x ^ ((x << 16) | (x >> 16));

View File

@ -71,6 +71,7 @@ def cleanupFile( path ):
list.removeEmptyLines()
list.removeMacroDefines( kernel_ignored_macros )
list.insertDisclaimer( kernel.kernel_disclaimer )
list.replaceTokens( kernel_token_replacements )
out = StringOutput()
list.write(out)

View File

@ -1863,6 +1863,16 @@ class BlockList:
tokens = tokens[:-1] # remove trailing tokLN
self.blocks = [ Block(tokens) ] + self.blocks
def replaceTokens(self,replacements=dict()):
"""replace tokens according to the given dict
"""
for b in self.blocks:
if not b.isDirective():
for tok in b.tokens:
if tok.id == tokIDENT:
if tok.value in replacements:
tok.value = replacements[tok.value]
class BlockParser:
"""a class used to convert an input source file into a BlockList object"""

View File

@ -43,6 +43,11 @@ kernel_default_arch_macros = {
"x86": {"__i386__": "1"},
}
# Replace tokens in the output according to this mapping
kernel_token_replacements = {
{"asm": "__asm__"},
}
# this is the set of known static inline functions that we want to keep
# in the final ARM headers. this is only used to keep optimized byteswapping
# static functions and stuff like that.

View File

@ -1497,11 +1497,13 @@ _get_scope(const struct sockaddr *addr)
if (IN_LOOPBACK(na) || /* 127.0.0.0/8 */
(na & 0xffff0000) == 0xa9fe0000) { /* 169.254.0.0/16 */
return IPV6_ADDR_SCOPE_LINKLOCAL;
} else if ((na & 0xff000000) == 0x0a000000 || /* 10.0.0.0/8 */
(na & 0xfff00000) == 0xac100000 || /* 172.16.0.0/12 */
(na & 0xffff0000) == 0xc0a80000) { /* 192.168.0.0/16 */
return IPV6_ADDR_SCOPE_SITELOCAL;
} else {
/*
* According to draft-ietf-6man-rfc3484-revise-01 section 2.3,
* it is best not to treat the private IPv4 ranges
* (10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16) as being
* in a special scope, so we don't.
*/
return IPV6_ADDR_SCOPE_GLOBAL;
}
} else {

View File

@ -1,316 +0,0 @@
/*
SHA-1 in C
By Steve Reid <sreid@sea-to-sky.net>
100% Public Domain
-----------------
Modified 7/98
By James H. Brown <jbrown@burgoyne.com>
Still 100% Public Domain
Corrected a problem which generated improper hash values on 16 bit machines
Routine SHA1Update changed from
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
len)
to
void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
long len)
The 'len' parameter was declared an int which works fine on 32 bit machines.
However, on 16 bit machines an int is too small for the shifts being done
against
it. This caused the hash function to generate incorrect values if len was
greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
Since the file IO in main() reads 16K at a time, any file 8K or larger would
be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
"a"s).
I also changed the declaration of variables i & j in SHA1Update to
unsigned long from unsigned int for the same reason.
These changes should make no difference to any 32 bit implementations since
an
int and a long are the same size in those environments.
--
I also corrected a few compiler warnings generated by Borland C.
1. Added #include <process.h> for exit() prototype
2. Removed unused variable 'j' in SHA1Final
3. Changed exit(0) to return(0) at end of main.
ALL changes I made can be located by searching for comments containing 'JHB'
-----------------
Modified 8/98
By Steve Reid <sreid@sea-to-sky.net>
Still 100% public domain
1- Removed #include <process.h> and used return() instead of exit()
2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
-----------------
Modified 4/01
By Saul Kravitz <Saul.Kravitz@celera.com>
Still 100% PD
Modified to run on Compaq Alpha hardware.
-----------------
Modified 2/03
By H. Peter Anvin <hpa@zytor.com>
Still 100% PD
Modified to run on any hardware with <inttypes.h> and <netinet/in.h>
Changed the driver program
*/
/*
Test Vectors (from FIPS PUB 180-1)
"abc"
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
A million repetitions of "a"
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
*/
/* #define SHA1HANDSOFF */
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */
/* #include <process.h> */ /* prototype for exit() - JHB */
/* Using return() instead of exit() - SWR */
typedef struct {
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
void SHA1Transform(uint32_t state[5], unsigned char buffer[64]);
void SHA1Init(SHA1_CTX* context);
void SHA1Update(SHA1_CTX* context, unsigned char* data, uint32_t len); /*
JHB */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
/* blk0() and blk() perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#define blk0(i) (block->l[i] = ntohl(block->l[i]))
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
^block->l[(i+2)&15]^block->l[i&15],1))
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
#ifdef VERBOSE /* SAK */
void SHAPrintContext(SHA1_CTX *context, char *msg){
printf("%s (%d,%d) %x %x %x %x %x\n",
msg,
context->count[0], context->count[1],
context->state[0],
context->state[1],
context->state[2],
context->state[3],
context->state[4]);
}
#endif
/* Hash a single 512-bit block. This is the core of the algorithm. */
void SHA1Transform(uint32_t state[5], unsigned char buffer[64])
{
uint32_t a, b, c, d, e;
typedef union {
unsigned char c[64];
uint32_t l[16];
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static unsigned char workspace[64];
block = (CHAR64LONG16*)workspace;
memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16*)buffer;
#endif
/* Copy context->state[] to working vars */
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
/* 4 rounds of 20 operations each. Loop unrolled. */
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
/* Add the working vars back into context.state[] */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
/* Wipe variables */
a = b = c = d = e = 0;
}
/* SHA1Init - Initialize new context */
void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
context->state[1] = 0xEFCDAB89;
context->state[2] = 0x98BADCFE;
context->state[3] = 0x10325476;
context->state[4] = 0xC3D2E1F0;
context->count[0] = context->count[1] = 0;
}
/* Run your data through this. */
void SHA1Update(SHA1_CTX* context, unsigned char* data, uint32_t len) /*
JHB */
{
uint32_t i, j; /* JHB */
#ifdef VERBOSE
SHAPrintContext(context, "before");
#endif
j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29);
if ((j + len) > 63) {
memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
}
j = 0;
}
else i = 0;
memcpy(&context->buffer[j], &data[i], len - i);
#ifdef VERBOSE
SHAPrintContext(context, "after ");
#endif
}
/* Add padding and return the message digest. */
void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
uint32_t i; /* JHB */
unsigned char finalcount[8];
for (i = 0; i < 8; i++) {
finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
>> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
}
SHA1Update(context, (unsigned char *)"\200", 1);
while ((context->count[0] & 504) != 448) {
SHA1Update(context, (unsigned char *)"\0", 1);
}
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
for (i = 0; i < 20; i++) {
digest[i] = (unsigned char)
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
}
/* Wipe variables */
i = 0; /* JHB */
memset(context->buffer, 0, 64);
memset(context->state, 0, 20);
memset(context->count, 0, 8);
memset(finalcount, 0, 8); /* SWR */
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
SHA1Transform(context->state, context->buffer);
#endif
}
/*************************************************************/
/* This is not quite the MIME base64 algorithm: it uses _ instead of /,
and instead of padding the output with = characters we just make the
output shorter. */
char *mybase64(uint8_t digest[20])
{
static const char charz[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
uint8_t input[21];
static char output[28];
int i, j;
uint8_t *p;
char *q;
uint32_t bv;
memcpy(input, digest, 20);
input[20] = 0; /* Pad to multiple of 3 bytes */
p = input; q = output;
for ( i = 0 ; i < 7 ; i++ ) {
bv = (p[0] << 16) | (p[1] << 8) | p[2];
p += 3;
for ( j = 0 ; j < 4 ; j++ ) {
*q++ = charz[(bv >> 18) & 0x3f];
bv <<= 6;
}
}
*--q = '\0'; /* The last character is not significant */
return output;
}
int main(int argc, char** argv)
{
int i;
SHA1_CTX context;
uint8_t digest[20], buffer[16384];
FILE* file;
if (argc < 2) {
file = stdin;
}
else {
if (!(file = fopen(argv[1], "rb"))) {
fputs("Unable to open file.", stderr);
return(-1);
}
}
SHA1Init(&context);
while (!feof(file)) { /* note: what if ferror(file) */
i = fread(buffer, 1, 16384, file);
SHA1Update(&context, buffer, i);
}
SHA1Final(digest, &context);
fclose(file);
puts(mybase64(digest));
return 0;
}

View File

@ -30,5 +30,5 @@
int raise(int signum)
{
return kill(getpid(), signum);
return kill(gettid(), signum);
}

View File

@ -131,7 +131,8 @@ feclearexcept(int __excepts)
static __inline int
fegetexceptflag(fexcept_t *__flagp, int __excepts)
{
int __mxcsr, __status;
int __mxcsr;
short __status;
__fnstsw(&__status);
if (__HAS_SSE())

View File

@ -4,6 +4,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
arch/$(TARGET_ARCH)/begin.S \
linker.c \
linker_environ.c \
linker_format.c \
rt.c \
dlfcn.c \

View File

@ -48,6 +48,7 @@
#include "linker.h"
#include "linker_debug.h"
#include "linker_environ.h"
#include "linker_format.h"
#include "ba.h"
@ -123,6 +124,9 @@ static soinfo *preloads[LDPRELOAD_MAX + 1];
int debug_verbosity;
static int pid;
/* This boolean is set if the program being loaded is setuid */
static int program_is_setuid;
#if STATS
struct _link_stats linker_stats;
#endif
@ -286,7 +290,7 @@ static soinfo *alloc_info(const char *name)
/* Make sure we get a clean block of soinfo */
memset(si, 0, sizeof(soinfo));
strcpy((char*) si->name, name);
strlcpy((char*) si->name, name, sizeof(si->name));
sonext->next = si;
si->ba_index = -1; /* by default, prelinked */
si->next = NULL;
@ -2033,7 +2037,7 @@ static int link_image(soinfo *si, unsigned wr_offset)
ftp://ftp.freebsd.org/pub/FreeBSD/CERT/advisories/FreeBSD-SA-02:23.stdio.asc
*/
if (getuid() != geteuid() || getgid() != getegid())
if (program_is_setuid)
nullify_closed_stdio ();
call_constructors(si);
notify_gdb_of_load(si);
@ -2045,7 +2049,7 @@ fail:
return -1;
}
static void parse_library_path(char *path, char *delim)
static void parse_library_path(const char *path, char *delim)
{
size_t len;
char *ldpaths_bufp = ldpaths_buf;
@ -2068,7 +2072,7 @@ static void parse_library_path(char *path, char *delim)
}
}
static void parse_preloads(char *path, char *delim)
static void parse_preloads(const char *path, char *delim)
{
size_t len;
char *ldpreloads_bufp = ldpreloads_buf;
@ -2110,8 +2114,8 @@ unsigned __linker_init(unsigned **elfdata)
unsigned *vecs = (unsigned*) (argv + argc + 1);
soinfo *si;
struct link_map * map;
char *ldpath_env = NULL;
char *ldpreload_env = NULL;
const char *ldpath_env = NULL;
const char *ldpreload_env = NULL;
/* Setup a temporary TLS area that is used to get a working
* errno for system calls.
@ -2135,20 +2139,32 @@ unsigned __linker_init(unsigned **elfdata)
*/
__tls_area[TLS_SLOT_BIONIC_PREINIT] = elfdata;
/* Are we setuid? */
program_is_setuid = (getuid() != geteuid()) || (getgid() != getegid());
/* Initialize environment functions, and get to the ELF aux vectors table */
vecs = linker_env_init(vecs);
/* Sanitize environment if we're loading a setuid program */
if (program_is_setuid)
linker_env_secure();
debugger_init();
/* skip past the environment */
while(vecs[0] != 0) {
if(!strncmp((char*) vecs[0], "DEBUG=", 6)) {
debug_verbosity = atoi(((char*) vecs[0]) + 6);
} else if(!strncmp((char*) vecs[0], "LD_LIBRARY_PATH=", 16)) {
ldpath_env = (char*) vecs[0] + 16;
} else if(!strncmp((char*) vecs[0], "LD_PRELOAD=", 11)) {
ldpreload_env = (char*) vecs[0] + 11;
/* Get a few environment variables */
{
const char* env;
env = linker_env_get("DEBUG"); /* XXX: TODO: Change to LD_DEBUG */
if (env)
debug_verbosity = atoi(env);
/* Normally, these are cleaned by linker_env_secure, but the test
* against program_is_setuid doesn't cost us anything */
if (!program_is_setuid) {
ldpath_env = linker_env_get("LD_LIBRARY_PATH");
ldpreload_env = linker_env_get("LD_PRELOAD");
}
vecs++;
}
vecs++;
INFO("[ android linker & debugger ]\n");
DEBUG("%5d elfdata @ 0x%08x\n", pid, (unsigned)elfdata);
@ -2176,7 +2192,7 @@ unsigned __linker_init(unsigned **elfdata)
* is. Don't use alloc_info(), because the linker shouldn't
* be on the soinfo list.
*/
strcpy((char*) linker_soinfo.name, "/system/bin/linker");
strlcpy((char*) linker_soinfo.name, "/system/bin/linker", sizeof linker_soinfo.name);
linker_soinfo.flags = 0;
linker_soinfo.base = 0; // This is the important part; must be zero.
insert_soinfo_into_debug_map(&linker_soinfo);
@ -2206,10 +2222,10 @@ unsigned __linker_init(unsigned **elfdata)
si->refcount = 1;
/* Use LD_LIBRARY_PATH if we aren't setuid/setgid */
if (ldpath_env && getuid() == geteuid() && getgid() == getegid())
if (ldpath_env)
parse_library_path(ldpath_env, ":");
if (ldpreload_env && getuid() == geteuid() && getgid() == getegid()) {
if (ldpreload_env) {
parse_preloads(ldpreload_env, " :");
}

204
linker/linker_environ.c Normal file
View File

@ -0,0 +1,204 @@
/*
* Copyright (C) 2010 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 "linker_environ.h"
#include <stddef.h>
static char** _envp;
/* Returns 1 if 'str' points to a valid environment variable definition.
* For now, we check that:
* - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings)
* - It contains at least one equal sign that is not the first character
*/
static int
_is_valid_definition(const char* str)
{
int pos = 0;
int first_equal_pos = -1;
/* According to its sources, the kernel uses 32*PAGE_SIZE by default
* as the maximum size for an env. variable definition.
*/
const int MAX_ENV_LEN = 32*4096;
if (str == NULL)
return 0;
/* Parse the string, looking for the first '=' there, and its size */
do {
if (str[pos] == '\0')
break;
if (str[pos] == '=' && first_equal_pos < 0)
first_equal_pos = pos;
pos++;
} while (pos < MAX_ENV_LEN);
if (pos >= MAX_ENV_LEN) /* Too large */
return 0;
if (first_equal_pos < 1) /* No equal sign, or it is the first character */
return 0;
return 1;
}
unsigned*
linker_env_init(unsigned* vecs)
{
/* Store environment pointer - can't be NULL */
_envp = (char**) vecs;
/* Skip over all definitions */
while (vecs[0] != 0)
vecs++;
/* The end of the environment block is marked by two NULL pointers */
vecs++;
/* As a sanity check, we're going to remove all invalid variable
* definitions from the environment array.
*/
{
char** readp = _envp;
char** writep = _envp;
for ( ; readp[0] != NULL; readp++ ) {
if (!_is_valid_definition(readp[0]))
continue;
writep[0] = readp[0];
writep++;
}
writep[0] = NULL;
}
/* Return the address of the aux vectors table */
return vecs;
}
/* Check if the environment variable definition at 'envstr'
* starts with '<name>=', and if so return the address of the
* first character after the equal sign. Otherwise return NULL.
*/
static char*
env_match(char* envstr, const char* name)
{
size_t cnt = 0;
while (envstr[cnt] == name[cnt] && name[cnt] != '\0')
cnt++;
if (name[cnt] == '\0' && envstr[cnt] == '=')
return envstr + cnt + 1;
return NULL;
}
#define MAX_ENV_LEN (16*4096)
const char*
linker_env_get(const char* name)
{
char** readp = _envp;
if (name == NULL || name[0] == '\0')
return NULL;
for ( ; readp[0] != NULL; readp++ ) {
char* val = env_match(readp[0], name);
if (val != NULL) {
/* Return NULL for empty strings, or if it is too large */
if (val[0] == '\0')
val = NULL;
return val;
}
}
return NULL;
}
void
linker_env_unset(const char* name)
{
char** readp = _envp;
char** writep = readp;
if (name == NULL || name[0] == '\0')
return;
for ( ; readp[0] != NULL; readp++ ) {
if (env_match(readp[0], name))
continue;
writep[0] = readp[0];
writep++;
}
/* end list with a NULL */
writep[0] = NULL;
}
/* Remove unsafe environment variables. This should be used when
* running setuid programs. */
void
linker_env_secure(void)
{
/* The same list than GLibc at this point */
static const char* const unsec_vars[] = {
"GCONV_PATH",
"GETCONF_DIR",
"HOSTALIASES",
"LD_AUDIT",
"LD_DEBUG",
"LD_DEBUG_OUTPUT",
"LD_DYNAMIC_WEAK",
"LD_LIBRARY_PATH",
"LD_ORIGIN_PATH",
"LD_PRELOAD",
"LD_PROFILE",
"LD_SHOW_AUXV",
"LD_USE_LOAD_BIAS",
"LOCALDOMAIN",
"LOCPATH",
"MALLOC_TRACE",
"MALLOC_CHECK_",
"NIS_PATH",
"NLSPATH",
"RESOLV_HOST_CONF",
"RES_OPTIONS",
"TMPDIR",
"TZDIR",
"LD_AOUT_LIBRARY_PATH",
"LD_AOUT_PRELOAD",
};
const char* const* cp = unsec_vars;
const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
while (cp < endp) {
linker_env_unset(*cp);
cp++;
}
}

54
linker/linker_environ.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2010 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 LINKER_ENVIRON_H
#define LINKER_ENVIRON_H
/* Call this function before anything else. 'vecs' must be the pointer
* to the environment block in the ELF data block. The function returns
* the start of the aux vectors after the env block.
*/
extern unsigned* linker_env_init(unsigned* vecs);
/* Unset a given environment variable. In case the variable is defined
* multiple times, unset all instances. This modifies the environment
* block, so any pointer returned by linker_env_get() after this call
* might become invalid */
extern void linker_env_unset(const char* name);
/* Returns the value of environment variable 'name' if defined and not
* empty, or NULL otherwise. Note that the returned pointer may become
* invalid if linker_env_unset() or linker_env_secure() are called
* after this function. */
extern const char* linker_env_get(const char* name);
/* Remove unsecure environment variables. This should be used when
* running setuid programs. */
extern void linker_env_secure(void);
#endif /* LINKER_ENVIRON_H */