summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libc/bionic/libc_init_common.cpp17
-rw-r--r--libc/dns/include/resolv_netid.h29
-rw-r--r--libc/dns/net/getaddrinfo.c91
-rw-r--r--libc/dns/net/gethnamaddr.c6
-rw-r--r--libc/include/android/dlext.h10
-rw-r--r--libc/include/pthread.h3
-rw-r--r--libc/include/sys/personality.h2
-rw-r--r--libc/libc.map1
-rw-r--r--linker/dlfcn.cpp5
-rw-r--r--linker/linker.cpp18
-rw-r--r--linker/linker.h2
-rw-r--r--linker/linker_phdr.cpp26
-rw-r--r--linker/linker_phdr.h3
-rw-r--r--tests/Android.mk4
-rw-r--r--tests/sys_personality_test.cpp2
-rw-r--r--tests/time_test.cpp6
16 files changed, 152 insertions, 73 deletions
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 @@ static void __sanitize_environment_variables(char** env) {
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 @@ void __libc_init_AT_SECURE(KernelArgumentBlock& args) {
// 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 @@ struct addrinfo;
#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 @@ struct res_target {
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 void _endhtent(FILE **);
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 @@ str2number(const char *p)
}
/*
- * 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 @@ _test_connect(int pf, struct sockaddr *addr, size_t addrlen, unsigned mark) {
* 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 @@ android_getaddrinfo_proxy(
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 @@ int
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 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
/* 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 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
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 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
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 @@ android_getaddrinfofornet(const char *hostname, const char *servname,
*/
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 @@ explore_fqdn(const struct addrinfo *pai, const char *hostname,
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 @@ _rfc6724_compare(const void *ptr1, const void* ptr2)
* 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 @@ _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned
}
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 @@ _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned
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 @@ _find_src_addr(const struct sockaddr *addr, struct sockaddr *src_addr, unsigned
/*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 @@ _rfc6724_sort(struct addrinfo *list_sentinel, unsigned mark)
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 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
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 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
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 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
* 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 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
}
}
- _rfc6724_sort(&sentinel, netid);
+ _rfc6724_sort(&sentinel, netcontext->app_mark, netcontext->uid);
__res_put_state(res);
diff --git a/libc/dns/net/gethnamaddr.c b/libc/dns/net/gethnamaddr.c
index 8f5800a..42f0d0a 100644
--- a/libc/dns/net/gethnamaddr.c
+++ b/libc/dns/net/gethnamaddr.c
@@ -640,6 +640,9 @@ android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen
ptr += size;
}
+ // Fix alignment after variable-length data.
+ ptr = (char*)ALIGN(ptr);
+
int aliases_len = ((int)(aliases - aliases_ptrs) + 1) * sizeof(*hp->h_aliases);
if (ptr + aliases_len > hbuf_end) {
goto nospc;
@@ -674,6 +677,9 @@ android_read_hostent(FILE* proxy, struct hostent* hp, char* hbuf, size_t hbuflen
ptr += size;
}
+ // Fix alignment after variable-length data.
+ ptr = (char*)ALIGN(ptr);
+
int addrs_len = ((int)(addr_p - addr_ptrs) + 1) * sizeof(*hp->h_addr_list);
if (ptr + addrs_len > hbuf_end) {
goto nospc;
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index f10a8a2..40f610f 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -73,6 +73,13 @@ enum {
*/
ANDROID_DLEXT_FORCE_LOAD = 0x40,
+ /* When set, if the minimum p_vaddr of the ELF file's PT_LOAD segments is non-zero,
+ * the dynamic linker will load it at that address.
+ *
+ * This flag is for ART internal use only.
+ */
+ ANDROID_DLEXT_FORCE_FIXED_VADDR = 0x80,
+
/* Mask of valid bits */
ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS |
ANDROID_DLEXT_RESERVED_ADDRESS_HINT |
@@ -80,7 +87,8 @@ enum {
ANDROID_DLEXT_USE_RELRO |
ANDROID_DLEXT_USE_LIBRARY_FD |
ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET |
- ANDROID_DLEXT_FORCE_LOAD,
+ ANDROID_DLEXT_FORCE_LOAD |
+ ANDROID_DLEXT_FORCE_FIXED_VADDR,
};
typedef struct {
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 6fb06fb..260ae5b 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -46,9 +46,6 @@ typedef struct {
typedef long pthread_mutexattr_t;
-#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER
-#define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER
-
enum {
PTHREAD_MUTEX_NORMAL = 0,
PTHREAD_MUTEX_RECURSIVE = 1,
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/libc.map b/libc/libc.map
index 4e17515..47c52a4 100644
--- a/libc/libc.map
+++ b/libc/libc.map
@@ -306,6 +306,7 @@ LIBC {
alphasort;
alphasort64;
android_getaddrinfofornet;
+ android_getaddrinfofornetcontext;
android_gethostbyaddrfornet;
android_gethostbynamefornet;
android_set_abort_message;
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 @@ int dlclose(void* handle) {
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 2c51ed9..60f8489 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>
@@ -353,7 +352,7 @@ _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int* pcount) {
// 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;
@@ -1293,7 +1292,7 @@ static soinfo* load_library(int fd, off64_t file_offset,
}
// 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;
}
@@ -2884,6 +2883,13 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
#if !defined(__LP64__)
if (has_text_relocations) {
+ // Fail if app is targeting sdk version > 22
+ // TODO (dimitry): remove != __ANDROID_API__ check once http://b/20020312 is fixed
+ if (get_application_target_sdk_version() != __ANDROID_API__
+ && get_application_target_sdk_version() > 22) {
+ DL_ERR("%s: has text relocations", get_realpath());
+ return false;
+ }
// Make segments writable to allow text relocations to work properly. We will later call
// phdr_table_protect_segments() after all of them are applied and all constructors are run.
DL_WARN("%s has text relocations. This is wasting memory and prevents "
@@ -3104,12 +3110,6 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
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 6042cb8..023b672 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -421,6 +421,8 @@ void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
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 638c9d6..30118e3 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -133,8 +133,8 @@ static int GetTargetElfMachine() {
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) {
@@ -316,6 +316,8 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
void* start;
size_t reserved_size = 0;
bool reserved_hint = true;
+ // Assume position independent executable by default.
+ uint8_t* mmap_hint = nullptr;
if (extinfo != nullptr) {
if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS) {
@@ -324,6 +326,10 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
} else if (extinfo->flags & ANDROID_DLEXT_RESERVED_ADDRESS_HINT) {
reserved_size = extinfo->reserved_size;
}
+
+ if ((extinfo->flags & ANDROID_DLEXT_FORCE_FIXED_VADDR) != 0) {
+ mmap_hint = addr;
+ }
}
if (load_size_ > reserved_size) {
@@ -333,7 +339,7 @@ bool ElfReader::ReserveAddressSpace(const android_dlextinfo* extinfo) {
return false;
}
int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
- start = mmap(nullptr, load_size_, PROT_NONE, mmap_flags, -1, 0);
+ start = mmap(mmap_hint, load_size_, PROT_NONE, mmap_flags, -1, 0);
if (start == MAP_FAILED) {
DL_ERR("couldn't reserve %zd bytes of address space for \"%s\"", load_size_, name_);
return false;
@@ -371,6 +377,20 @@ bool ElfReader::LoadSegments() {
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 @@ class ElfReader {
const char* name_;
int fd_;
off64_t file_offset_;
+ off64_t file_size_;
ElfW(Ehdr) header_;
size_t phdr_num_;
diff --git a/tests/Android.mk b/tests/Android.mk
index 964a34a..84d3426 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -49,9 +49,6 @@ endif
test_cppflags = \
-std=gnu++11 \
-libBionicStandardTests_src_files_target := \
- libdl_test.cpp \
-
libBionicStandardTests_src_files := \
arpa_inet_test.cpp \
buffer_tests.cpp \
@@ -275,6 +272,7 @@ bionic-unit-tests_src_files := \
dlext_test.cpp \
__cxa_thread_atexit_test.cpp \
dlfcn_test.cpp \
+ libdl_test.cpp \
pthread_dlfcn_test.cpp \
bionic-unit-tests_cflags := $(test_cflags)
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);
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index c37df36..90de8d8 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -166,7 +166,7 @@ void SetTime(timer_t t, time_t value_s, time_t value_ns, time_t interval_s, time
ts.it_value.tv_nsec = value_ns;
ts.it_interval.tv_sec = interval_s;
ts.it_interval.tv_nsec = interval_ns;
- ASSERT_EQ(0, timer_settime(t, TIMER_ABSTIME, &ts, NULL));
+ ASSERT_EQ(0, timer_settime(t, 0, &ts, NULL));
}
static void NoOpNotifyFunction(sigval_t) {
@@ -381,8 +381,8 @@ TEST(time, timer_create_multiple) {
ASSERT_EQ(0, counter2.Value());
ASSERT_EQ(0, counter3.Value());
- counter2.SetTime(0, 1, 0, 0);
- usleep(500000);
+ counter2.SetTime(0, 500000000, 0, 0);
+ sleep(1);
EXPECT_EQ(0, counter1.Value());
EXPECT_EQ(1, counter2.Value());