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