Merge "Fixed uchar.h for clang3.6"
diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp
index 9b23ece..bd71628 100644
--- a/libc/bionic/libc_init_common.cpp
+++ b/libc/bionic/libc_init_common.cpp
@@ -37,6 +37,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/auxv.h>
+#include <sys/personality.h>
 #include <sys/time.h>
 #include <unistd.h>
 
@@ -44,6 +45,7 @@
 #include "private/bionic_ssp.h"
 #include "private/bionic_tls.h"
 #include "private/KernelArgumentBlock.h"
+#include "private/libc_logging.h"
 #include "pthread_internal.h"
 
 extern "C" abort_msg_t** __abort_message_ptr;
@@ -289,6 +291,19 @@
   dst[0] = nullptr;
 }
 
+static void __initialize_personality() {
+#if !defined(__LP64__)
+  int old_value = personality(0xffffffff);
+  if (old_value == -1) {
+    __libc_fatal("error getting old personality value: %s", strerror(errno));
+  }
+
+  if (personality((static_cast<unsigned int>(old_value) & ~PER_MASK) | PER_LINUX32) == -1) {
+    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
+  }
+#endif
+}
+
 void __libc_init_AT_SECURE(KernelArgumentBlock& args) {
   __libc_auxv = args.auxv;
 
@@ -312,6 +327,8 @@
 
   // Now the environment has been sanitized, make it available.
   environ = args.envp;
+
+  __initialize_personality();
 }
 
 /* This function will be called during normal program termination
diff --git a/libc/dns/include/resolv_netid.h b/libc/dns/include/resolv_netid.h
index 1d0f869..d364645 100644
--- a/libc/dns/include/resolv_netid.h
+++ b/libc/dns/include/resolv_netid.h
@@ -53,10 +53,37 @@
 
 #define __used_in_netd __attribute__((visibility ("default")))
 
+/*
+ * A struct to capture context relevant to network operations.
+ *
+ * Application and DNS netids/marks can differ from one another under certain
+ * circumstances, notably when a VPN applies to the given uid's traffic but the
+ * VPN network does not have its own DNS servers explicitly provisioned.
+ *
+ * The introduction of per-UID routing means the uid is also an essential part
+ * of the evaluation context. Its proper uninitialized value is
+ * NET_CONTEXT_INVALID_UID.
+ */
+struct android_net_context {
+    unsigned app_netid;
+    unsigned app_mark;
+    unsigned dns_netid;
+    unsigned dns_mark;
+    uid_t uid;
+} __attribute__((packed));
+
+#define NET_CONTEXT_INVALID_UID ((uid_t)-1)
+
 struct hostent *android_gethostbyaddrfornet(const void *, socklen_t, int, unsigned, unsigned) __used_in_netd;
 struct hostent *android_gethostbynamefornet(const char *, int, unsigned, unsigned) __used_in_netd;
 int android_getaddrinfofornet(const char *, const char *, const struct addrinfo *, unsigned,
-		unsigned, struct addrinfo **) __used_in_netd;
+    unsigned, struct addrinfo **) __used_in_netd;
+/*
+ * TODO: consider refactoring android_getaddrinfo_proxy() to serve as an
+ * explore_fqdn() dispatch table method, with the below function only making DNS calls.
+ */
+int android_getaddrinfofornetcontext(const char *, const char *, const struct addrinfo *,
+    const struct android_net_context *, struct addrinfo **) __used_in_netd;
 
 /* set name servers for a network */
 extern void _resolv_set_nameservers_for_net(unsigned netid,
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index c73c085..829b679 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -218,7 +218,7 @@
 
 static int str2number(const char *);
 static int explore_fqdn(const struct addrinfo *, const char *,
-	const char *, struct addrinfo **, unsigned netid, unsigned mark);
+	const char *, struct addrinfo **, const struct android_net_context *);
 static int explore_null(const struct addrinfo *,
 	const char *, struct addrinfo **);
 static int explore_numeric(const struct addrinfo *, const char *,
@@ -244,6 +244,7 @@
 static struct addrinfo *_gethtent(FILE **, const char *,
     const struct addrinfo *);
 static int _files_getaddrinfo(void *, void *, va_list);
+static int _find_src_addr(const struct sockaddr *, struct sockaddr *, unsigned , uid_t);
 
 static int res_queryN(const char *, struct res_target *, res_state);
 static int res_searchN(const char *, struct res_target *, res_state);
@@ -360,29 +361,6 @@
 }
 
 /*
- * Connect a UDP socket to a given unicast address. This will cause no network
- * traffic, but will fail fast if the system has no or limited reachability to
- * the destination (e.g., no IPv4 address, no IPv6 default route, ...).
- */
-static int
-_test_connect(int pf, struct sockaddr *addr, size_t addrlen, unsigned mark) {
-	int s = socket(pf, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
-	if (s < 0)
-		return 0;
-	if (mark != MARK_UNSET && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
-		return 0;
-	int ret;
-	do {
-		ret = __connect(s, addr, addrlen);
-	} while (ret < 0 && errno == EINTR);
-	int success = (ret == 0);
-	do {
-		ret = close(s);
-	} while (ret < 0 && errno == EINTR);
-	return success;
-}
-
-/*
  * The following functions determine whether IPv4 or IPv6 connectivity is
  * available in order to implement AI_ADDRCONFIG.
  *
@@ -392,24 +370,24 @@
  * so checking for connectivity is the next best thing.
  */
 static int
-_have_ipv6(unsigned mark) {
+_have_ipv6(unsigned mark, uid_t uid) {
 	static const struct sockaddr_in6 sin6_test = {
 		.sin6_family = AF_INET6,
 		.sin6_addr.s6_addr = {  // 2000::
 			0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 		};
 	sockaddr_union addr = { .in6 = sin6_test };
-	return _test_connect(PF_INET6, &addr.generic, sizeof(addr.in6), mark);
+	return _find_src_addr(&addr.generic, NULL, mark, uid) == 1;
 }
 
 static int
-_have_ipv4(unsigned mark) {
+_have_ipv4(unsigned mark, uid_t uid) {
 	static const struct sockaddr_in sin_test = {
 		.sin_family = AF_INET,
 		.sin_addr.s_addr = __constant_htonl(0x08080808L)  // 8.8.8.8
 	};
 	sockaddr_union addr = { .in = sin_test };
-	return _test_connect(PF_INET, &addr.generic, sizeof(addr.in), mark);
+	return _find_src_addr(&addr.generic, NULL, mark, uid) == 1;
 }
 
 bool readBE32(FILE* fp, int32_t* result) {
@@ -474,7 +452,7 @@
 
 	int result_code = (int)strtol(buf, NULL, 10);
 	// verify the code itself
-	if (result_code != DnsProxyQueryResult ) {
+	if (result_code != DnsProxyQueryResult) {
 		fread(buf, 1, sizeof(buf), proxy);
 		goto exit;
 	}
@@ -589,6 +567,21 @@
 android_getaddrinfofornet(const char *hostname, const char *servname,
     const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
 {
+	struct android_net_context netcontext = {
+		.app_netid = netid,
+		.app_mark = mark,
+		.dns_netid = netid,
+		.dns_mark = mark,
+		.uid = NET_CONTEXT_INVALID_UID,
+        };
+	return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
+}
+
+int
+android_getaddrinfofornetcontext(const char *hostname, const char *servname,
+    const struct addrinfo *hints, const struct android_net_context *netcontext,
+    struct addrinfo **res)
+{
 	struct addrinfo sentinel;
 	struct addrinfo *cur;
 	int error = 0;
@@ -601,6 +594,7 @@
 	/* servname is allowed to be NULL */
 	/* hints is allowed to be NULL */
 	assert(res != NULL);
+	assert(netcontext != NULL);
 	memset(&sentinel, 0, sizeof(sentinel));
 	cur = &sentinel;
 	pai = &ai;
@@ -731,7 +725,8 @@
 		ERR(EAI_NONAME);
 
 #if defined(__ANDROID__)
-	int gai_error = android_getaddrinfo_proxy(hostname, servname, hints, res, netid);
+	int gai_error = android_getaddrinfo_proxy(
+		hostname, servname, hints, res, netcontext->app_netid);
 	if (gai_error != EAI_SYSTEM) {
 		return gai_error;
 	}
@@ -763,8 +758,8 @@
 		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
 			pai->ai_protocol = ex->e_protocol;
 
-		error = explore_fqdn(pai, hostname, servname,
-			&cur->ai_next, netid, mark);
+		error = explore_fqdn(
+			pai, hostname, servname, &cur->ai_next, netcontext);
 
 		while (cur && cur->ai_next)
 			cur = cur->ai_next;
@@ -797,7 +792,8 @@
  */
 static int
 explore_fqdn(const struct addrinfo *pai, const char *hostname,
-    const char *servname, struct addrinfo **res, unsigned netid, unsigned mark)
+    const char *servname, struct addrinfo **res,
+    const struct android_net_context *netcontext)
 {
 	struct addrinfo *result;
 	struct addrinfo *cur;
@@ -823,7 +819,7 @@
 		return 0;
 
 	switch (nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
-			default_dns_files, hostname, pai, netid, mark)) {
+			default_dns_files, hostname, pai, netcontext)) {
 	case NS_TRYAGAIN:
 		error = EAI_AGAIN;
 		goto free;
@@ -1763,13 +1759,13 @@
  * address. src_addr must be large enough to hold a struct sockaddr_in6.
  *
  * Returns 1 if a source address was found, 0 if the address is unreachable,
- * and -1 if a fatal error occurred. If 0 or 1, the contents of src_addr are
+ * and -1 if a fatal error occurred. If 0 or -1, the contents of src_addr are
  * undefined.
  */
 
 /*ARGSUSED*/
 static int
-_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned mark)
+_find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned mark, uid_t uid)
 {
 	int sock;
 	int ret;
@@ -1797,6 +1793,8 @@
 	}
 	if (mark != MARK_UNSET && setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0)
 		return 0;
+	if (uid > 0 && uid != NET_CONTEXT_INVALID_UID && fchown(sock, uid, (gid_t)-1) < 0)
+		return 0;
 	do {
 		ret = __connect(sock, addr, len);
 	} while (ret == -1 && errno == EINTR);
@@ -1806,7 +1804,7 @@
 		return 0;
 	}
 
-	if (getsockname(sock, src_addr, &len) == -1) {
+	if (src_addr && getsockname(sock, src_addr, &len) == -1) {
 		close(sock);
 		return -1;
 	}
@@ -1821,7 +1819,7 @@
 
 /*ARGSUSED*/
 static void
-_rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark)
+_rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark, uid_t uid)
 {
 	struct addrinfo *cur;
 	int nelem = 0, i;
@@ -1848,7 +1846,7 @@
 		elems[i].ai = cur;
 		elems[i].original_order = i;
 
-		has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic, mark);
+		has_src_addr = _find_src_addr(cur->ai_addr, &elems[i].src_addr.generic, mark, uid);
 		if (has_src_addr == -1) {
 			goto error;
 		}
@@ -1879,12 +1877,11 @@
 	struct addrinfo sentinel, *cur;
 	struct res_target q, q2;
 	res_state res;
-	unsigned netid, mark;
+	const struct android_net_context *netcontext;
 
 	name = va_arg(ap, char *);
 	pai = va_arg(ap, const struct addrinfo *);
-	netid = va_arg(ap, unsigned);
-	mark = va_arg(ap, unsigned);
+	netcontext = va_arg(ap, const struct android_net_context *);
 	//fprintf(stderr, "_dns_getaddrinfo() name = '%s'\n", name);
 
 	memset(&q, 0, sizeof(q));
@@ -1913,8 +1910,8 @@
 		q.anslen = sizeof(buf->buf);
 		int query_ipv6 = 1, query_ipv4 = 1;
 		if (pai->ai_flags & AI_ADDRCONFIG) {
-			query_ipv6 = _have_ipv6(mark);
-			query_ipv4 = _have_ipv4(mark);
+			query_ipv6 = _have_ipv6(netcontext->app_mark, netcontext->uid);
+			query_ipv4 = _have_ipv4(netcontext->app_mark, netcontext->uid);
 		}
 		if (query_ipv6) {
 			q.qtype = T_AAAA;
@@ -1966,8 +1963,8 @@
 	 * fully populate the thread private data here, but if we get down there
 	 * and have a cache hit that would be wasted, so we do the rest there on miss
 	 */
-	res_setnetid(res, netid);
-	res_setmark(res, mark);
+	res_setnetid(res, netcontext->dns_netid);
+	res_setmark(res, netcontext->dns_mark);
 	if (res_searchN(name, &q, res) < 0) {
 		__res_put_state(res);
 		free(buf);
@@ -1999,7 +1996,7 @@
 		}
 	}
 
-	_rfc6724_sort(&sentinel, netid);
+	_rfc6724_sort(&sentinel, netcontext->app_mark, netcontext->uid);
 
 	__res_put_state(res);
 
diff --git a/libc/include/sys/personality.h b/libc/include/sys/personality.h
index 8a023f9..7764468 100644
--- a/libc/include/sys/personality.h
+++ b/libc/include/sys/personality.h
@@ -34,7 +34,7 @@
 
 __BEGIN_DECLS
 
-extern int personality (unsigned long persona);
+extern int personality (unsigned int persona);
 
 __END_DECLS
 
diff --git a/libc/include/sys/procfs.h b/libc/include/sys/procfs.h
index b5b1a46..7ef5023 100644
--- a/libc/include/sys/procfs.h
+++ b/libc/include/sys/procfs.h
@@ -39,6 +39,10 @@
 
 typedef fpregset_t elf_fpregset_t;
 
+#if defined(__i386__)
+typedef struct user_fpxregs_struct elf_fpxregset_t;
+#endif
+
 typedef elf_gregset_t prgregset_t;
 typedef elf_fpregset_t prfpregset_t;
 
diff --git a/libc/include/sys/user.h b/libc/include/sys/user.h
index b370add..d63fe6a 100644
--- a/libc/include/sys/user.h
+++ b/libc/include/sys/user.h
@@ -47,7 +47,7 @@
   long fos;
   long st_space[20];
 };
-struct user_fxsr_struct {
+struct user_fpxregs_struct {
   unsigned short cwd;
   unsigned short swd;
   unsigned short twd;
diff --git a/libc/include/sysexits.h b/libc/include/sysexits.h
new file mode 100644
index 0000000..e244836
--- /dev/null
+++ b/libc/include/sysexits.h
@@ -0,0 +1,119 @@
+/*	$OpenBSD: sysexits.h,v 1.5 2003/06/02 19:34:12 millert Exp $	*/
+/*	$NetBSD: sysexits.h,v 1.4 1994/10/26 00:56:33 cgd Exp $	*/
+
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * 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.
+ *
+ *	@(#)sysexits.h	4.8 (Berkeley) 4/3/91
+ */
+
+#ifndef	_SYSEXITS_H_
+#define	_SYSEXITS_H_
+
+/*
+ *  SYSEXITS.H -- Exit status codes for system programs.
+ *
+ *	This include file attempts to categorize possible error
+ *	exit statuses for system programs, notably delivermail
+ *	and the Berkeley network.
+ *
+ *	Error numbers begin at EX__BASE to reduce the possibility of
+ *	clashing with other exit statuses that random programs may
+ *	already return.  The meaning of the codes is approximately
+ *	as follows:
+ *
+ *	EX_USAGE -- The command was used incorrectly, e.g., with
+ *		the wrong number of arguments, a bad flag, a bad
+ *		syntax in a parameter, or whatever.
+ *	EX_DATAERR -- The input data was incorrect in some way.
+ *		This should only be used for user's data & not
+ *		system files.
+ *	EX_NOINPUT -- An input file (not a system file) did not
+ *		exist or was not readable.  This could also include
+ *		errors like "No message" to a mailer (if it cared
+ *		to catch it).
+ *	EX_NOUSER -- The user specified did not exist.  This might
+ *		be used for mail addresses or remote logins.
+ *	EX_NOHOST -- The host specified did not exist.  This is used
+ *		in mail addresses or network requests.
+ *	EX_UNAVAILABLE -- A service is unavailable.  This can occur
+ *		if a support program or file does not exist.  This
+ *		can also be used as a catchall message when something
+ *		you wanted to do doesn't work, but you don't know
+ *		why.
+ *	EX_SOFTWARE -- An internal software error has been detected.
+ *		This should be limited to non-operating system related
+ *		errors as possible.
+ *	EX_OSERR -- An operating system error has been detected.
+ *		This is intended to be used for such things as "cannot
+ *		fork", "cannot create pipe", or the like.  It includes
+ *		things like getuid returning a user that does not
+ *		exist in the passwd file.
+ *	EX_OSFILE -- Some system file (e.g., /etc/passwd, /var/run/utmp,
+ *		etc.) does not exist, cannot be opened, or has some
+ *		sort of error (e.g., syntax error).
+ *	EX_CANTCREAT -- A (user specified) output file cannot be
+ *		created.
+ *	EX_IOERR -- An error occurred while doing I/O on some file.
+ *	EX_TEMPFAIL -- temporary failure, indicating something that
+ *		is not really an error.  In sendmail, this means
+ *		that a mailer (e.g.) could not create a connection,
+ *		and the request should be reattempted later.
+ *	EX_PROTOCOL -- the remote system returned something that
+ *		was "not possible" during a protocol exchange.
+ *	EX_NOPERM -- You did not have sufficient permission to
+ *		perform the operation.  This is not intended for
+ *		file system problems, which should use EX_NOINPUT or
+ *		EX_CANTCREAT, but rather for higher level permissions.
+ *	EX_CONFIG -- Something was found in an unconfigured or
+ *		misconfigured state.
+ */
+
+#define EX_OK		0	/* successful termination */
+
+#define EX__BASE	64	/* base value for error messages */
+
+#define EX_USAGE	64	/* command line usage error */
+#define EX_DATAERR	65	/* data format error */
+#define EX_NOINPUT	66	/* cannot open input */
+#define EX_NOUSER	67	/* addressee unknown */
+#define EX_NOHOST	68	/* host name unknown */
+#define EX_UNAVAILABLE	69	/* service unavailable */
+#define EX_SOFTWARE	70	/* internal software error */
+#define EX_OSERR	71	/* system error (e.g., can't fork) */
+#define EX_OSFILE	72	/* critical OS file missing */
+#define EX_CANTCREAT	73	/* can't create (user) output file */
+#define EX_IOERR	74	/* input/output error */
+#define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
+#define EX_PROTOCOL	76	/* remote error in protocol */
+#define EX_NOPERM	77	/* permission denied */
+#define EX_CONFIG	78	/* configuration error */
+
+#define EX__MAX		78	/* maximum listed value */
+
+#endif /* !_SYSEXITS_H_ */
diff --git a/libc/libc.map b/libc/libc.map
index 4e17515..47c52a4 100644
--- a/libc/libc.map
+++ b/libc/libc.map
@@ -306,6 +306,7 @@
     alphasort;
     alphasort64;
     android_getaddrinfofornet;
+    android_getaddrinfofornetcontext;
     android_gethostbyaddrfornet;
     android_gethostbynamefornet;
     android_set_abort_message;
diff --git a/libc/zoneinfo/tzdata b/libc/zoneinfo/tzdata
index 2c734fa..4e4f6a7 100644
--- a/libc/zoneinfo/tzdata
+++ b/libc/zoneinfo/tzdata
Binary files differ
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index a70abf5..ef454ab 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -158,6 +158,11 @@
   return 0;
 }
 
+int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
+  ScopedPthreadMutexLocker locker(&g_dl_mutex);
+  return do_dl_iterate_phdr(cb, data);
+}
+
 void android_set_application_target_sdk_version(uint32_t target) {
   // lock to avoid modification in the middle of dlopen.
   ScopedPthreadMutexLocker locker(&g_dl_mutex);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 1f00771..611edb3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -37,7 +37,6 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/param.h>
-#include <sys/personality.h>
 #include <unistd.h>
 
 #include <new>
@@ -393,7 +392,7 @@
 
 // Here, we only have to provide a callback to iterate across all the
 // loaded libraries. gcc_eh does the rest.
-int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
+int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data) {
   int rv = 0;
   for (soinfo* si = solist; si != nullptr; si = si->next) {
     dl_phdr_info dl_info;
@@ -1159,7 +1158,7 @@
 
   ZipEntry entry;
 
-  if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) {
+  if (FindEntry(handle, ZipString(file_path), &entry) != 0) {
     // Entry was not found.
     close(fd);
     return -1;
@@ -1337,7 +1336,7 @@
   }
 
   // Read the ELF header and load the segments.
-  ElfReader elf_reader(realpath.c_str(), fd, file_offset);
+  ElfReader elf_reader(realpath.c_str(), fd, file_offset, file_stat.st_size);
   if (!elf_reader.Load(extinfo)) {
     return nullptr;
   }
@@ -3181,12 +3180,6 @@
     ldpreload_env = getenv("LD_PRELOAD");
   }
 
-#if !defined(__LP64__)
-  if (personality(PER_LINUX32) == -1) {
-    __libc_fatal("error setting PER_LINUX32 personality: %s", strerror(errno));
-  }
-#endif
-
   INFO("[ android linker & debugger ]");
 
   soinfo* si = soinfo_alloc(args.argv[0], nullptr, 0, RTLD_GLOBAL);
diff --git a/linker/linker.h b/linker/linker.h
index 43b1e07..9bca7f3 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -428,6 +428,8 @@
 soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo);
 void do_dlclose(soinfo* si);
 
+int do_dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data), void* data);
+
 const ElfW(Sym)* dlsym_linear_lookup(const char* name, soinfo** found, soinfo* caller, void* handle);
 soinfo* find_containing_library(const void* addr);
 
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index f586b08..30118e3 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -133,8 +133,8 @@
                                       MAYBE_MAP_FLAG((x), PF_R, PROT_READ) | \
                                       MAYBE_MAP_FLAG((x), PF_W, PROT_WRITE))
 
-ElfReader::ElfReader(const char* name, int fd, off64_t file_offset)
-    : name_(name), fd_(fd), file_offset_(file_offset),
+ElfReader::ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size)
+    : name_(name), fd_(fd), file_offset_(file_offset), file_size_(file_size),
       phdr_num_(0), phdr_mmap_(nullptr), phdr_table_(nullptr), phdr_size_(0),
       load_start_(nullptr), load_size_(0), load_bias_(0),
       loaded_phdr_(nullptr) {
@@ -377,6 +377,20 @@
     ElfW(Addr) file_page_start = PAGE_START(file_start);
     ElfW(Addr) file_length = file_end - file_page_start;
 
+    if (file_size_ <= 0) {
+      DL_ERR("\"%s\" invalid file size: %" PRId64, name_, file_size_);
+      return false;
+    }
+
+    if (file_end >= static_cast<size_t>(file_size_)) {
+      DL_ERR("invalid ELF file \"%s\" load segment[%zd]:"
+          " p_offset (%p) + p_filesz (%p) ( = %p) past end of file (0x%" PRIx64 ")",
+          name_, i, reinterpret_cast<void*>(phdr->p_offset),
+          reinterpret_cast<void*>(phdr->p_filesz),
+          reinterpret_cast<void*>(file_end), file_size_);
+      return false;
+    }
+
     if (file_length != 0) {
       void* seg_addr = mmap64(reinterpret_cast<void*>(seg_page_start),
                             file_length,
diff --git a/linker/linker_phdr.h b/linker/linker_phdr.h
index 50f2117..3affa66 100644
--- a/linker/linker_phdr.h
+++ b/linker/linker_phdr.h
@@ -39,7 +39,7 @@
 
 class ElfReader {
  public:
-  ElfReader(const char* name, int fd, off64_t file_offset);
+  ElfReader(const char* name, int fd, off64_t file_offset, off64_t file_size);
   ~ElfReader();
 
   bool Load(const android_dlextinfo* extinfo);
@@ -62,6 +62,7 @@
   const char* name_;
   int fd_;
   off64_t file_offset_;
+  off64_t file_size_;
 
   ElfW(Ehdr) header_;
   size_t phdr_num_;
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 1c01c62..92e3287 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -51,12 +51,12 @@
 
 TEST(dlfcn, dlsym_in_executable) {
   dlerror(); // Clear any pending errors.
-  void* self = dlopen(NULL, RTLD_NOW);
-  ASSERT_TRUE(self != NULL);
-  ASSERT_TRUE(dlerror() == NULL);
+  void* self = dlopen(nullptr, RTLD_NOW);
+  ASSERT_TRUE(self != nullptr);
+  ASSERT_TRUE(dlerror() == nullptr);
 
   void* sym = dlsym(self, "DlSymTestFunction");
-  ASSERT_TRUE(sym != NULL);
+  ASSERT_TRUE(sym != nullptr);
 
   void (*function)() = reinterpret_cast<void(*)()>(sym);
 
@@ -175,11 +175,11 @@
 
 TEST(dlfcn, dlopen_noload) {
   void* handle = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
-  ASSERT_TRUE(handle == NULL);
+  ASSERT_TRUE(handle == nullptr);
   handle = dlopen("libtest_simple.so", RTLD_NOW);
   void* handle2 = dlopen("libtest_simple.so", RTLD_NOW | RTLD_NOLOAD);
-  ASSERT_TRUE(handle != NULL);
-  ASSERT_TRUE(handle2 != NULL);
+  ASSERT_TRUE(handle != nullptr);
+  ASSERT_TRUE(handle2 != nullptr);
   ASSERT_TRUE(handle == handle2);
   ASSERT_EQ(0, dlclose(handle));
   ASSERT_EQ(0, dlclose(handle2));
@@ -220,11 +220,11 @@
   // first check the set case
   setenv("IFUNC_CHOICE", "set", 1);
   void* handle = dlopen("libtest_ifunc.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
   fn_ptr foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
   fn_ptr foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
-  ASSERT_TRUE(foo_ptr != NULL);
-  ASSERT_TRUE(foo_library_ptr != NULL);
+  ASSERT_TRUE(foo_ptr != nullptr);
+  ASSERT_TRUE(foo_library_ptr != nullptr);
   ASSERT_EQ(strncmp("set", foo_ptr(), 3), 0);
   ASSERT_EQ(strncmp("set", foo_library_ptr(), 3), 0);
   dlclose(handle);
@@ -232,11 +232,11 @@
   // then check the unset case
   unsetenv("IFUNC_CHOICE");
   handle = dlopen("libtest_ifunc.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
   foo_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo"));
   foo_library_ptr = reinterpret_cast<fn_ptr>(dlsym(handle, "foo_library"));
-  ASSERT_TRUE(foo_ptr != NULL);
-  ASSERT_TRUE(foo_library_ptr != NULL);
+  ASSERT_TRUE(foo_ptr != nullptr);
+  ASSERT_TRUE(foo_library_ptr != nullptr);
   ASSERT_EQ(strncmp("unset", foo_ptr(), 5), 0);
   ASSERT_EQ(strncmp("unset", foo_library_ptr(), 3), 0);
   dlclose(handle);
@@ -315,9 +315,9 @@
   typedef int (*fn_t) (void);
   fn_t fn, fn2;
   fn = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer"));
-  ASSERT_TRUE(fn != NULL) << dlerror();
+  ASSERT_TRUE(fn != nullptr) << dlerror();
   fn2 = reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "check_order_dlsym_get_answer2"));
-  ASSERT_TRUE(fn2 != NULL) << dlerror();
+  ASSERT_TRUE(fn2 != nullptr) << dlerror();
 
   ASSERT_EQ(42, fn());
   ASSERT_EQ(43, fn2());
@@ -718,7 +718,7 @@
 
 TEST(dlfcn, dlopen_failure) {
   void* self = dlopen("/does/not/exist", RTLD_NOW);
-  ASSERT_TRUE(self == NULL);
+  ASSERT_TRUE(self == nullptr);
 #if defined(__BIONIC__)
   ASSERT_STREQ("dlopen failed: library \"/does/not/exist\" not found", dlerror());
 #else
@@ -737,7 +737,7 @@
   ASSERT_SUBSTR("/main/thread", main_thread_error);
 
   pthread_t t;
-  ASSERT_EQ(0, pthread_create(&t, NULL, ConcurrentDlErrorFn, NULL));
+  ASSERT_EQ(0, pthread_create(&t, nullptr, ConcurrentDlErrorFn, nullptr));
   void* result;
   ASSERT_EQ(0, pthread_join(t, &result));
   char* child_thread_error = static_cast<char*>(result);
@@ -749,31 +749,31 @@
 
 TEST(dlfcn, dlsym_failures) {
   dlerror(); // Clear any pending errors.
-  void* self = dlopen(NULL, RTLD_NOW);
-  ASSERT_TRUE(self != NULL);
-  ASSERT_TRUE(dlerror() == NULL);
+  void* self = dlopen(nullptr, RTLD_NOW);
+  ASSERT_TRUE(self != nullptr);
+  ASSERT_TRUE(dlerror() == nullptr);
 
   void* sym;
 
 #if defined(__BIONIC__) && !defined(__LP64__)
   // RTLD_DEFAULT in lp32 bionic is not (void*)0
   // so it can be distinguished from the NULL handle.
-  sym = dlsym(NULL, "test");
-  ASSERT_TRUE(sym == NULL);
+  sym = dlsym(nullptr, "test");
+  ASSERT_TRUE(sym == nullptr);
   ASSERT_SUBSTR("dlsym library handle is null", dlerror());
 #endif
 
   // NULL symbol name.
 #if defined(__BIONIC__)
   // glibc marks this parameter non-null and SEGVs if you cheat.
-  sym = dlsym(self, NULL);
-  ASSERT_TRUE(sym == NULL);
+  sym = dlsym(self, nullptr);
+  ASSERT_TRUE(sym == nullptr);
   ASSERT_SUBSTR("", dlerror());
 #endif
 
   // Symbol that doesn't exist.
   sym = dlsym(self, "ThisSymbolDoesNotExist");
-  ASSERT_TRUE(sym == NULL);
+  ASSERT_TRUE(sym == nullptr);
   ASSERT_SUBSTR("undefined symbol: ThisSymbolDoesNotExist", dlerror());
 
   ASSERT_EQ(0, dlclose(self));
@@ -781,12 +781,12 @@
 
 TEST(dlfcn, dladdr_executable) {
   dlerror(); // Clear any pending errors.
-  void* self = dlopen(NULL, RTLD_NOW);
-  ASSERT_TRUE(self != NULL);
-  ASSERT_TRUE(dlerror() == NULL);
+  void* self = dlopen(nullptr, RTLD_NOW);
+  ASSERT_TRUE(self != nullptr);
+  ASSERT_TRUE(dlerror() == nullptr);
 
   void* sym = dlsym(self, "DlSymTestFunction");
-  ASSERT_TRUE(sym != NULL);
+  ASSERT_TRUE(sym != nullptr);
 
   // Deliberately ask dladdr for an address inside a symbol, rather than the symbol base address.
   void* addr = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(sym) + 2);
@@ -861,12 +861,12 @@
   dlerror(); // Clear any pending errors.
 
   // No symbol corresponding to NULL.
-  ASSERT_EQ(dladdr(NULL, &info), 0); // Zero on error, non-zero on success.
-  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
+  ASSERT_EQ(dladdr(nullptr, &info), 0); // Zero on error, non-zero on success.
+  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
 
   // No symbol corresponding to a stack address.
   ASSERT_EQ(dladdr(&info, &info), 0); // Zero on error, non-zero on success.
-  ASSERT_TRUE(dlerror() == NULL); // dladdr(3) doesn't set dlerror(3).
+  ASSERT_TRUE(dlerror() == nullptr); // dladdr(3) doesn't set dlerror(3).
 }
 
 // GNU-style ELF hash tables are incompatible with the MIPS ABI.
@@ -922,49 +922,49 @@
 
 #if defined(__GLIBC__)
   // glibc was smart enough not to define RTLD_NOW as 0, so it can detect missing flags.
-  handle = dlopen(NULL, 0);
-  ASSERT_TRUE(handle == NULL);
+  handle = dlopen(nullptr, 0);
+  ASSERT_TRUE(handle == nullptr);
   ASSERT_SUBSTR("invalid", dlerror());
 #endif
 
-  handle = dlopen(NULL, 0xffffffff);
-  ASSERT_TRUE(handle == NULL);
+  handle = dlopen(nullptr, 0xffffffff);
+  ASSERT_TRUE(handle == nullptr);
   ASSERT_SUBSTR("invalid", dlerror());
 
   // glibc actually allows you to choose both RTLD_NOW and RTLD_LAZY at the same time, and so do we.
-  handle = dlopen(NULL, RTLD_NOW|RTLD_LAZY);
-  ASSERT_TRUE(handle != NULL);
-  ASSERT_SUBSTR(NULL, dlerror());
+  handle = dlopen(nullptr, RTLD_NOW|RTLD_LAZY);
+  ASSERT_TRUE(handle != nullptr);
+  ASSERT_SUBSTR(nullptr, dlerror());
 }
 
 TEST(dlfcn, rtld_default_unknown_symbol) {
   void* addr = dlsym(RTLD_DEFAULT, "ANY_UNKNOWN_SYMBOL_NAME");
-  ASSERT_TRUE(addr == NULL);
+  ASSERT_TRUE(addr == nullptr);
 }
 
 TEST(dlfcn, rtld_default_known_symbol) {
   void* addr = dlsym(RTLD_DEFAULT, "fopen");
-  ASSERT_TRUE(addr != NULL);
+  ASSERT_TRUE(addr != nullptr);
 }
 
 TEST(dlfcn, rtld_next_unknown_symbol) {
   void* addr = dlsym(RTLD_NEXT, "ANY_UNKNOWN_SYMBOL_NAME");
-  ASSERT_TRUE(addr == NULL);
+  ASSERT_TRUE(addr == nullptr);
 }
 
 TEST(dlfcn, rtld_next_known_symbol) {
   void* addr = dlsym(RTLD_NEXT, "fopen");
-  ASSERT_TRUE(addr != NULL);
+  ASSERT_TRUE(addr != nullptr);
 }
 
 TEST(dlfcn, dlsym_weak_func) {
   dlerror();
   void* handle = dlopen("libtest_dlsym_weak_func.so", RTLD_NOW);
-  ASSERT_TRUE(handle != NULL);
+  ASSERT_TRUE(handle != nullptr);
 
   int (*weak_func)();
   weak_func = reinterpret_cast<int (*)()>(dlsym(handle, "weak_func"));
-  ASSERT_TRUE(weak_func != NULL) << "dlerror: " << dlerror();
+  ASSERT_TRUE(weak_func != nullptr) << "dlerror: " << dlerror();
   EXPECT_EQ(42, weak_func());
   dlclose(handle);
 }
@@ -982,8 +982,8 @@
 TEST(dlfcn, dlopen_symlink) {
   void* handle1 = dlopen("libdlext_test.so", RTLD_NOW);
   void* handle2 = dlopen("libdlext_test_v2.so", RTLD_NOW);
-  ASSERT_TRUE(handle1 != NULL);
-  ASSERT_TRUE(handle2 != NULL);
+  ASSERT_TRUE(handle1 != nullptr);
+  ASSERT_TRUE(handle2 != nullptr);
   ASSERT_EQ(handle1, handle2);
   dlclose(handle1);
   dlclose(handle2);
diff --git a/tests/sys_personality_test.cpp b/tests/sys_personality_test.cpp
index 55a023d..2dfaa65 100644
--- a/tests/sys_personality_test.cpp
+++ b/tests/sys_personality_test.cpp
@@ -19,7 +19,7 @@
 #include <sys/personality.h>
 
 TEST(sys_personality, current_persona) {
-  int persona = personality(0xffffffff);
+  int persona = personality(0xffffffff) & PER_MASK;
 #if defined(__BIONIC__)
 #if defined(__LP64__)
   ASSERT_EQ(PER_LINUX, persona);