diff options
-rw-r--r-- | libc/bionic/libc_init_common.cpp | 17 | ||||
-rw-r--r-- | libc/dns/include/resolv_netid.h | 29 | ||||
-rw-r--r-- | libc/dns/net/getaddrinfo.c | 91 | ||||
-rw-r--r-- | libc/dns/net/gethnamaddr.c | 6 | ||||
-rw-r--r-- | libc/include/android/dlext.h | 10 | ||||
-rw-r--r-- | libc/include/pthread.h | 3 | ||||
-rw-r--r-- | libc/include/sys/personality.h | 2 | ||||
-rw-r--r-- | libc/libc.map | 1 | ||||
-rw-r--r-- | linker/dlfcn.cpp | 5 | ||||
-rw-r--r-- | linker/linker.cpp | 18 | ||||
-rw-r--r-- | linker/linker.h | 2 | ||||
-rw-r--r-- | linker/linker_phdr.cpp | 26 | ||||
-rw-r--r-- | linker/linker_phdr.h | 3 | ||||
-rw-r--r-- | tests/Android.mk | 4 | ||||
-rw-r--r-- | tests/sys_personality_test.cpp | 2 | ||||
-rw-r--r-- | tests/time_test.cpp | 6 |
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()); |