summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libc/Android.bp22
-rw-r--r--libc/bionic/pthread_mutex.cpp22
-rw-r--r--libc/dns/net/getaddrinfo.c10
-rw-r--r--libc/dns/net/hosts_cache.c551
-rw-r--r--libc/dns/net/hosts_cache.h23
-rw-r--r--libc/dns/net/sethostent.c7
-rw-r--r--libc/include/arpa/inet.h1
-rw-r--r--libc/include/bits/in_addr.h3
-rw-r--r--libc/include/inaddr.h36
-rw-r--r--linker/Android.bp4
-rw-r--r--linker/linker.cpp84
-rw-r--r--linker/linker.h20
-rw-r--r--linker/linker_main.cpp11
13 files changed, 782 insertions, 12 deletions
diff --git a/libc/Android.bp b/libc/Android.bp
index d3271ae91..ce714054a 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -102,6 +102,18 @@ libc_scudo_product_variables = {
},
}
+libc32_scudo_product_variables = {
+ malloc_not_svelte_libc32: {
+ cflags: ["-DUSE_SCUDO"],
+ whole_static_libs: ["libscudo"],
+ exclude_static_libs: [
+ "libjemalloc5",
+ "libc_jemalloc_wrapper",
+ ],
+ },
+}
+
+
// Defaults for native allocator libs/includes to make it
// easier to change.
// To disable scudo for the non-svelte config remove the line:
@@ -116,7 +128,14 @@ cc_defaults {
"libc_jemalloc_wrapper",
],
header_libs: ["gwp_asan_headers"],
- product_variables: libc_scudo_product_variables,
+ multilib: {
+ lib64: {
+ product_variables: libc_scudo_product_variables,
+ },
+ lib32: {
+ product_variables: libc32_scudo_product_variables,
+ }
+ },
}
// Functions not implemented by jemalloc directly, or that need to
@@ -1860,6 +1879,7 @@ cc_library {
name: "libstdc++",
static_ndk_lib: true,
static_libs: ["libasync_safe"],
+ vendor_available: true,
static: {
system_shared_libs: [],
diff --git a/libc/bionic/pthread_mutex.cpp b/libc/bionic/pthread_mutex.cpp
index a15e98149..ead3e632e 100644
--- a/libc/bionic/pthread_mutex.cpp
+++ b/libc/bionic/pthread_mutex.cpp
@@ -527,7 +527,8 @@ int pthread_mutex_init(pthread_mutex_t* mutex_interface, const pthread_mutexattr
return EINVAL;
}
- if (((*attr & MUTEXATTR_PROTOCOL_MASK) >> MUTEXATTR_PROTOCOL_SHIFT) == PTHREAD_PRIO_INHERIT) {
+ if (((*attr & MUTEXATTR_PROTOCOL_MASK) >> MUTEXATTR_PROTOCOL_SHIFT) == PTHREAD_PRIO_INHERIT
+ && android_get_application_target_sdk_version() >= 28) {
#if !defined(__LP64__)
if (state & MUTEX_SHARED_MASK) {
return EINVAL;
@@ -791,17 +792,22 @@ static int MutexLockWithTimeout(pthread_mutex_internal_t* mutex, bool use_realti
} // namespace NonPI
-static inline __always_inline bool IsMutexDestroyed(uint16_t mutex_state) {
- return mutex_state == 0xffff;
-}
-
// Inlining this function in pthread_mutex_lock() adds the cost of stack frame instructions on
// ARM64. So make it noinline.
-static int __attribute__((noinline)) HandleUsingDestroyedMutex(pthread_mutex_t* mutex,
- const char* function_name) {
+static bool __attribute__((noinline)) IsMutexDestroyed(uint16_t mutex_state) {
+ // Checking for mutex destruction is a P-specific behavior. Bypass the
+ // check if the SDK version precedes P, so that no change in behavior
+ // that may cause crashes is introduced.
if (android_get_application_target_sdk_version() >= 28) {
- __fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex);
+ return mutex_state == 0xffff;
+ } else {
+ return false;
}
+}
+
+static int __always_inline HandleUsingDestroyedMutex(pthread_mutex_t* mutex,
+ const char* function_name) {
+ __fortify_fatal("%s called on a destroyed mutex (%p)", function_name, mutex);
return EBUSY;
}
diff --git a/libc/dns/net/getaddrinfo.c b/libc/dns/net/getaddrinfo.c
index d0c11d2b0..cc94b21e2 100644
--- a/libc/dns/net/getaddrinfo.c
+++ b/libc/dns/net/getaddrinfo.c
@@ -109,6 +109,8 @@
#include "nsswitch.h"
#include "private/bionic_defs.h"
+#include "hosts_cache.h"
+
typedef union sockaddr_union {
struct sockaddr generic;
struct sockaddr_in in;
@@ -2125,6 +2127,14 @@ _files_getaddrinfo(void *rv, void *cb_data, va_list ap)
name = va_arg(ap, char *);
pai = va_arg(ap, struct addrinfo *);
+ memset(&sentinel, 0, sizeof(sentinel));
+ cur = &sentinel;
+ int gai_error = hc_getaddrinfo(name, NULL, pai, &cur);
+ if (gai_error != EAI_SYSTEM) {
+ *((struct addrinfo **)rv) = sentinel.ai_next;
+ return (gai_error == 0 ? NS_SUCCESS : NS_NOTFOUND);
+ }
+
// fprintf(stderr, "_files_getaddrinfo() name = '%s'\n", name);
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
diff --git a/libc/dns/net/hosts_cache.c b/libc/dns/net/hosts_cache.c
new file mode 100644
index 000000000..5038986be
--- /dev/null
+++ b/libc/dns/net/hosts_cache.c
@@ -0,0 +1,551 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utime.h>
+#include <pthread.h>
+
+#include <netinet/in6.h>
+#include <arpa/inet.h>
+
+#include "hostent.h"
+#include "resolv_private.h"
+
+#define MAX_ADDRLEN (INET6_ADDRSTRLEN - (1 + 5))
+#define MAX_HOSTLEN MAXHOSTNAMELEN
+
+#define ESTIMATED_LINELEN 32
+#define HCFILE_ALLOC_SIZE 256
+
+/* From sethostent.c */
+#define ALIGNBYTES (sizeof(uintptr_t) - 1)
+#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
+
+/*
+ * Host cache entry for hcfile.c_data.
+ * Offsets are into hcfile.h_data.
+ * Strings are *not* terminated by NULL, but by whitespace (isspace) or '#'.
+ * Use hstr* functions with these.
+ */
+struct hcent
+{
+ uint32_t addr;
+ uint32_t name;
+};
+
+/*
+ * Overall host cache file state.
+ */
+struct hcfile
+{
+ int h_fd;
+ struct stat h_st;
+ char *h_data;
+
+ uint32_t c_alloc;
+ uint32_t c_len;
+ struct hcent *c_data;
+};
+static struct hcfile hcfile;
+static pthread_mutex_t hclock = PTHREAD_MUTEX_INITIALIZER;
+
+static size_t hstrlen(const char *s)
+{
+ const char *p = s;
+ while (*p && *p != '#' && !isspace(*p))
+ ++p;
+ return p - s;
+}
+
+static int hstrcmp(const char *a, const char *b)
+{
+ size_t alen = hstrlen(a);
+ size_t blen = hstrlen(b);
+ int res = strncmp(a, b, MIN(alen, blen));
+ if (res == 0)
+ res = alen - blen;
+ return res;
+}
+
+static char *hstrcpy(char *dest, const char *src)
+{
+ size_t len = hstrlen(src);
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ return dest;
+}
+
+static char *hstrdup(const char *s)
+{
+ size_t len = hstrlen(s);
+ char *dest = (char *)malloc(len + 1);
+ if (!dest)
+ return NULL;
+ memcpy(dest, s, len);
+ dest[len] = '\0';
+ return dest;
+}
+
+static int cmp_hcent_name(const void *a, const void *b)
+{
+ struct hcent *ea = (struct hcent *)a;
+ const char *na = hcfile.h_data + ea->name;
+ struct hcent *eb = (struct hcent *)b;
+ const char *nb = hcfile.h_data + eb->name;
+
+ return hstrcmp(na, nb);
+}
+
+static struct hcent *_hcfindname_exact(const char *name)
+{
+ size_t first, last, mid;
+ struct hcent *cur = NULL;
+ int cmp;
+
+ if (hcfile.c_len == 0)
+ return NULL;
+
+ first = 0;
+ last = hcfile.c_len - 1;
+ mid = (first + last) / 2;
+ while (first <= last) {
+ cur = hcfile.c_data + mid;
+ cmp = hstrcmp(hcfile.h_data + cur->name, name);
+ if (cmp == 0)
+ goto found;
+ if (cmp < 0)
+ first = mid + 1;
+ else {
+ if (mid > 0)
+ last = mid - 1;
+ else
+ return NULL;
+ }
+ mid = (first + last) / 2;
+ }
+ return NULL;
+
+found:
+ while (cur > hcfile.c_data) {
+ struct hcent *prev = cur - 1;
+ cmp = cmp_hcent_name(cur, prev);
+ if (cmp)
+ break;
+ cur = prev;
+ }
+
+ return cur;
+}
+
+static struct hcent *_hcfindname(const char *name)
+{
+ struct hcent *ent;
+ char namebuf[MAX_HOSTLEN];
+ char *p;
+ char *dot;
+
+ ent = _hcfindname_exact(name);
+ if (!ent && strlen(name) < sizeof(namebuf)) {
+ strcpy(namebuf, name);
+ p = namebuf;
+ do {
+ dot = strchr(p, '.');
+ if (!dot)
+ break;
+ if (dot > p) {
+ *(dot - 1) = '*';
+ ent = _hcfindname_exact(dot - 1);
+ }
+ p = dot + 1;
+ }
+ while (!ent);
+ }
+
+ return ent;
+}
+
+/*
+ * Find next name on line, if any.
+ *
+ * Assumes that line is terminated by LF.
+ */
+static const char *_hcnextname(const char *name)
+{
+ while (!isspace(*name)) {
+ if (*name == '#')
+ return NULL;
+ ++name;
+ }
+ while (isspace(*name)) {
+ if (*name == '\n')
+ return NULL;
+ ++name;
+ }
+ if (*name == '#')
+ return NULL;
+ return name;
+}
+
+static int _hcfilemmap(void)
+{
+ struct stat st;
+ int h_fd;
+ char *h_addr;
+ const char *p, *pend;
+ uint32_t c_alloc;
+
+ h_fd = open(_PATH_HOSTS, O_RDONLY);
+ if (h_fd < 0)
+ return -1;
+ if (flock(h_fd, LOCK_EX) != 0) {
+ close(h_fd);
+ return -1;
+ }
+
+ if (hcfile.h_data) {
+ memset(&st, 0, sizeof(st));
+ if (fstat(h_fd, &st) == 0) {
+ if (st.st_size == hcfile.h_st.st_size &&
+ st.st_mtime == hcfile.h_st.st_mtime) {
+ flock(h_fd, LOCK_UN);
+ close(h_fd);
+ return 0;
+ }
+ }
+ free(hcfile.c_data);
+ munmap(hcfile.h_data, hcfile.h_st.st_size);
+ close(hcfile.h_fd);
+ memset(&hcfile, 0, sizeof(struct hcfile));
+ }
+
+ if (fstat(h_fd, &st) != 0) {
+ flock(h_fd, LOCK_UN);
+ close(h_fd);
+ return -1;
+ }
+ h_addr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, h_fd, 0);
+ if (h_addr == MAP_FAILED) {
+ flock(h_fd, LOCK_UN);
+ close(h_fd);
+ return -1;
+ }
+
+ hcfile.h_fd = h_fd;
+ hcfile.h_st = st;
+ hcfile.h_data = h_addr;
+
+ c_alloc = 0;
+ /*
+ * Do an initial allocation if the file is "large". Estimate
+ * 32 bytes per line and define "large" as more than half of
+ * the alloc growth size (256 entries).
+ */
+ if (st.st_size >= ESTIMATED_LINELEN * HCFILE_ALLOC_SIZE / 2) {
+ c_alloc = st.st_size / ESTIMATED_LINELEN;
+ hcfile.c_data = malloc(c_alloc * sizeof(struct hcent));
+ if (!hcfile.c_data) {
+ goto oom;
+ }
+ }
+
+ p = (const char *)h_addr;
+ pend = p + st.st_size;
+ while (p < pend) {
+ const char *eol, *addr, *name;
+ size_t len;
+ addr = p;
+ eol = memchr(p, '\n', pend - p);
+ if (!eol)
+ break;
+ p = eol + 1;
+ if (*addr == '#' || *addr == '\n')
+ continue;
+ len = hstrlen(addr);
+ if (len > MAX_ADDRLEN)
+ continue;
+ name = addr + len;
+ while (name < eol && isspace(*name))
+ ++name;
+ while (name < eol) {
+ len = hstrlen(name);
+ if (len == 0)
+ break;
+ if (len < MAX_HOSTLEN) {
+ struct hcent *ent;
+ if (c_alloc <= hcfile.c_len) {
+ struct hcent *c_data;
+ c_alloc += HCFILE_ALLOC_SIZE;
+ c_data = realloc(hcfile.c_data, c_alloc * sizeof(struct hcent));
+ if (!c_data) {
+ goto oom;
+ }
+ hcfile.c_data = c_data;
+ }
+ ent = hcfile.c_data + hcfile.c_len;
+ ent->addr = addr - h_addr;
+ ent->name = name - h_addr;
+ ++hcfile.c_len;
+ }
+ name += len;
+ while (name < eol && isspace(*name))
+ ++name;
+ }
+ }
+
+ qsort(hcfile.c_data, hcfile.c_len,
+ sizeof(struct hcent), cmp_hcent_name);
+
+ flock(h_fd, LOCK_UN);
+
+ return 0;
+
+oom:
+ free(hcfile.c_data);
+ munmap(hcfile.h_data, hcfile.h_st.st_size);
+ flock(hcfile.h_fd, LOCK_UN);
+ close(hcfile.h_fd);
+ memset(&hcfile, 0, sizeof(struct hcfile));
+ return -1;
+}
+
+/*
+ * Caching version of getaddrinfo.
+ *
+ * If we find the requested host name in the cache, use getaddrinfo to
+ * populate the result for each address we find.
+ *
+ * Note glibc and bionic differ in the handling of ai_canonname. POSIX
+ * says that ai_canonname is only populated in the first result entry.
+ * glibc does this. bionic populates ai_canonname in all result entries.
+ * We choose the POSIX/glibc way here.
+ */
+int hc_getaddrinfo(const char *host, const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result)
+{
+ int ret = 0;
+ struct hcent *ent, *cur;
+ struct addrinfo *ai;
+ struct addrinfo rhints;
+ struct addrinfo *last;
+ int canonname = 0;
+ int cmp;
+
+ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
+ return EAI_SYSTEM;
+
+ /* Avoid needless work and recursion */
+ if (hints && (hints->ai_flags & AI_NUMERICHOST))
+ return EAI_SYSTEM;
+ if (!host)
+ return EAI_SYSTEM;
+
+ pthread_mutex_lock(&hclock);
+
+ if (_hcfilemmap() != 0) {
+ ret = EAI_SYSTEM;
+ goto out;
+ }
+ ent = _hcfindname(host);
+ if (!ent) {
+ ret = EAI_NONAME;
+ goto out;
+ }
+
+ if (hints) {
+ canonname = (hints->ai_flags & AI_CANONNAME);
+ memcpy(&rhints, hints, sizeof(rhints));
+ rhints.ai_flags &= ~AI_CANONNAME;
+ }
+ else {
+ memset(&rhints, 0, sizeof(rhints));
+ }
+ rhints.ai_flags |= AI_NUMERICHOST;
+
+ last = NULL;
+ cur = ent;
+ do {
+ char addrstr[MAX_ADDRLEN];
+ struct addrinfo *res;
+
+ hstrcpy(addrstr, hcfile.h_data + cur->addr);
+
+ if (getaddrinfo(addrstr, service, &rhints, &res) == 0) {
+ if (!last)
+ (*result)->ai_next = res;
+ else
+ last->ai_next = res;
+ last = res;
+ while (last->ai_next)
+ last = last->ai_next;
+ }
+
+ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
+ break;
+ cmp = cmp_hcent_name(cur, cur + 1);
+ cur = cur + 1;
+ }
+ while (!cmp);
+
+ if (last == NULL) {
+ /* This check is equivalent to (*result)->ai_next == NULL */
+ ret = EAI_NODATA;
+ goto out;
+ }
+
+ if (canonname) {
+ ai = (*result)->ai_next;
+ free(ai->ai_canonname);
+ ai->ai_canonname = hstrdup(hcfile.h_data + ent->name);
+ }
+
+out:
+ pthread_mutex_unlock(&hclock);
+ return ret;
+}
+
+/*
+ * Caching version of gethtbyname.
+ *
+ * Note glibc and bionic differ in the handling of aliases. glibc returns
+ * all aliases for all entries, regardless of whether they match h_addrtype.
+ * bionic returns only the aliases for the first hosts entry. We return all
+ * aliases for all IPv4 entries.
+ *
+ * Additionally, if an alias is IPv6 and the primary name for an alias also
+ * has an IPv4 entry, glibc will return the IPv4 address(es), but bionic
+ * will not. Neither do we.
+ */
+int hc_gethtbyname(const char *host, int af, struct getnamaddr *info)
+{
+ int ret = NETDB_SUCCESS;
+ struct hcent *ent, *cur;
+ int cmp;
+ size_t addrlen;
+ unsigned int naliases = 0;
+ char *aliases[MAXALIASES];
+ unsigned int naddrs = 0;
+ char *addr_ptrs[MAXADDRS];
+ unsigned int n;
+
+ if (getenv("ANDROID_HOSTS_CACHE_DISABLE") != NULL)
+ return NETDB_INTERNAL;
+
+ switch (af) {
+ case AF_INET: addrlen = NS_INADDRSZ; break;
+ case AF_INET6: addrlen = NS_IN6ADDRSZ; break;
+ default:
+ return NETDB_INTERNAL;
+ }
+
+ pthread_mutex_lock(&hclock);
+
+ if (_hcfilemmap() != 0) {
+ ret = NETDB_INTERNAL;
+ goto out;
+ }
+
+ ent = _hcfindname(host);
+ if (!ent) {
+ ret = HOST_NOT_FOUND;
+ goto out;
+ }
+
+ cur = ent;
+ do {
+ char addr[16];
+ char addrstr[MAX_ADDRLEN];
+ char namestr[MAX_HOSTLEN];
+ const char *name;
+
+ hstrcpy(addrstr, hcfile.h_data + cur->addr);
+ if (inet_pton(af, addrstr, &addr) == 1) {
+ char *aligned;
+ /* First match is considered the official hostname */
+ if (naddrs == 0) {
+ hstrcpy(namestr, hcfile.h_data + cur->name);
+ HENT_SCOPY(info->hp->h_name, namestr, info->buf, info->buflen);
+ }
+ for (name = hcfile.h_data + cur->name; name; name = _hcnextname(name)) {
+ if (!hstrcmp(name, host))
+ continue;
+ hstrcpy(namestr, name);
+ HENT_SCOPY(aliases[naliases], namestr, info->buf, info->buflen);
+ ++naliases;
+ if (naliases >= MAXALIASES)
+ goto nospc;
+ }
+ aligned = (char *)ALIGN(info->buf);
+ if (info->buf != aligned) {
+ if ((ptrdiff_t)info->buflen < (aligned - info->buf))
+ goto nospc;
+ info->buflen -= (aligned - info->buf);
+ info->buf = aligned;
+ }
+ HENT_COPY(addr_ptrs[naddrs], addr, addrlen, info->buf, info->buflen);
+ ++naddrs;
+ if (naddrs >= MAXADDRS)
+ goto nospc;
+ }
+
+ if(cur + 1 >= hcfile.c_data + hcfile.c_len)
+ break;
+ cmp = cmp_hcent_name(cur, cur + 1);
+ cur = cur + 1;
+ }
+ while (!cmp);
+
+ if (naddrs == 0) {
+ ret = HOST_NOT_FOUND;
+ goto out;
+ }
+
+ addr_ptrs[naddrs++] = NULL;
+ aliases[naliases++] = NULL;
+
+ /* hp->h_name already populated */
+ HENT_ARRAY(info->hp->h_aliases, naliases, info->buf, info->buflen);
+ for (n = 0; n < naliases; ++n) {
+ info->hp->h_aliases[n] = aliases[n];
+ }
+ info->hp->h_addrtype = af;
+ info->hp->h_length = addrlen;
+ HENT_ARRAY(info->hp->h_addr_list, naddrs, info->buf, info->buflen);
+ for (n = 0; n < naddrs; ++n) {
+ info->hp->h_addr_list[n] = addr_ptrs[n];
+ }
+
+out:
+ pthread_mutex_unlock(&hclock);
+ *info->he = ret;
+ return ret;
+
+nospc:
+ ret = NETDB_INTERNAL;
+ goto out;
+}
diff --git a/libc/dns/net/hosts_cache.h b/libc/dns/net/hosts_cache.h
new file mode 100644
index 000000000..fa5488f51
--- /dev/null
+++ b/libc/dns/net/hosts_cache.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+struct getnamaddr;
+
+int hc_getaddrinfo(const char *host, const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result);
+
+int hc_gethtbyname(const char *host, int af, struct getnamaddr *info);
diff --git a/libc/dns/net/sethostent.c b/libc/dns/net/sethostent.c
index a743a543e..cbf091167 100644
--- a/libc/dns/net/sethostent.c
+++ b/libc/dns/net/sethostent.c
@@ -55,6 +55,8 @@ __RCSID("$NetBSD: sethostent.c,v 1.20 2014/03/17 13:24:23 christos Exp $");
#include "hostent.h"
#include "resolv_private.h"
+#include "hosts_cache.h"
+
#define ALIGNBYTES (sizeof(uintptr_t) - 1)
#define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES)
@@ -112,6 +114,11 @@ _hf_gethtbyname(void *rv, void *cb_data, va_list ap)
/* NOSTRICT skip string len */(void)va_arg(ap, int);
af = va_arg(ap, int);
+ int rc = hc_gethtbyname(name, af, info);
+ if (rc != NETDB_INTERNAL) {
+ return (rc == NETDB_SUCCESS ? NS_SUCCESS : NS_NOTFOUND);
+ }
+
#if 0
{
res_state res = __res_get_state();
diff --git a/libc/include/arpa/inet.h b/libc/include/arpa/inet.h
index db054c9e1..7716b9445 100644
--- a/libc/include/arpa/inet.h
+++ b/libc/include/arpa/inet.h
@@ -33,6 +33,7 @@
#include <stdint.h>
#include <sys/cdefs.h>
#include <sys/types.h>
+#include <inaddr.h>
__BEGIN_DECLS
diff --git a/libc/include/bits/in_addr.h b/libc/include/bits/in_addr.h
index 30eb04b66..3e46dad2b 100644
--- a/libc/include/bits/in_addr.h
+++ b/libc/include/bits/in_addr.h
@@ -36,8 +36,7 @@
#include <sys/cdefs.h>
#include <stdint.h>
-/** An integral type representing an IPv4 address. */
-typedef uint32_t in_addr_t;
+#include <inaddr.h>
/** A structure representing an IPv4 address. */
struct in_addr {
diff --git a/libc/include/inaddr.h b/libc/include/inaddr.h
new file mode 100644
index 000000000..524addabf
--- /dev/null
+++ b/libc/include/inaddr.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _INADDR_H_
+#define _INADDR_H_
+
+#include <stdint.h>
+
+typedef uint32_t in_addr_t;
+
+#endif
diff --git a/linker/Android.bp b/linker/Android.bp
index f75088d60..582a9e41e 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -57,6 +57,10 @@ cc_object {
// Configuration for the linker binary and any of its static libraries.
cc_defaults {
name: "linker_defaults",
+ defaults: [
+ "process_sdk_version_overrides_defaults",
+ "shim_libs_defaults",
+ ],
arch: {
arm: {
cflags: ["-D__work_around_b_24465209__"],
diff --git a/linker/linker.cpp b/linker/linker.cpp
index f24167722..c87118b9f 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -644,6 +644,68 @@ enum walk_action_result_t : uint32_t {
kWalkSkip = 2
};
+#ifdef LD_SHIM_LIBS
+// g_ld_all_shim_libs maintains the references to memory as it used
+// in the soinfo structures and in the g_active_shim_libs list.
+
+static std::vector<ShimDescriptor> g_ld_all_shim_libs;
+
+// g_active_shim_libs are all shim libs that are still eligible
+// to be loaded. We must remove a shim lib from the list before
+// we load the library to avoid recursive loops (load shim libA
+// for libB where libA also links against libB).
+static linked_list_t<const ShimDescriptor> g_active_shim_libs;
+
+static void reset_g_active_shim_libs(void) {
+ g_active_shim_libs.clear();
+ for (const auto& pair : g_ld_all_shim_libs) {
+ g_active_shim_libs.push_back(&pair);
+ }
+}
+
+void parse_LD_SHIM_LIBS(const char* path) {
+ g_ld_all_shim_libs.clear();
+ if (path != nullptr) {
+ for (const auto& pair : android::base::Split(path, ":")) {
+ std::vector<std::string> pieces = android::base::Split(pair, "|");
+ if (pieces.size() != 2) continue;
+ // If the path can be resolved, resolve it
+ char buf[PATH_MAX];
+ std::string resolved_path = pieces[0];
+ if (access(pieces[0].c_str(), R_OK) != 0) {
+ if (errno == ENOENT) {
+ // no need to test for non-existing path. skip.
+ continue;
+ }
+ // If not accessible, don't call realpath as it will just cause
+ // SELinux denial spam. Use the path unresolved.
+ } else if (realpath(pieces[0].c_str(), buf) != nullptr) {
+ resolved_path = buf;
+ }
+ auto desc = std::pair<std::string, std::string>(resolved_path, pieces[1]);
+ g_ld_all_shim_libs.push_back(desc);
+ }
+ }
+ reset_g_active_shim_libs();
+}
+
+std::vector<const ShimDescriptor*> shim_matching_pairs(const char* path) {
+ std::vector<const ShimDescriptor*> matched_pairs;
+
+ g_active_shim_libs.for_each([&](const ShimDescriptor* a_pair) {
+ if (a_pair->first == path) {
+ matched_pairs.push_back(a_pair);
+ }
+ });
+
+ g_active_shim_libs.remove_if([&](const ShimDescriptor* a_pair) {
+ return a_pair->first == path;
+ });
+
+ return matched_pairs;
+}
+#endif
+
// This function walks down the tree of soinfo dependencies
// in breadth-first order and
// * calls action(soinfo* si) for each node, and
@@ -1279,6 +1341,12 @@ static bool load_library(android_namespace_t* ns,
}
#endif
+#ifdef LD_SHIM_LIBS
+ for_each_matching_shim(realpath.c_str(), [&](const char* name) {
+ load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
+ });
+#endif
+
for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
LD_LOG(kLogDlopen, "load_library(ns=%s, task=%s): Adding DT_NEEDED task: %s",
ns->get_name(), task->get_name(), name);
@@ -2181,6 +2249,9 @@ void* do_dlopen(const char* name, int flags,
}
ProtectedDataGuard guard;
+#ifdef LD_SHIM_LIBS
+ reset_g_active_shim_libs();
+#endif
soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
loading_trace.End();
@@ -3530,7 +3601,18 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable
}
}
- set_application_target_sdk_version(config->target_sdk_version());
+ uint32_t target_sdk = config->target_sdk_version();
+#ifdef SDK_VERSION_OVERRIDES
+ for (const auto& entry : android::base::Split(SDK_VERSION_OVERRIDES, " ")) {
+ auto splitted = android::base::Split(entry, "=");
+ if (splitted.size() == 2 && splitted[0] == executable_path) {
+ target_sdk = static_cast<uint32_t>(std::stoul(splitted[1]));
+ break;
+ }
+ }
+ DEBUG("Target SDK for %s = %d", executable_path, target_sdk);
+#endif
+ set_application_target_sdk_version(target_sdk);
std::vector<android_namespace_t*> created_namespaces;
created_namespaces.reserve(namespaces.size());
diff --git a/linker/linker.h b/linker/linker.h
index 2da14041b..dce6c5e4c 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -42,6 +42,10 @@
#include "linker_logger.h"
#include "linker_soinfo.h"
+#ifdef LD_SHIM_LIBS
+#include "linker_debug.h"
+#endif
+
#include <string>
#include <vector>
@@ -77,6 +81,22 @@ soinfo* find_containing_library(const void* p);
int open_executable(const char* path, off64_t* file_offset, std::string* realpath);
+#ifdef LD_SHIM_LIBS
+typedef std::pair<std::string, std::string> ShimDescriptor;
+void parse_LD_SHIM_LIBS(const char* path);
+std::vector<const ShimDescriptor*> shim_matching_pairs(const char* path);
+
+template<typename F>
+void for_each_matching_shim(const char* path, F action) {
+ if (path == nullptr) return;
+ INFO("Finding shim libs for \"%s\"", path);
+ for (const auto& one_pair : shim_matching_pairs(path)) {
+ INFO("Injecting shim lib \"%s\" as needed for %s", one_pair->second.c_str(), path);
+ action(one_pair->second.c_str());
+ }
+}
+#endif
+
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
void do_android_update_LD_LIBRARY_PATH(const char* ld_library_path);
void* do_dlopen(const char* name,
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 98af54ac2..22c034b61 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -417,6 +417,11 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load
parse_LD_LIBRARY_PATH(ldpath_env);
parse_LD_PRELOAD(ldpreload_env);
+#ifdef LD_SHIM_LIBS
+ // Read from TARGET_LD_SHIM_LIBS
+ parse_LD_SHIM_LIBS(LD_SHIM_LIBS);
+#endif
+
std::vector<android_namespace_t*> namespaces = init_default_namespaces(exe_info.path.c_str());
if (!si->prelink_image()) __linker_cannot_link(g_argv[0]);
@@ -442,6 +447,12 @@ static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load
++ld_preloads_count;
}
+#ifdef LD_SHIM_LIBS
+ for_each_matching_shim(si->get_realpath(), [&](const char* name) {
+ needed_library_name_list.push_back(name);
+ });
+#endif
+
for_each_dt_needed(si, [&](const char* name) {
needed_library_name_list.push_back(name);
});