Merge "Add seccomp support library"
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index ec48870..ebdae83 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -11,6 +11,26 @@
and “pax-utils” for scanelf.
+## How we manage incompatible changes
+
+Our general practice with dynamic linker behavior changes is that they
+will be tied to an app's target API level:
+
+* Below the affected API level we'll preserve the old behavior or issue
+a warning, as appropriate.
+
+* At the affected API level and above, we’ll refuse to load the library.
+
+* Warnings about any behavior change that will affect a library if you
+increase your target API level will appear in logcat when that library
+is loaded, even if you're not yet targeting that API level.
+
+* On a developer preview build, dynamic linker warnings will also show up
+as toasts. Experience has shown that many developers don’t habitually
+check logcat for warnings until their app stops functioning, so the
+toasts help bring some visibility to the issues before it's too late.
+
+
## Changes to library search order
We have made various fixes to library search order when resolving symbols.
diff --git a/benchmarks/time_benchmark.cpp b/benchmarks/time_benchmark.cpp
index 4a5c2da..c90dfad 100644
--- a/benchmarks/time_benchmark.cpp
+++ b/benchmarks/time_benchmark.cpp
@@ -40,7 +40,7 @@
static void BM_time_gettimeofday(benchmark::State& state) {
timeval tv;
while (state.KeepRunning()) {
- gettimeofday(&tv, NULL);
+ gettimeofday(&tv, nullptr);
}
}
BENCHMARK(BM_time_gettimeofday);
@@ -48,14 +48,31 @@
void BM_time_gettimeofday_syscall(benchmark::State& state) {
timeval tv;
while (state.KeepRunning()) {
- syscall(__NR_gettimeofday, &tv, NULL);
+ syscall(__NR_gettimeofday, &tv, nullptr);
}
}
BENCHMARK(BM_time_gettimeofday_syscall);
void BM_time_time(benchmark::State& state) {
while (state.KeepRunning()) {
- time(NULL);
+ time(nullptr);
}
}
BENCHMARK(BM_time_time);
+
+void BM_time_localtime(benchmark::State& state) {
+ time_t t = time(nullptr);
+ while (state.KeepRunning()) {
+ localtime(&t);
+ }
+}
+BENCHMARK(BM_time_localtime);
+
+void BM_time_localtime_r(benchmark::State& state) {
+ time_t t = time(nullptr);
+ while (state.KeepRunning()) {
+ struct tm tm;
+ localtime_r(&t, &tm);
+ }
+}
+BENCHMARK(BM_time_localtime_r);
diff --git a/libc/Android.bp b/libc/Android.bp
index 3f7e94c..4df94a0 100644
--- a/libc/Android.bp
+++ b/libc/Android.bp
@@ -1201,6 +1201,14 @@
name: "libc_bionic",
}
+genrule {
+ name: "generated_android_ids",
+ out: ["generated_android_ids.h"],
+ srcs: [":android_filesystem_config_header"],
+ tool_files: ["fs_config_generator.py"],
+ cmd: "$(location fs_config_generator.py) aidarray $(in) > $(out)",
+}
+
// ========================================================
// libc_bionic_ndk.a- The portions of libc_bionic that can
// be safely used in libc_ndk.a (no troublesome global data
@@ -1389,6 +1397,7 @@
local_include_dirs: ["stdio"],
include_dirs: ["bionic/libstdc++/include"],
name: "libc_bionic_ndk",
+ generated_headers: ["generated_android_ids"],
}
// ========================================================
diff --git a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S b/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
index 1d152bb..4ff982b 100644
--- a/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
+++ b/libc/arch-arm/cortex-a7/bionic/memcpy_base.S
@@ -101,16 +101,38 @@
vld1.8 {d0}, [r1]!
vst1.8 {d0}, [r0, :64]!
-2: // Make sure we have at least 64 bytes to copy.
+2: cmp r2, #256
+ ble .L_copy_loop
+
+ // Make sure DST is 64 BYTE aligned.
+ rsb r3, r0, #0
+ ands r3, r3, #0x30
+ beq .L_copy_loop
+
+ sub r2, r2, r3
+ cmp r3, #0x10
+ beq .L_copy_16
+
+ vld1.8 {d0 - d3}, [r1]!
+ vst1.8 {d0 - d3}, [r0, :128]!
+ ands r3, r3, #0x10
+ beq .L_copy_loop
+
+.L_copy_16:
+ vld1.8 {d0, d1}, [r1]!
+ vst1.8 {d0, d1}, [r0, :128]!
+
+.L_copy_loop:
+ // Make sure we have at least 64 bytes to copy.
subs r2, r2, #64
blo 2f
1: // The main loop copies 64 bytes at a time.
vld1.8 {d0 - d3}, [r1]!
- vld1.8 {d4 - d7}, [r1]!
+ vst1.8 {d0 - d3}, [r0, :128]!
pld [r1, #(64*4)]
subs r2, r2, #64
- vst1.8 {d0 - d3}, [r0, :128]!
+ vld1.8 {d4 - d7}, [r1]!
vst1.8 {d4 - d7}, [r0, :128]!
bhs 1b
diff --git a/libc/bionic/__libc_current_sigrtmin.cpp b/libc/bionic/__libc_current_sigrtmin.cpp
index 16b037d..7c93267 100644
--- a/libc/bionic/__libc_current_sigrtmin.cpp
+++ b/libc/bionic/__libc_current_sigrtmin.cpp
@@ -31,7 +31,8 @@
// POSIX timers use __SIGRTMIN + 0.
// libbacktrace uses __SIGRTMIN + 1.
// libcore uses __SIGRTMIN + 2.
+// __SIGRTMIN + 3 is reserved for triggering native stack dumps.
int __libc_current_sigrtmin(void) {
- return __SIGRTMIN + 3;
+ return __SIGRTMIN + 4;
}
diff --git a/libc/bionic/grp_pwd.cpp b/libc/bionic/grp_pwd.cpp
index db0f777..e99eaca 100644
--- a/libc/bionic/grp_pwd.cpp
+++ b/libc/bionic/grp_pwd.cpp
@@ -43,6 +43,9 @@
#include "private/libc_logging.h"
#include "private/ThreadLocalBuffer.h"
+// Generated android_ids array
+#include "generated_android_ids.h"
+
// POSIX seems to envisage an implementation where the <pwd.h> functions are
// implemented by brute-force searching with getpwent(3), and the <grp.h>
// functions are implemented similarly with getgrent(3). This means that it's
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index e925d23..5aefbaf 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -56,6 +56,7 @@
#include "private/bionic_futex.h"
#include "private/bionic_lock.h"
#include "private/bionic_macros.h"
+#include "private/bionic_sdk_version.h"
#include "private/libc_logging.h"
static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
@@ -1265,6 +1266,11 @@
const prop_info *__system_property_find_nth(unsigned n)
{
+ if (bionic_get_application_target_sdk_version() >= __ANDROID_API_O__) {
+ __libc_fatal("__system_property_find_nth is not supported since Android O,"
+ " please use __system_property_foreach instead.");
+ }
+
find_nth_cookie cookie(n);
const int err = __system_property_foreach(find_nth_fn, &cookie);
diff --git a/libc/fs_config_generator.py b/libc/fs_config_generator.py
new file mode 120000
index 0000000..aafb7dc
--- /dev/null
+++ b/libc/fs_config_generator.py
@@ -0,0 +1 @@
+../../build/tools/fs_config/fs_config_generator.py
\ No newline at end of file
diff --git a/libc/include/dlfcn.h b/libc/include/dlfcn.h
index 9aa4a1f..b8f3cec 100644
--- a/libc/include/dlfcn.h
+++ b/libc/include/dlfcn.h
@@ -29,6 +29,7 @@
#ifndef __DLFCN_H__
#define __DLFCN_H__
+#include <stdint.h>
#include <sys/cdefs.h>
__BEGIN_DECLS
diff --git a/libc/include/sys/system_properties.h b/libc/include/sys/system_properties.h
index d3e0d8d..faed9a0 100644
--- a/libc/include/sys/system_properties.h
+++ b/libc/include/sys/system_properties.h
@@ -81,7 +81,8 @@
** is inefficient and order of results may change from call
** to call.
*/
-const prop_info *__system_property_find_nth(unsigned n);
+const prop_info *__system_property_find_nth(unsigned n)
+ __REMOVED_IN(26);
/* Pass a prop_info for each system property to the provided
** callback. Use __system_property_read() to read the value
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index f9c5ede..3ff7ead 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -186,19 +186,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__timer_create; # arm x86 mips
__timer_delete; # arm x86 mips
@@ -1535,8 +1532,15 @@
wcswcs; # arm x86 mips
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index 179d8bf..a696c41 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -131,19 +131,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__umask_chk; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
__vsnprintf_chk; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
@@ -1252,8 +1249,15 @@
gMallocLeakZygoteChild;
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index f122937..391c65c 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -187,19 +187,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__timer_create; # arm x86 mips
__timer_delete; # arm x86 mips
@@ -1561,8 +1558,15 @@
wcswcs; # arm x86 mips
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index a969703..c89b4ad 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -183,19 +183,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__timer_create; # arm x86 mips
__timer_delete; # arm x86 mips
@@ -1376,8 +1373,15 @@
wcswcs; # arm x86 mips
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index 179d8bf..a696c41 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -131,19 +131,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__umask_chk; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
__vsnprintf_chk; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
@@ -1252,8 +1249,15 @@
gMallocLeakZygoteChild;
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index dfa839e..51b222d 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -183,19 +183,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__timer_create; # arm x86 mips
__timer_delete; # arm x86 mips
@@ -1375,8 +1372,15 @@
wcswcs; # arm x86 mips
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index 179d8bf..a696c41 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -131,19 +131,16 @@
__sym_ntos;
__sym_ston;
__system_properties_init;
- __system_property_add; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area__; # var
__system_property_area_init; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_area_serial; # introduced=23
__system_property_find;
- __system_property_find_nth;
__system_property_foreach; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_get;
__system_property_read;
__system_property_serial; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_set; # introduced-arm=12 introduced-arm64=21 introduced-mips=12 introduced-mips64=21 introduced-x86=12 introduced-x86_64=21
__system_property_set_filename; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
- __system_property_update; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__system_property_wait_any; # introduced-arm=19 introduced-arm64=21 introduced-mips=19 introduced-mips64=21 introduced-x86=19 introduced-x86_64=21
__umask_chk; # introduced-arm=18 introduced-arm64=21 introduced-mips=18 introduced-mips64=21 introduced-x86=18 introduced-x86_64=21
__vsnprintf_chk; # introduced-arm=17 introduced-arm64=21 introduced-mips=17 introduced-mips64=21 introduced-x86=17 introduced-x86_64=21
@@ -1252,8 +1249,15 @@
gMallocLeakZygoteChild;
} LIBC_O;
+LIBC_DEPRECATED {
+ global:
+ __system_property_find_nth;
+};
+
LIBC_PLATFORM {
global:
+ __system_property_add;
+ __system_property_update;
android_net_res_stats_get_info_for_net;
android_net_res_stats_aggregate;
android_net_res_stats_get_usable_servers;
diff --git a/libc/private/CFIShadow.h b/libc/private/CFIShadow.h
new file mode 100644
index 0000000..26351db
--- /dev/null
+++ b/libc/private/CFIShadow.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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.
+ */
+
+#ifndef CFI_SHADOW_H
+#define CFI_SHADOW_H
+
+#include <stdint.h>
+
+#include "private/bionic_page.h"
+#include "private/bionic_macros.h"
+
+constexpr unsigned kLibraryAlignmentBits = 18;
+constexpr size_t kLibraryAlignment = 1UL << kLibraryAlignmentBits;
+
+// This class defines format of the shadow region for Control Flow Integrity support.
+// See documentation in http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#shared-library-support.
+//
+// CFI shadow is effectively a very fast and specialized implementation of dladdr: given an address that
+// belongs to a shared library or an executable, it can find the address of a specific export in that
+// library (a function called "__cfi_check"). This is only guaranteed to work for
+// addresses of possible CFI targets inside a library: indirectly called functions and virtual
+// tables. A random address inside a library may not work in the future (but it does in the current
+// implementation).
+//
+// Implementation is a sparse array of uint16_t where each element describes the location of
+// __cfi_check for a 2**kShadowGranularity range of memory. Array elements (called "shadow values"
+// below) are interpreted as follows.
+//
+// For an address P and corresponding shadow value V, the address of __cfi_check is calculated as
+// align_up(P, 2**kShadowGranularity) - (V - 2) * (2 ** kCfiCheckGranularity)
+//
+// Special shadow values:
+// 0 = kInvalidShadow, this memory range has no valid CFI targets.
+// 1 = kUncheckedShadow, any address is this memory range is a valid CFI target
+//
+// Loader requirement: each aligned 2**kShadowGranularity region of address space may contain at
+// most one DSO.
+// Compiler requirement: __cfi_check is aligned at kCfiCheckGranularity.
+// Compiler requirement: __cfi_check for a given DSO is located below any CFI target for that DSO.
+class CFIShadow {
+ public:
+ static constexpr uintptr_t kShadowGranularity = kLibraryAlignmentBits;
+ static constexpr uintptr_t kCfiCheckGranularity = 12;
+
+ // Each uint16_t element of the shadow corresponds to this much application memory.
+ static constexpr uintptr_t kShadowAlign = 1UL << kShadowGranularity;
+
+ // Alignment of __cfi_check.
+ static constexpr uintptr_t kCfiCheckAlign = 1UL << kCfiCheckGranularity; // 4K
+
+#if defined(__aarch64__)
+ static constexpr uintptr_t kMaxTargetAddr = 0x7fffffffff;
+#elif defined (__LP64__)
+ static constexpr uintptr_t kMaxTargetAddr = 0x7fffffffffff;
+#else
+ static constexpr uintptr_t kMaxTargetAddr = 0xffffffff;
+#endif
+
+ // Shadow is 2 -> 2**kShadowGranularity.
+ static constexpr uintptr_t kShadowSize =
+ align_up((kMaxTargetAddr >> (kShadowGranularity - 1)), PAGE_SIZE);
+
+ // Returns offset inside the shadow region for an address.
+ static constexpr uintptr_t MemToShadowOffset(uintptr_t x) {
+ return (x >> kShadowGranularity) << 1;
+ }
+
+ typedef int (*CFICheckFn)(uint64_t, void *, void *);
+
+ public:
+ enum ShadowValues : uint16_t {
+ kInvalidShadow = 0, // Not a valid CFI target.
+ kUncheckedShadow = 1, // Unchecked, valid CFI target.
+ kRegularShadowMin = 2 // This and all higher values encode a negative offset to __cfi_check in
+ // the units of kCfiCheckGranularity, starting with 0 at
+ // kRegularShadowMin.
+ };
+};
+
+#endif // CFI_SHADOW_H
diff --git a/libc/private/bionic_macros.h b/libc/private/bionic_macros.h
index d5c5b9c..303218e 100644
--- a/libc/private/bionic_macros.h
+++ b/libc/private/bionic_macros.h
@@ -48,11 +48,11 @@
? (1UL << (64 - __builtin_clzl(static_cast<unsigned long>(value)))) \
: (1UL << (32 - __builtin_clz(static_cast<unsigned int>(value)))))
-static inline uintptr_t align_down(uintptr_t p, size_t align) {
+static constexpr uintptr_t align_down(uintptr_t p, size_t align) {
return p & ~(align - 1);
}
-static inline uintptr_t align_up(uintptr_t p, size_t align) {
+static constexpr uintptr_t align_up(uintptr_t p, size_t align) {
return (p + align - 1) & ~(align - 1);
}
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index 74411f7..723e4f2 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -1327,21 +1327,22 @@
// If that's not set, look at the "persist.sys.timezone" system property.
if (name == NULL) {
+ // The lookup is the most expensive part by several orders of magnitude, so we cache it.
+ // We check for null more than once because the system property may not have been set
+ // yet, so our first lookup may fail.
static const prop_info* pi;
+ if (pi == NULL) pi = __system_property_find("persist.sys.timezone");
- if (!pi) {
- pi = __system_property_find("persist.sys.timezone");
- }
if (pi) {
- static char buf[PROP_VALUE_MAX];
- static uint32_t s = -1;
- static bool ok = false;
+ // If the property hasn't changed since the last time we read it, there's nothing else to do.
+ static uint32_t last_serial = -1;
uint32_t serial = __system_property_serial(pi);
- if (serial != s) {
- ok = __system_property_read(pi, 0, buf) > 0;
- s = serial;
- }
- if (ok) {
+ if (serial == last_serial) return;
+
+ // Otherwise read the new value...
+ last_serial = serial;
+ char buf[PROP_VALUE_MAX];
+ if (__system_property_read(pi, NULL, buf) > 0) {
// POSIX and Java disagree about the sign in a timezone string. For POSIX, "GMT+3" means
// "3 hours west/behind", but for Java it means "3 hours east/ahead". Since (a) Java is
// the one that matches human expectations and (b) this system property is used directly
@@ -1532,16 +1533,22 @@
#endif
static struct tm *
-localtime_tzset(time_t const *timep, struct tm *tmp, bool setname)
+localtime_tzset(time_t const *timep, struct tm *tmp)
{
int err = lock();
if (err) {
errno = err;
return NULL;
}
- if (setname || !lcl_is_set)
- tzset_unlocked();
- tmp = localsub(lclptr, timep, setname, tmp);
+
+ // http://b/31339449: POSIX says localtime(3) acts as if it called tzset(3), but upstream
+ // and glibc both think it's okay for localtime_r(3) to not do so (presumably because of
+ // the "not required to set tzname" clause). It's unclear that POSIX actually intended this,
+ // the BSDs disagree with glibc, and it's confusing to developers to have localtime_r(3)
+ // behave differently than other time zone-sensitive functions in <time.h>.
+ tzset_unlocked();
+
+ tmp = localsub(lclptr, timep, true, tmp);
unlock();
return tmp;
}
@@ -1549,13 +1556,13 @@
struct tm *
localtime(const time_t *timep)
{
- return localtime_tzset(timep, &tm, true);
+ return localtime_tzset(timep, &tm);
}
struct tm *
localtime_r(const time_t *timep, struct tm *tmp)
{
- return localtime_tzset(timep, tmp, false);
+ return localtime_tzset(timep, tmp);
}
/*
diff --git a/libdl/Android.bp b/libdl/Android.bp
index a0aeeff..013554a 100644
--- a/libdl/Android.bp
+++ b/libdl/Android.bp
@@ -44,7 +44,7 @@
version_script: "libdl.x86_64.map",
},
},
- srcs: ["libdl.c"],
+ srcs: ["libdl.c", "libdl_cfi.cpp"],
cflags: [
"-Wall",
"-Wextra",
@@ -61,6 +61,9 @@
allow_undefined_symbols: true,
system_shared_libs: [],
+ // For private/CFIShadow.h.
+ include_dirs: ["bionic/libc"],
+
// This is placeholder library the actual implementation is (currently)
// provided by the linker.
shared_libs: [ "ld-android" ],
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index 1fdc1a7..f452641 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -36,6 +36,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -35,6 +35,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index 0a82a2e..cc044fe 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -35,6 +35,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -35,6 +35,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -35,6 +35,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -35,6 +35,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 28d2613..62f5ff4 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -35,6 +35,9 @@
LIBC_PLATFORM {
global:
+ __cfi_init;
+ __cfi_slowpath;
+ __cfi_slowpath_diag;
android_dlwarning;
android_get_application_target_sdk_version;
android_set_application_target_sdk_version;
diff --git a/libdl/libdl_cfi.cpp b/libdl/libdl_cfi.cpp
new file mode 100644
index 0000000..362b093
--- /dev/null
+++ b/libdl/libdl_cfi.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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 <sys/mman.h>
+
+#include "private/CFIShadow.h"
+
+__attribute__((__weak__, visibility("default"))) extern "C" void __loader_cfi_fail(
+ uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc);
+
+// Base address of the CFI shadow. Passed down from the linker in __cfi_init()
+// and does not change after that. The contents of the shadow change in
+// dlopen/dlclose.
+static struct {
+ uintptr_t v;
+ char padding[PAGE_SIZE - sizeof(v)];
+} shadow_base_storage alignas(PAGE_SIZE);
+
+extern "C" uintptr_t* __cfi_init(uintptr_t shadow_base) {
+ shadow_base_storage.v = shadow_base;
+ static_assert(sizeof(shadow_base_storage) == PAGE_SIZE, "");
+ mprotect(&shadow_base_storage, PAGE_SIZE, PROT_READ);
+ return &shadow_base_storage.v;
+}
+
+static uint16_t shadow_load(void* p) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(p);
+ uintptr_t ofs = CFIShadow::MemToShadowOffset(addr);
+ if (ofs > CFIShadow::kShadowSize) return CFIShadow::kInvalidShadow;
+ return *reinterpret_cast<uint16_t*>(shadow_base_storage.v + ofs);
+}
+
+static uintptr_t cfi_check_addr(uint16_t v, void* Ptr) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(Ptr);
+ uintptr_t aligned_addr = align_up(addr, CFIShadow::kShadowAlign);
+ uintptr_t p = aligned_addr - (static_cast<uintptr_t>(v - CFIShadow::kRegularShadowMin)
+ << CFIShadow::kCfiCheckGranularity);
+#ifdef __arm__
+ // Assume Thumb encoding. FIXME: force thumb at compile time?
+ p++;
+#endif
+ return p;
+}
+
+static inline void cfi_slowpath_common(uint64_t CallSiteTypeId, void* Ptr, void* DiagData) {
+ uint16_t v = shadow_load(Ptr);
+ switch (v) {
+ case CFIShadow::kInvalidShadow:
+ __loader_cfi_fail(CallSiteTypeId, Ptr, DiagData, __builtin_return_address(0));
+ break;
+ case CFIShadow::kUncheckedShadow:
+ break;
+ default:
+ reinterpret_cast<CFIShadow::CFICheckFn>(cfi_check_addr(v, Ptr))(CallSiteTypeId, Ptr, DiagData);
+ }
+}
+
+extern "C" void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr) {
+ cfi_slowpath_common(CallSiteTypeId, Ptr, nullptr);
+}
+
+extern "C" void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData) {
+ cfi_slowpath_common(CallSiteTypeId, Ptr, DiagData);
+}
diff --git a/linker/Android.bp b/linker/Android.bp
index a3b9cb2..6d93571 100644
--- a/linker/Android.bp
+++ b/linker/Android.bp
@@ -18,6 +18,7 @@
"linker.cpp",
"linker_block_allocator.cpp",
"linker_dlwarning.cpp",
+ "linker_cfi.cpp",
"linker_gdb_support.cpp",
"linker_globals.cpp",
"linker_libc_support.c",
@@ -116,6 +117,7 @@
"libz",
"liblog",
"libc++_static",
+ "libdebuggerd_handler",
// Important: The liblinker_malloc should be the last library in the list
// to overwrite any other malloc implementations by other static libraries.
diff --git a/linker/arch/arm/begin.S b/linker/arch/arm/begin.S
index 8cb599b..480047a 100644
--- a/linker/arch/arm/begin.S
+++ b/linker/arch/arm/begin.S
@@ -33,5 +33,5 @@
bl __linker_init
/* linker init returns the _entry address in the main image */
- mov pc, r0
+ bx r0
END(_start)
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index bb7b1ca..0092179 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -15,6 +15,7 @@
*/
#include "linker.h"
+#include "linker_cfi.h"
#include "linker_globals.h"
#include "linker_dlwarning.h"
@@ -189,6 +190,10 @@
return result;
}
+void __cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *CallerPc) {
+ CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
+}
+
// name_offset: starting index of the name in libdl_info.strtab
#define ELF32_SYM_INITIALIZER(name_offset, value, shndx) \
{ name_offset, \
@@ -225,11 +230,11 @@
// 012345678901234 567890123456789012345678901234567 8901234567890123456789012345678901 2345678901234567 89
"et_sdk_version\0__loader_android_init_namespaces\0__loader_android_create_namespace\0__loader_dlvsym\0__"
// 4*
- // 0000000000111111111122222 2222233333333334444444 4445555555555666666666677777777778 8888888889999999 999
- // 0123456789012345678901234 5678901234567890123456 7890123456789012345678901234567890 1234567890123456 789
- "loader_android_dlwarning\0"
+ // 0000000000111111111122222 222223333333333444 4444444555555555566666666667777 77777788888888889999999999
+ // 0123456789012345678901234 567890123456789012 3456789012345678901234567890123 45678901234567890123456789
+ "loader_android_dlwarning\0__loader_cfi_fail\0"
#if defined(__arm__)
- // 425
+ // 443
"__loader_dl_unwind_find_exidx\0"
#endif
;
@@ -255,8 +260,9 @@
ELFW(SYM_INITIALIZER)(348, &__android_create_namespace, 1),
ELFW(SYM_INITIALIZER)(382, &__dlvsym, 1),
ELFW(SYM_INITIALIZER)(398, &__android_dlwarning, 1),
+ ELFW(SYM_INITIALIZER)(425, &__cfi_fail, 1),
#if defined(__arm__)
- ELFW(SYM_INITIALIZER)(425, &__dl_unwind_find_exidx, 1),
+ ELFW(SYM_INITIALIZER)(443, &__dl_unwind_find_exidx, 1),
#endif
};
@@ -273,9 +279,9 @@
// Note that adding any new symbols here requires stubbing them out in libdl.
static unsigned g_libdl_buckets[1] = { 1 };
#if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
#else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
#endif
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linker.cpp b/linker/linker.cpp
index fc8d1ef..83bd9f3 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -48,6 +48,7 @@
#include "linker.h"
#include "linker_block_allocator.h"
+#include "linker_cfi.h"
#include "linker_gdb_support.h"
#include "linker_globals.h"
#include "linker_debug.h"
@@ -105,6 +106,12 @@
// Is ASAN enabled?
static bool g_is_asan = false;
+static CFIShadowWriter g_cfi_shadow;
+
+CFIShadowWriter* get_cfi_shadow() {
+ return &g_cfi_shadow;
+}
+
static bool is_system_library(const std::string& realpath) {
for (const auto& dir : g_default_namespace.get_default_library_paths()) {
if (file_is_in_dir(realpath, dir)) {
@@ -1226,7 +1233,7 @@
// target_sdk_version (*candidate != nullptr)
// 2. The library was not found by soname (*candidate is nullptr)
static bool find_loaded_library_by_soname(android_namespace_t* ns,
- const char* name, soinfo** candidate) {
+ const char* name, soinfo** candidate) {
*candidate = nullptr;
// Ignore filename with path.
@@ -1504,7 +1511,8 @@
bool linked = local_group.visit([&](soinfo* si) {
if (!si->is_linked()) {
- if (!si->link_image(global_group, local_group, extinfo)) {
+ if (!si->link_image(global_group, local_group, extinfo) ||
+ !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
return false;
}
}
@@ -1656,6 +1664,7 @@
while ((si = local_unload_list.pop_front()) != nullptr) {
notify_gdb_of_unload(si);
+ get_cfi_shadow()->BeforeUnload(si);
soinfo_free(si);
}
diff --git a/linker/linker.h b/linker/linker.h
index c65d503..7746982 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -103,6 +103,8 @@
soinfo* get_libdl_info(const char* linker_path);
+soinfo* find_containing_library(const void* p);
+
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,
@@ -125,6 +127,10 @@
int do_dladdr(const void* addr, Dl_info* info);
+// void ___cfi_slowpath(uint64_t CallSiteTypeId, void *Ptr, void *Ret);
+// void ___cfi_slowpath_diag(uint64_t CallSiteTypeId, void *Ptr, void *DiagData, void *Ret);
+void ___cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *Ret);
+
void set_application_target_sdk_version(uint32_t target);
uint32_t get_application_target_sdk_version();
@@ -163,7 +169,4 @@
const char* permitted_when_isolated_path,
android_namespace_t* parent_namespace);
-constexpr unsigned kLibraryAlignmentBits = 18;
-constexpr size_t kLibraryAlignment = 1UL << kLibraryAlignmentBits;
-
#endif
diff --git a/linker/linker_cfi.cpp b/linker/linker_cfi.cpp
new file mode 100644
index 0000000..f788c16
--- /dev/null
+++ b/linker/linker_cfi.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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 "linker_cfi.h"
+
+#include "linker_debug.h"
+#include "linker_globals.h"
+#include "private/bionic_page.h"
+#include "private/bionic_prctl.h"
+
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <cstdint>
+
+// Update shadow without making it writable by preparing the data on the side and mremap-ing it in
+// place.
+class ShadowWrite {
+ char* shadow_start;
+ char* shadow_end;
+ char* aligned_start;
+ char* aligned_end;
+ char* tmp_start;
+
+ public:
+ ShadowWrite(uint16_t* s, uint16_t* e) {
+ shadow_start = reinterpret_cast<char*>(s);
+ shadow_end = reinterpret_cast<char*>(e);
+ aligned_start = reinterpret_cast<char*>(PAGE_START(reinterpret_cast<uintptr_t>(shadow_start)));
+ aligned_end = reinterpret_cast<char*>(PAGE_END(reinterpret_cast<uintptr_t>(shadow_end)));
+ tmp_start =
+ reinterpret_cast<char*>(mmap(nullptr, aligned_end - aligned_start, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ CHECK(tmp_start != MAP_FAILED);
+ memcpy(tmp_start, aligned_start, shadow_start - aligned_start);
+ memcpy(tmp_start + (shadow_end - aligned_start), shadow_end, aligned_end - shadow_end);
+ }
+
+ uint16_t* begin() {
+ return reinterpret_cast<uint16_t*>(tmp_start + (shadow_start - aligned_start));
+ }
+
+ uint16_t* end() {
+ return reinterpret_cast<uint16_t*>(tmp_start + (shadow_end - aligned_start));
+ }
+
+ ~ShadowWrite() {
+ size_t size = aligned_end - aligned_start;
+ mprotect(tmp_start, size, PROT_READ);
+ void* res = mremap(tmp_start, size, size, MREMAP_MAYMOVE | MREMAP_FIXED,
+ reinterpret_cast<void*>(aligned_start));
+ CHECK(res != MAP_FAILED);
+ }
+};
+
+void CFIShadowWriter::FixupVmaName() {
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, *shadow_start, kShadowSize, "cfi shadow");
+}
+
+void CFIShadowWriter::AddConstant(uintptr_t begin, uintptr_t end, uint16_t v) {
+ uint16_t* shadow_begin = MemToShadow(begin);
+ uint16_t* shadow_end = MemToShadow(end - 1) + 1;
+
+ ShadowWrite sw(shadow_begin, shadow_end);
+ std::fill(sw.begin(), sw.end(), v);
+}
+
+void CFIShadowWriter::AddUnchecked(uintptr_t begin, uintptr_t end) {
+ AddConstant(begin, end, kUncheckedShadow);
+}
+
+void CFIShadowWriter::AddInvalid(uintptr_t begin, uintptr_t end) {
+ AddConstant(begin, end, kInvalidShadow);
+}
+
+void CFIShadowWriter::Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check) {
+ CHECK((cfi_check & (kCfiCheckAlign - 1)) == 0);
+
+ // Don't fill anything below cfi_check. We can not represent those addresses
+ // in the shadow, and must make sure at codegen to place all valid call
+ // targets above cfi_check.
+ begin = std::max(begin, cfi_check) & ~(kShadowAlign - 1);
+ uint16_t* shadow_begin = MemToShadow(begin);
+ uint16_t* shadow_end = MemToShadow(end - 1) + 1;
+
+ ShadowWrite sw(shadow_begin, shadow_end);
+ uint16_t sv = ((begin + kShadowAlign - cfi_check) >> kCfiCheckGranularity) + kRegularShadowMin;
+
+ // With each step of the loop below, __cfi_check address computation base is increased by
+ // 2**ShadowGranularity.
+ // To compensate for that, each next shadow value must be increased by 2**ShadowGranularity /
+ // 2**CfiCheckGranularity.
+ uint16_t sv_step = 1 << (kShadowGranularity - kCfiCheckGranularity);
+ for (uint16_t& s : sw) {
+ // If there is something there already, fall back to unchecked. This may happen in rare cases
+ // with MAP_FIXED libraries. FIXME: consider using a (slow) resolution function instead.
+ s = (s == kInvalidShadow) ? sv : kUncheckedShadow;
+ sv += sv_step;
+ }
+}
+
+static soinfo* find_libdl(soinfo* solist) {
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
+ const char* soname = si->get_soname();
+ if (soname && strcmp(soname, "libdl.so") == 0) {
+ return si;
+ }
+ }
+ return nullptr;
+}
+
+static uintptr_t soinfo_find_symbol(soinfo* si, const char* s) {
+ SymbolName name(s);
+ const ElfW(Sym) * sym;
+ if (si->find_symbol_by_name(name, nullptr, &sym) && sym) {
+ return si->resolve_symbol_address(sym);
+ }
+ return 0;
+}
+
+uintptr_t soinfo_find_cfi_check(soinfo* si) {
+ return soinfo_find_symbol(si, "__cfi_check");
+}
+
+uintptr_t CFIShadowWriter::MapShadow() {
+ void* p =
+ mmap(nullptr, kShadowSize, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
+ CHECK(p != MAP_FAILED);
+ return reinterpret_cast<uintptr_t>(p);
+}
+
+bool CFIShadowWriter::AddLibrary(soinfo* si) {
+ CHECK(shadow_start != nullptr);
+ if (si->base == 0 || si->size == 0) {
+ return true;
+ }
+ uintptr_t cfi_check = soinfo_find_cfi_check(si);
+ if (cfi_check == 0) {
+ INFO("[ CFI add 0x%zx + 0x%zx %s ]", static_cast<uintptr_t>(si->base),
+ static_cast<uintptr_t>(si->size), si->get_soname());
+ AddUnchecked(si->base, si->base + si->size);
+ return true;
+ }
+
+ INFO("[ CFI add 0x%zx + 0x%zx %s: 0x%zx ]", static_cast<uintptr_t>(si->base),
+ static_cast<uintptr_t>(si->size), si->get_soname(), cfi_check);
+#ifdef __arm__
+ // Require Thumb encoding.
+ if ((cfi_check & 1UL) != 1UL) {
+ DL_ERR("__cfi_check in not a Thumb function in the library \"%s\"", si->get_soname());
+ return false;
+ }
+ cfi_check &= ~1UL;
+#endif
+ if ((cfi_check & (kCfiCheckAlign - 1)) != 0) {
+ DL_ERR("unaligned __cfi_check in the library \"%s\"", si->get_soname());
+ return false;
+ }
+ Add(si->base, si->base + si->size, cfi_check);
+ return true;
+}
+
+// Pass the shadow mapping address to libdl.so. In return, we get an pointer to the location
+// libdl.so uses to store the address.
+bool CFIShadowWriter::NotifyLibDl(soinfo* solist, uintptr_t p) {
+ soinfo* libdl = find_libdl(solist);
+ if (libdl == nullptr) {
+ DL_ERR("CFI could not find libdl");
+ return false;
+ }
+
+ uintptr_t cfi_init = soinfo_find_symbol(libdl, "__cfi_init");
+ CHECK(cfi_init != 0);
+ shadow_start = reinterpret_cast<uintptr_t* (*)(uintptr_t)>(cfi_init)(p);
+ CHECK(shadow_start != nullptr);
+ CHECK(*shadow_start == p);
+ return true;
+}
+
+bool CFIShadowWriter::MaybeInit(soinfo* new_si, soinfo* solist) {
+ CHECK(initial_link_done);
+ // Check if CFI shadow must be initialized at this time.
+ bool found = false;
+ if (new_si == nullptr) {
+ // This is the case when we've just completed the initial link. There may have been earlier
+ // calls to MaybeInit that were skipped. Look though the entire solist.
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
+ if (soinfo_find_cfi_check(si)) {
+ found = true;
+ break;
+ }
+ }
+ } else {
+ // See if the new library uses CFI.
+ found = soinfo_find_cfi_check(new_si);
+ }
+
+ // Nothing found.
+ if (!found) {
+ return true;
+ }
+
+ // Init shadow and add all currently loaded libraries (not just the new ones).
+ if (!NotifyLibDl(solist, MapShadow()))
+ return false;
+ for (soinfo* si = solist; si != nullptr; si = si->next) {
+ if (!AddLibrary(si))
+ return false;
+ }
+ FixupVmaName();
+ return true;
+}
+
+bool CFIShadowWriter::AfterLoad(soinfo* si, soinfo* solist) {
+ if (!initial_link_done) {
+ // Too early.
+ return true;
+ }
+
+ if (shadow_start == nullptr) {
+ return MaybeInit(si, solist);
+ }
+
+ // Add the new library to the CFI shadow.
+ if (!AddLibrary(si))
+ return false;
+ FixupVmaName();
+ return true;
+}
+
+void CFIShadowWriter::BeforeUnload(soinfo* si) {
+ if (shadow_start == nullptr) return;
+ if (si->base == 0 || si->size == 0) return;
+ INFO("[ CFI remove 0x%zx + 0x%zx: %s ]", static_cast<uintptr_t>(si->base),
+ static_cast<uintptr_t>(si->size), si->get_soname());
+ AddInvalid(si->base, si->base + si->size);
+ FixupVmaName();
+}
+
+bool CFIShadowWriter::InitialLinkDone(soinfo* solist) {
+ CHECK(!initial_link_done)
+ initial_link_done = true;
+ return MaybeInit(nullptr, solist);
+}
+
+// Find __cfi_check in the caller and let it handle the problem. Since caller_pc is likely not a
+// valid CFI target, we can not use CFI shadow for lookup. This does not need to be fast, do the
+// regular symbol lookup.
+void CFIShadowWriter::CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void* CallerPc) {
+ soinfo* si = find_containing_library(CallerPc);
+ if (!si) {
+ __builtin_trap();
+ }
+
+ uintptr_t cfi_check = soinfo_find_cfi_check(si);
+ if (!cfi_check) {
+ __builtin_trap();
+ }
+
+ reinterpret_cast<CFICheckFn>(cfi_check)(CallSiteTypeId, Ptr, DiagData);
+}
diff --git a/linker/linker_cfi.h b/linker/linker_cfi.h
new file mode 100644
index 0000000..df76421
--- /dev/null
+++ b/linker/linker_cfi.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source 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.
+ */
+
+#ifndef _LINKER_CFI_H_
+#define _LINKER_CFI_H_
+
+#include "linker.h"
+#include "linker_debug.h"
+
+#include <algorithm>
+
+#include "private/CFIShadow.h"
+
+// This class keeps the contents of CFI shadow up-to-date with the current set of loaded libraries.
+// See the comment in CFIShadow.h for more context.
+// See documentation in http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html#shared-library-support.
+//
+// Shadow is mapped and initialized lazily as soon as the first CFI-enabled DSO is loaded.
+// It is updated after a set of libraries is loaded (but before any constructors are ran), and
+// before any library is unloaded.
+class CFIShadowWriter : private CFIShadow {
+ // Returns pointer to the shadow element for an address.
+ uint16_t* MemToShadow(uintptr_t x) {
+ return reinterpret_cast<uint16_t*>(*shadow_start + MemToShadowOffset(x));
+ }
+
+ // Update shadow for the address range to the given constant value.
+ void AddConstant(uintptr_t begin, uintptr_t end, uint16_t v);
+
+ // Update shadow for the address range to kUncheckedShadow.
+ void AddUnchecked(uintptr_t begin, uintptr_t end);
+
+ // Update shadow for the address range to kInvalidShadow.
+ void AddInvalid(uintptr_t begin, uintptr_t end);
+
+ // Update shadow for the address range to the given __cfi_check value.
+ void Add(uintptr_t begin, uintptr_t end, uintptr_t cfi_check);
+
+ // Add a DSO to CFI shadow.
+ bool AddLibrary(soinfo* si);
+
+ // Map CFI shadow.
+ uintptr_t MapShadow();
+
+ // Initialize CFI shadow and update its contents for everything in solist if any loaded library is
+ // CFI-enabled. If soinfos != nullptr, do an incremental check by looking only at the libraries in
+ // soinfos[]; otherwise look at the entire solist.
+ //
+ // Returns false if the shadow is already initialized. It is the caller's responsibility to update
+ // the shadow for the new libraries in that case.
+ // Otherwise, returns true and leaves the shadow either up-to-date or uninitialized.
+ bool MaybeInit(soinfo *new_si, soinfo *solist);
+
+ // Set a human readable name for the entire shadow region.
+ void FixupVmaName();
+
+ bool NotifyLibDl(soinfo *solist, uintptr_t p);
+
+ // Pointer to the shadow start address.
+ uintptr_t *shadow_start;
+
+ bool initial_link_done;
+
+ public:
+ // Update shadow after loading a set of DSOs.
+ // This function will initialize the shadow if it sees a CFI-enabled DSO for the first time.
+ // In that case it will retroactively update shadow for all previously loaded DSOs. "solist" is a
+ // pointer to the global list.
+ // This function must be called before any user code has observed the newly loaded DSO.
+ bool AfterLoad(soinfo* si, soinfo *solist);
+
+ // Update shadow before unloading a DSO.
+ void BeforeUnload(soinfo* si);
+
+ bool InitialLinkDone(soinfo *solist);
+
+ // Handle failure to locate __cfi_check for a target address.
+ static void CfiFail(uint64_t CallSiteTypeId, void* Ptr, void* DiagData, void *caller_pc);
+};
+
+CFIShadowWriter* get_cfi_shadow();
+
+#endif // _LINKER_CFI_H_
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index a5abdff..9ed7505 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -29,6 +29,7 @@
#include "linker_main.h"
#include "linker_debug.h"
+#include "linker_cfi.h"
#include "linker_gdb_support.h"
#include "linker_globals.h"
#include "linker_phdr.h"
@@ -41,7 +42,7 @@
#include "android-base/strings.h"
#include "android-base/stringprintf.h"
#ifdef __ANDROID__
-#include "debuggerd/client.h"
+#include "debuggerd/handler.h"
#endif
#include <vector>
@@ -316,9 +317,9 @@
// tombstone for them. The tombstone never provided any detail relevant to
// fixing the problem anyway, and the utility of drawing extra attention
// to the problem is non-existent at this late date.
- __libc_format_fd(STDOUT_FILENO,
+ __libc_format_fd(STDERR_FILENO,
"\"%s\": error: Android 5.0 and later only support "
- "position-independent executables (-fPIE).",
+ "position-independent executables (-fPIE).\n",
g_argv[0]);
exit(0);
}
@@ -368,6 +369,10 @@
add_vdso(args);
+ if (!get_cfi_shadow()->InitialLinkDone(solist)) {
+ __libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
+ }
+
{
ProtectedDataGuard guard;
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index a453bef..72549cc 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -42,6 +42,7 @@
#include "linker_utils.h"
#include "private/bionic_prctl.h"
+#include "private/CFIShadow.h" // For kLibraryAlignment
static int GetTargetElfMachine() {
#if defined(__arm__)
diff --git a/tests/Android.bp b/tests/Android.bp
index cb69d2b..85ae26e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -155,6 +155,8 @@
shared: {
enabled: false,
},
+
+ generated_headers: ["generated_android_ids"],
}
// -----------------------------------------------------------------------------
@@ -293,6 +295,7 @@
target: {
android: {
srcs: [
+ "cfi_test.cpp",
"dlext_test.cpp",
"libdl_test.cpp",
],
@@ -364,6 +367,8 @@
include_dirs: ["bionic/libc"],
+ stl: "libc++_static",
+
target: {
android: {
shared_libs: [
@@ -438,7 +443,7 @@
"libtinyxml2",
"liblog",
"libbase",
- "libdebuggerd_client",
+ "libdebuggerd_handler",
],
static_executable: true,
diff --git a/tests/Android.build.mk b/tests/Android.build.mk
index 9236558..266c7d7 100644
--- a/tests/Android.build.mk
+++ b/tests/Android.build.mk
@@ -102,11 +102,7 @@
$($(module)_ldlibs) \
$($(module)_ldlibs_$(build_type)) \
-ifeq ($(LOCAL_FORCE_STATIC_EXECUTABLE),true)
- LOCAL_CXX_STL := libc++_static
-else
- LOCAL_CXX_STL := libc++
-endif
+LOCAL_CXX_STL := libc++_static
ifeq ($(build_type),target)
include $(BUILD_$(build_target))
diff --git a/tests/cfi_test.cpp b/tests/cfi_test.cpp
new file mode 100644
index 0000000..0f93edb
--- /dev/null
+++ b/tests/cfi_test.cpp
@@ -0,0 +1,94 @@
+#include <gtest/gtest.h>
+#include <dlfcn.h>
+
+#include "BionicDeathTest.h"
+
+// Private libdl interface.
+extern "C" {
+void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr);
+void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData);
+}
+
+static void f() {}
+
+TEST(cfi_test, basic) {
+ void* handle;
+ handle = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+#define SYM(type, name) auto name = reinterpret_cast<type>(dlsym(handle, #name))
+ SYM(int (*)(), get_count);
+ SYM(uint64_t(*)(), get_last_type_id);
+ SYM(void* (*)(), get_last_address);
+ SYM(void* (*)(), get_last_diag);
+ SYM(void* (*)(), get_global_address);
+ SYM(void (*)(uint64_t, void*, void*), __cfi_check);
+#undef SYM
+
+ int c = get_count();
+
+ // CFI check for code inside the DSO. Can't use just any function address - this is only
+ // guaranteed to work for code addresses above __cfi_check.
+ void* code_ptr = reinterpret_cast<char*>(__cfi_check) + 1234;
+ void* diag_ptr = reinterpret_cast<void*>(5678);
+ __cfi_slowpath_diag(42, code_ptr, diag_ptr);
+ EXPECT_EQ(42U, get_last_type_id());
+ EXPECT_EQ(code_ptr, get_last_address());
+ EXPECT_EQ(diag_ptr, get_last_diag());
+ EXPECT_EQ(++c, get_count());
+
+ // __cfi_slowpath passes nullptr for the Diag argument.
+ __cfi_slowpath(42, code_ptr);
+ EXPECT_EQ(42U, get_last_type_id());
+ EXPECT_EQ(code_ptr, get_last_address());
+ EXPECT_EQ(nullptr, get_last_diag());
+ EXPECT_EQ(++c, get_count());
+
+ // CFI check for a data address inside the DSO.
+ __cfi_slowpath(43, get_global_address());
+ EXPECT_EQ(43U, get_last_type_id());
+ EXPECT_EQ(get_global_address(), get_last_address());
+ EXPECT_EQ(++c, get_count());
+
+ // CFI check for a function inside _this_ DSO. It either goes to this DSO's __cfi_check,
+ // or (if missing) is simply ignored. Any way, it does not affect the test lib's counters.
+ __cfi_slowpath(44, reinterpret_cast<void*>(&f));
+ EXPECT_EQ(43U, get_last_type_id());
+ EXPECT_EQ(get_global_address(), get_last_address());
+ EXPECT_EQ(c, get_count());
+
+ // CFI check for a stack address. This is always invalid and gets the process killed.
+ EXPECT_DEATH(__cfi_slowpath(45, reinterpret_cast<void*>(&c)), "");
+
+ // CFI check for a heap address. This is always invalid and gets the process killed.
+ void* p = malloc(4096);
+ EXPECT_DEATH(__cfi_slowpath(46, p), "");
+ free(p);
+
+ // Load the same library again.
+ void* handle2 = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_TRUE(handle2 != nullptr) << dlerror();
+ EXPECT_EQ(handle2, handle);
+
+ // Check that it is still there.
+ __cfi_slowpath(43, get_global_address());
+ EXPECT_EQ(43U, get_last_type_id());
+ EXPECT_EQ(get_global_address(), get_last_address());
+ EXPECT_EQ(++c, get_count());
+
+ dlclose(handle);
+ dlclose(handle2);
+
+ // CFI check for a function inside the unloaded DSO. This is always invalid and gets the process
+ // killed.
+ EXPECT_DEATH(__cfi_slowpath(45, reinterpret_cast<void*>(code_ptr)), "");
+}
+
+TEST(cfi_test, invalid) {
+ void* handle;
+ handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_FALSE(handle != nullptr) << dlerror();
+
+ handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
+ ASSERT_FALSE(handle != nullptr) << dlerror();
+}
diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp
index cc236f8..f8232aa 100644
--- a/tests/grp_pwd_test.cpp
+++ b/tests/grp_pwd_test.cpp
@@ -30,6 +30,9 @@
#include <private/android_filesystem_config.h>
+// Generated android_ids array
+#include "generated_android_ids.h"
+
enum uid_type_t {
TYPE_SYSTEM,
TYPE_APP
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index f0dac7c..b9ee585 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -170,6 +170,9 @@
void SetResult(TestResult result) { result_ = result; }
TestResult GetResult() const { return result_; }
+ TestResult GetExpectedResult() const {
+ return GetName().find("xfail_") == 0 ? TEST_FAILED : TEST_SUCCESS;
+ }
void SetTestTime(int64_t elapsed_time_ns) { elapsed_time_ns_ = elapsed_time_ns; }
@@ -224,6 +227,15 @@
return test_list_[test_id].GetResult();
}
+ TestResult GetExpectedTestResult(size_t test_id) const {
+ VerifyTestId(test_id);
+ return test_list_[test_id].GetExpectedResult();
+ }
+
+ bool GetTestSuccess(size_t test_id) const {
+ return GetTestResult(test_id) == GetExpectedTestResult(test_id);
+ }
+
void SetTestTime(size_t test_id, int64_t elapsed_time_ns) {
VerifyTestId(test_id);
test_list_[test_id].SetTestTime(elapsed_time_ns);
@@ -356,7 +368,7 @@
printf("%s", test_output.c_str());
TestResult result = testcase.GetTestResult(test_id);
- if (result == TEST_SUCCESS) {
+ if (result == testcase.GetExpectedTestResult(test_id)) {
ColoredPrintf(COLOR_GREEN, "[ OK ] ");
} else {
ColoredPrintf(COLOR_RED, "[ FAILED ] ");
@@ -373,10 +385,19 @@
static void OnTestEndPrint(const TestCase& testcase, size_t test_id) {
TestResult result = testcase.GetTestResult(test_id);
+ TestResult expected = testcase.GetExpectedTestResult(test_id);
if (result == TEST_SUCCESS) {
- ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ if (expected == TEST_SUCCESS) {
+ ColoredPrintf(COLOR_GREEN, "[ OK ] ");
+ } else if (expected == TEST_FAILED) {
+ ColoredPrintf(COLOR_RED, "[ XPASS ] ");
+ }
} else if (result == TEST_FAILED) {
- ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ if (expected == TEST_SUCCESS) {
+ ColoredPrintf(COLOR_RED, "[ FAILED ] ");
+ } else if (expected == TEST_FAILED) {
+ ColoredPrintf(COLOR_YELLOW, "[ XFAIL ] ");
+ }
} else if (result == TEST_TIMEOUT) {
ColoredPrintf(COLOR_RED, "[ TIMEOUT ] ");
}
@@ -398,6 +419,7 @@
int64_t elapsed_time_ns) {
std::vector<std::string> fail_test_name_list;
+ std::vector<std::string> xpass_test_name_list;
std::vector<std::pair<std::string, int64_t>> timeout_test_list;
// For tests that were slow but didn't time out.
@@ -405,18 +427,28 @@
size_t testcase_count = testcase_list.size();
size_t test_count = 0;
size_t success_test_count = 0;
+ size_t expected_failure_count = 0;
for (const auto& testcase : testcase_list) {
test_count += testcase.TestCount();
for (size_t i = 0; i < testcase.TestCount(); ++i) {
TestResult result = testcase.GetTestResult(i);
- if (result == TEST_SUCCESS) {
- ++success_test_count;
- } else if (result == TEST_FAILED) {
- fail_test_name_list.push_back(testcase.GetTestName(i));
- } else if (result == TEST_TIMEOUT) {
- timeout_test_list.push_back(std::make_pair(testcase.GetTestName(i),
- testcase.GetTestTime(i)));
+ TestResult expected = testcase.GetExpectedTestResult(i);
+ if (result == TEST_TIMEOUT) {
+ timeout_test_list.push_back(
+ std::make_pair(testcase.GetTestName(i), testcase.GetTestTime(i)));
+ } else if (result == expected) {
+ if (result == TEST_SUCCESS) {
+ ++success_test_count;
+ } else {
+ ++expected_failure_count;
+ }
+ } else {
+ if (result == TEST_FAILED) {
+ fail_test_name_list.push_back(testcase.GetTestName(i));
+ } else {
+ xpass_test_name_list.push_back(testcase.GetTestName(i));
+ }
}
if (result != TEST_TIMEOUT &&
testcase.GetTestTime(i) / 1000000 >= GetSlowThresholdMs(testcase.GetTestName(i))) {
@@ -435,7 +467,12 @@
}
printf("\n");
ColoredPrintf(COLOR_GREEN, "[ PASS ] ");
- printf("%zu %s.\n", success_test_count, (success_test_count == 1) ? "test" : "tests");
+ printf("%zu %s.", success_test_count, (success_test_count == 1) ? "test" : "tests");
+ if (expected_failure_count > 0) {
+ printf(" (%zu expected failure%s)", expected_failure_count,
+ (expected_failure_count == 1) ? "" : "s");
+ }
+ printf("\n");
// Print tests that timed out.
size_t timeout_test_count = timeout_test_list.size();
@@ -472,7 +509,18 @@
}
}
- if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0) {
+ // Print tests that should have failed.
+ size_t xpass_test_count = xpass_test_name_list.size();
+ if (xpass_test_count > 0) {
+ ColoredPrintf(COLOR_RED, "[ XPASS ] ");
+ printf("%zu %s, listed below:\n", xpass_test_count, (xpass_test_count == 1) ? "test" : "tests");
+ for (const auto& name : xpass_test_name_list) {
+ ColoredPrintf(COLOR_RED, "[ XPASS ] ");
+ printf("%s\n", name.c_str());
+ }
+ }
+
+ if (timeout_test_count > 0 || slow_test_count > 0 || fail_test_count > 0 || xpass_test_count > 0) {
printf("\n");
}
@@ -485,6 +533,10 @@
if (fail_test_count > 0) {
printf("%2zu FAILED %s\n", fail_test_count, (fail_test_count == 1) ? "TEST" : "TESTS");
}
+ if (xpass_test_count > 0) {
+ printf("%2zu SHOULD HAVE FAILED %s\n", xpass_test_count, (xpass_test_count == 1) ? "TEST" : "TESTS");
+ }
+
fflush(stdout);
}
@@ -540,7 +592,7 @@
auto& testcase = testcase_list[i];
total_test_count += testcase.TestCount();
for (size_t j = 0; j < testcase.TestCount(); ++j) {
- if (testcase.GetTestResult(j) != TEST_SUCCESS) {
+ if (!testcase.GetTestSuccess(j)) {
++failed_count_list[i];
}
elapsed_time_list[i] += testcase.GetTestTime(j);
@@ -568,7 +620,7 @@
fprintf(fp, " <testcase name=\"%s\" status=\"run\" time=\"%.3lf\" classname=\"%s\"",
testcase.GetTest(j).GetName().c_str(), testcase.GetTestTime(j) / 1e9,
testcase.GetName().c_str());
- if (testcase.GetTestResult(j) == TEST_SUCCESS) {
+ if (!testcase.GetTestSuccess(j)) {
fputs(" />\n", fp);
} else {
fputs(">\n", fp);
@@ -927,7 +979,7 @@
if (++finished_test_count_list[testcase_id] == testcase.TestCount()) {
++finished_testcase_count;
}
- if (testcase.GetTestResult(test_id) != TEST_SUCCESS) {
+ if (!testcase.GetTestSuccess(test_id)) {
all_tests_passed = false;
}
diff --git a/tests/gtest_preinit_debuggerd.cpp b/tests/gtest_preinit_debuggerd.cpp
index aac2e3f..88ca63b 100644
--- a/tests/gtest_preinit_debuggerd.cpp
+++ b/tests/gtest_preinit_debuggerd.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "debuggerd/client.h"
+#include "debuggerd/handler.h"
void __gtest_preinit() {
debuggerd_init(nullptr);
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 4cd991a..b5855af 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -24,8 +24,10 @@
relative_install_path: "bionic-loader-test-libs",
gtest: false,
sanitize: {
- never: true,
+ address: false,
+ coverage: false,
},
+ stl: "libc++_static",
target: {
darwin: {
enabled: false,
@@ -474,3 +476,21 @@
"libutils",
],
}
+
+cc_test_library {
+ name: "libcfi-test",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["cfi_test_lib.cpp"],
+ sanitize: {
+ cfi: false,
+ },
+}
+
+cc_test_library {
+ name: "libcfi-test-bad",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["cfi_test_bad_lib.cpp"],
+ sanitize: {
+ cfi: false,
+ },
+}
diff --git a/tests/libs/cfi_test_bad_lib.cpp b/tests/libs/cfi_test_bad_lib.cpp
new file mode 100644
index 0000000..429c843
--- /dev/null
+++ b/tests/libs/cfi_test_bad_lib.cpp
@@ -0,0 +1,4 @@
+// Mock an invalid CFI-enabled library.
+__attribute__((aligned(4096))) extern "C" char dummy[16] = {};
+__asm__(".globl __cfi_check");
+__asm__("__cfi_check = dummy + 3"); // Not aligned to anything.
diff --git a/tests/libs/cfi_test_lib.cpp b/tests/libs/cfi_test_lib.cpp
new file mode 100644
index 0000000..b0e2f42
--- /dev/null
+++ b/tests/libs/cfi_test_lib.cpp
@@ -0,0 +1,68 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+// This library is built for all targets, including host tests, so __cfi_slowpath may not be
+// present. But it is only used in the bionic loader tests.
+extern "C" __attribute__((weak)) void __cfi_slowpath(uint64_t, void*);
+
+static int g_count;
+static uint64_t g_last_type_id;
+static void* g_last_address;
+static void* g_last_diag;
+
+extern "C" {
+
+// Mock a CFI-enabled library without relying on the compiler.
+__attribute__((aligned(4096))) void __cfi_check(uint64_t CallSiteTypeId, void* TargetAddr,
+ void* Diag) {
+ ++g_count;
+ g_last_type_id = CallSiteTypeId;
+ g_last_address = TargetAddr;
+ g_last_diag = Diag;
+}
+
+int get_count() {
+ return g_count;
+}
+
+uint64_t get_last_type_id() {
+ return g_last_type_id;
+}
+
+void* get_last_address() {
+ return g_last_address;
+}
+
+void* get_last_diag() {
+ return g_last_diag;
+}
+
+void* get_global_address() {
+ return &g_count;
+}
+}
+
+// Check that CFI is set up in module constructors and destructors.
+struct A {
+ void check_cfi_self() {
+ g_last_type_id = 0;
+ assert(&__cfi_slowpath);
+ // CFI check for an invalid address. Normally, this would kill the process by routing the call
+ // back to the calling module's __cfi_check, which does the right thing based on
+ // -fsanitize-recover / -fsanitize-trap. But this module has custom __cfi_check that does not do
+ // any of that, so the result looks like a passing check.
+ int zz;
+ __cfi_slowpath(13, static_cast<void*>(&zz));
+ assert(g_last_type_id == 13);
+ // CFI check for a libc function. This never goes into this module's __cfi_check, and must pass.
+ __cfi_slowpath(14, reinterpret_cast<void*>(&exit));
+ assert(g_last_type_id == 13);
+ }
+ A() {
+ check_cfi_self();
+ }
+ ~A() {
+ check_cfi_self();
+ }
+} a;
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 63da9e0..da70d21 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -31,6 +31,7 @@
#include "BionicDeathTest.h"
#include "TemporaryFile.h"
+#include "utils.h"
#if defined(NOFORTIFY)
#define STDIO_TEST stdio_nofortify
@@ -47,6 +48,7 @@
rewind(fp);
char line[1024];
+ memset(line, 0xff, sizeof(line));
ASSERT_EQ(line, fgets(line, sizeof(line), fp));
ASSERT_STREQ(expected, line);
@@ -938,7 +940,7 @@
fclose(fp);
}
-TEST(STDIO_TEST, fmemopen_NULL) {
+TEST(STDIO_TEST, KNOWN_FAILURE_ON_BIONIC(fmemopen_NULL)) {
FILE* fp = fmemopen(nullptr, 128, "r+");
ASSERT_NE(EOF, fputs("xyz\n", fp));
diff --git a/tests/sys_uio_test.cpp b/tests/sys_uio_test.cpp
index 569d4fb..60bd224 100644
--- a/tests/sys_uio_test.cpp
+++ b/tests/sys_uio_test.cpp
@@ -70,8 +70,38 @@
TEST(sys_uio, process_vm_readv) {
ASSERT_EQ(0, process_vm_readv(0, nullptr, 0, nullptr, 0, 0));
+
+ // Test that we can read memory from our own process
+ char src[1024] = "This is the source buffer containing some data";
+ char dst[1024] = "";
+ iovec remote = { src, sizeof src };
+ iovec local = { dst, sizeof dst };
+ ASSERT_EQ(ssize_t(sizeof src), process_vm_readv(getpid(), &local, 1, &remote, 1, 0));
+ // Check whether data was copied (in the correct direction)
+ ASSERT_EQ('T', dst[0]);
+ ASSERT_EQ(0, memcmp(src, dst, sizeof src));
+
+ // Reading from non-allocated memory should return an error
+ remote = { nullptr, sizeof dst };
+ ASSERT_EQ(-1, process_vm_readv(getpid(), &local, 1, &remote, 1, 0));
+ ASSERT_EQ(EFAULT, errno);
}
TEST(sys_uio, process_vm_writev) {
ASSERT_EQ(0, process_vm_writev(0, nullptr, 0, nullptr, 0, 0));
+
+ // Test that we can read memory from our own process
+ char src[1024] = "This is the source buffer containing some data";
+ char dst[1024] = "";
+ iovec remote = { dst, sizeof dst };
+ iovec local = { src, sizeof src };
+ ASSERT_EQ(ssize_t(sizeof src), process_vm_writev(getpid(), &local, 1, &remote, 1, 0));
+ // Check whether data was copied (in the correct direction)
+ ASSERT_EQ('T', dst[0]);
+ ASSERT_EQ(0, memcmp(src, dst, sizeof src));
+
+ // Writing to non-allocated memory should return an error
+ remote = { nullptr, sizeof dst };
+ ASSERT_EQ(-1, process_vm_writev(getpid(), &local, 1, &remote, 1, 0));
+ ASSERT_EQ(EFAULT, errno);
}
diff --git a/tests/system_properties_test.cpp b/tests/system_properties_test.cpp
index 09eac3f..70482f0 100644
--- a/tests/system_properties_test.cpp
+++ b/tests/system_properties_test.cpp
@@ -244,16 +244,10 @@
ASSERT_EQ(0, __system_property_add("other_property", 14, "value2", 6));
ASSERT_EQ(0, __system_property_add("property_other", 14, "value3", 6));
- ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(0));
- ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(1));
- ASSERT_NE((const prop_info *)NULL, __system_property_find_nth(2));
-
- ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(3));
- ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(4));
- ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(5));
- ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(100));
- ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(200));
- ASSERT_EQ((const prop_info *)NULL, __system_property_find_nth(247));
+ // This method is no longer supported and should result in abort
+ ASSERT_EXIT(__system_property_find_nth(0), testing::KilledBySignal(SIGABRT),
+ "__system_property_find_nth is not supported since Android O,"
+ " please use __system_property_foreach instead.");
#else // __BIONIC__
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif // __BIONIC__
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 914cb61..8c4a8a9 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -674,3 +674,39 @@
ASSERT_TRUE(localtime_r(&t, &tm) != nullptr);
EXPECT_EQ(9, tm.tm_hour);
}
+
+TEST(time, bug_31339449) {
+ // POSIX says localtime acts as if it calls tzset.
+ // tzset does two things:
+ // 1. it sets the time zone ctime/localtime/mktime/strftime will use.
+ // 2. it sets the global `tzname`.
+ // POSIX says localtime_r need not set `tzname` (2).
+ // Q: should localtime_r set the time zone (1)?
+ // Upstream tzcode (and glibc) answer "no", everyone else answers "yes".
+
+ // Pick a time, any time...
+ time_t t = 1475619727;
+
+ // Call tzset with a specific timezone.
+ setenv("TZ", "America/Atka", 1);
+ tzset();
+
+ // If we change the timezone and call localtime, localtime should use the new timezone.
+ setenv("TZ", "America/Los_Angeles", 1);
+ struct tm* tm_p = localtime(&t);
+ EXPECT_EQ(15, tm_p->tm_hour);
+
+ // Reset the timezone back.
+ setenv("TZ", "America/Atka", 1);
+ tzset();
+
+#if defined(__BIONIC__)
+ // If we change the timezone again and call localtime_r, localtime_r should use the new timezone.
+ setenv("TZ", "America/Los_Angeles", 1);
+ struct tm tm = {};
+ localtime_r(&t, &tm);
+ EXPECT_EQ(15, tm.tm_hour);
+#else
+ // The BSDs agree with us, but glibc gets this wrong.
+#endif
+}
diff --git a/tests/utils.h b/tests/utils.h
index 4c3aef4..79eed10 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -32,6 +32,12 @@
#include "private/ScopeGuard.h"
+#if defined(__BIONIC__)
+#define KNOWN_FAILURE_ON_BIONIC(x) xfail_ ## x
+#else
+#define KNOWN_FAILURE_ON_BIONIC(x) x
+#endif
+
#if defined(__linux__)
struct map_record {