Merge "Don't treat private IPv4 addresses as being in a non-global scope. The effect of this change is essentially to prefer NATed IPv4 over 6to4."
diff --git a/libc/Android.mk b/libc/Android.mk
index 6361ad9..d940753 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -398,6 +398,7 @@
 	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 \
diff --git a/libc/arch-x86/bionic/sigsetjmp.S b/libc/arch-x86/bionic/sigsetjmp.S
new file mode 100644
index 0000000..c990a05
--- /dev/null
+++ b/libc/arch-x86/bionic/sigsetjmp.S
@@ -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
diff --git a/libc/kernel/arch-arm/asm/byteorder.h b/libc/kernel/arch-arm/asm/byteorder.h
index 4da37bf..b869695 100644
--- a/libc/kernel/arch-arm/asm/byteorder.h
+++ b/libc/kernel/arch-arm/asm/byteorder.h
@@ -22,7 +22,7 @@
 #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));
diff --git a/libc/kernel/tools/clean_header.py b/libc/kernel/tools/clean_header.py
index 28cb05e..dad9120 100755
--- a/libc/kernel/tools/clean_header.py
+++ b/libc/kernel/tools/clean_header.py
@@ -71,6 +71,7 @@
     list.removeEmptyLines()
     list.removeMacroDefines( kernel_ignored_macros )
     list.insertDisclaimer( kernel.kernel_disclaimer )
+    list.replaceTokens( kernel_token_replacements )
 
     out = StringOutput()
     list.write(out)
diff --git a/libc/kernel/tools/cpp.py b/libc/kernel/tools/cpp.py
index 4b4bd38..8828a5d 100644
--- a/libc/kernel/tools/cpp.py
+++ b/libc/kernel/tools/cpp.py
@@ -1863,6 +1863,16 @@
         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"""
 
diff --git a/libc/kernel/tools/defaults.py b/libc/kernel/tools/defaults.py
index b35f72b..ca7e6bb 100644
--- a/libc/kernel/tools/defaults.py
+++ b/libc/kernel/tools/defaults.py
@@ -43,6 +43,11 @@
     "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.
diff --git a/libc/stdlib/sha1hash.c b/libc/stdlib/sha1hash.c
deleted file mode 100644
index 1c7aaf3..0000000
--- a/libc/stdlib/sha1hash.c
+++ /dev/null
@@ -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;
-}
diff --git a/libm/include/i387/fenv.h b/libm/include/i387/fenv.h
index 4281f10..5fe64e2 100644
--- a/libm/include/i387/fenv.h
+++ b/libm/include/i387/fenv.h
@@ -131,7 +131,8 @@
 static __inline int
 fegetexceptflag(fexcept_t *__flagp, int __excepts)
 {
-	int __mxcsr, __status;
+	int __mxcsr;
+	short __status;
 
 	__fnstsw(&__status);
 	if (__HAS_SSE())
diff --git a/linker/Android.mk b/linker/Android.mk
index 27a6677..da311cd 100644
--- a/linker/Android.mk
+++ b/linker/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_SRC_FILES:= \
 	arch/$(TARGET_ARCH)/begin.S \
 	linker.c \
+	linker_environ.c \
 	linker_format.c \
 	rt.c \
 	dlfcn.c \
@@ -93,6 +94,6 @@
 # just for this module
 $(LOCAL_BUILT_MODULE): TARGET_CRTBEGIN_STATIC_O :=
 # This line is not strictly necessary because the dynamic linker is built
-# as a static executable, but it won't hurt if in the future we start 
+# as a static executable, but it won't hurt if in the future we start
 # building the linker as a dynamic one.
 $(LOCAL_BUILT_MODULE): TARGET_CRTBEGIN_DYNAMIC_O :=
diff --git a/linker/linker.c b/linker/linker.c
index 42a5205..c4f54f7 100644
--- a/linker/linker.c
+++ b/linker/linker.c
@@ -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 @@
 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 @@
 
     /* 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;
@@ -314,7 +318,7 @@
         return;
     }
 
-    /* prev will never be NULL, because the first entry in solist is 
+    /* prev will never be NULL, because the first entry in solist is
        always the static libdl_info.
     */
     prev->next = si->next;
@@ -1232,8 +1236,8 @@
     return init_library(si);
 }
 
-/* TODO: 
- *   notify gdb of unload 
+/* TODO:
+ *   notify gdb of unload
  *   for non-prelinked libraries, find a way to decrement libbase
  */
 static void call_destructors(soinfo *si);
@@ -1765,14 +1769,14 @@
             }
 #endif
             if (phdr->p_type == PT_LOAD) {
-                /* For the executable, we use the si->size field only in 
-                   dl_unwind_find_exidx(), so the meaning of si->size 
-                   is not the size of the executable; it is the last 
+                /* For the executable, we use the si->size field only in
+                   dl_unwind_find_exidx(), so the meaning of si->size
+                   is not the size of the executable; it is the last
                    virtual address of the loadable part of the executable;
                    since si->base == 0 for an executable, we use the
-                   range [0, si->size) to determine whether a PC value 
+                   range [0, si->size) to determine whether a PC value
                    falls within the executable section.  Of course, if
-                   a value is below phdr->p_vaddr, it's not in the 
+                   a value is below phdr->p_vaddr, it's not in the
                    executable section, but a) we shouldn't be asking for
                    such a value anyway, and b) if we have to provide
                    an EXIDX for such a value, then the executable's
@@ -1927,7 +1931,7 @@
         }
     }
 
-    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n", 
+    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n",
            pid, si->base, si->strtab, si->symtab);
 
     if((si->strtab == 0) || (si->symtab == 0)) {
@@ -2033,7 +2037,7 @@
     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 @@
     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_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 *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 @@
      */
     __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 @@
          * 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 @@
     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, " :");
     }
 
diff --git a/linker/linker_environ.c b/linker/linker_environ.c
new file mode 100644
index 0000000..6c5b571
--- /dev/null
+++ b/linker/linker_environ.c
@@ -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++;
+    }
+}
diff --git a/linker/linker_environ.h b/linker/linker_environ.h
new file mode 100644
index 0000000..98ad1de
--- /dev/null
+++ b/linker/linker_environ.h
@@ -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 */