diff options
-rw-r--r-- | apex/Android.bp | 5 | ||||
-rw-r--r-- | libc/Android.bp | 57 | ||||
-rw-r--r-- | libc/bionic/libc_init_common.cpp | 1 | ||||
-rw-r--r-- | libc/bionic/tmpfile.cpp | 37 | ||||
-rw-r--r-- | libc/include/sys/capability.h | 4 | ||||
-rw-r--r-- | libc/include/sys/inotify.h | 2 | ||||
-rw-r--r-- | libc/include/sys/ipc.h | 2 | ||||
-rw-r--r-- | libc/include/sys/mount.h | 6 | ||||
-rw-r--r-- | libc/include/sys/msg.h | 6 | ||||
-rw-r--r-- | libc/include/sys/random.h | 4 | ||||
-rw-r--r-- | libc/include/sys/select.h | 12 | ||||
-rw-r--r-- | libc/include/sys/sendfile.h | 6 | ||||
-rw-r--r-- | libc/include/sys/wait.h | 8 | ||||
-rw-r--r-- | libc/include/wchar.h | 161 | ||||
-rw-r--r-- | linker/Android.bp | 5 | ||||
-rw-r--r-- | linker/linker.cpp | 83 | ||||
-rw-r--r-- | linker/linker_config.cpp | 3 | ||||
-rw-r--r-- | linker/linker_config.h | 1 | ||||
-rw-r--r-- | linker/linker_config_test.cpp | 96 | ||||
-rw-r--r-- | tests/Android.bp | 28 | ||||
-rw-r--r-- | tests/dlfcn_test.cpp | 19 | ||||
-rw-r--r-- | tests/hwasan_test.cpp | 67 | ||||
-rw-r--r-- | tests/libs/Android.bp | 32 | ||||
-rw-r--r-- | tests/libs/dlopen_testlib_simple_hwasan.cpp | 27 | ||||
-rw-r--r-- | tests/stdio_test.cpp | 17 | ||||
-rw-r--r-- | tests/sys_msg_test.cpp | 6 | ||||
-rw-r--r-- | tests/sys_random_test.cpp | 6 | ||||
-rw-r--r-- | tests/wchar_test.cpp | 4 |
28 files changed, 521 insertions, 184 deletions
diff --git a/apex/Android.bp b/apex/Android.bp index 90a14b245..6201ad12f 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -41,6 +41,11 @@ apex { "libc_malloc_debug", "libc_malloc_hooks", ], + arch: { + arm64: { + native_shared_libs: ["libc_hwasan", "libclang_rt.hwasan"], + }, + }, binaries: [ "linkerconfig", ], diff --git a/libc/Android.bp b/libc/Android.bp index 7eaa1bfa7..f5f5f7cee 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1674,13 +1674,12 @@ filegroup { // ======================================================== // libc.a + libc.so // ======================================================== -cc_library { +cc_defaults { defaults: [ "libc_defaults", "libc_native_allocator_defaults", ], - name: "libc", - static_ndk_lib: true, + name: "libc_library_defaults", product_variables: { platform_sdk_version: { asflags: ["-DPLATFORM_SDK_VERSION=%d"], @@ -1807,6 +1806,26 @@ cc_library { }, }, + + apex_available: [ + "//apex_available:platform", + "com.android.runtime", + ], + + target: { + native_bridge: { + shared: { + installable: false, + }, + }, + }, +} + +cc_library { + name: "libc", + defaults: [ + "libc_library_defaults", + ], stubs: { symbol_file: "libc.map.txt", versions: [ @@ -1815,24 +1834,40 @@ cc_library { "current", ], }, + static_ndk_lib: true, llndk: { symbol_file: "libc.map.txt", export_headers_as_system: true, export_preprocessed_headers: ["include"], export_llndk_headers: ["libc_llndk_headers"], }, - apex_available: [ - "//apex_available:platform", - "com.android.runtime", - ], +} +cc_library { + name: "libc_hwasan", + defaults: [ + "libc_library_defaults", + ], + sanitize: { + hwaddress: true, + }, + enabled: false, target: { - native_bridge: { - shared: { - installable: false, - }, + android_arm64: { + enabled: true, }, }, + stem: "libc", + relative_install_path: "hwasan", + // We don't really need the stubs, but this needs to stay to trigger the + // symlink logic in soong. + stubs: { + symbol_file: "libc.map.txt", + }, + native_bridge_supported: false, + // It is never correct to depend on this directly. This is only + // needed for the runtime apex, and in base_system.mk. + visibility: ["//bionic/apex"], } genrule { diff --git a/libc/bionic/libc_init_common.cpp b/libc/bionic/libc_init_common.cpp index 5d5ecaca4..59b2ddb33 100644 --- a/libc/bionic/libc_init_common.cpp +++ b/libc/bionic/libc_init_common.cpp @@ -289,6 +289,7 @@ static bool __is_unsafe_environment_variable(const char* name) { "LD_DEBUG", "LD_DEBUG_OUTPUT", "LD_DYNAMIC_WEAK", + "LD_HWASAN", "LD_LIBRARY_PATH", "LD_ORIGIN_PATH", "LD_PRELOAD", diff --git a/libc/bionic/tmpfile.cpp b/libc/bionic/tmpfile.cpp index 3d04610a4..4d6a1fbe0 100644 --- a/libc/bionic/tmpfile.cpp +++ b/libc/bionic/tmpfile.cpp @@ -51,6 +51,9 @@ static FILE* __fd_to_fp(int fd) { return nullptr; } +// O_TMPFILE isn't available until Linux 3.11, so we fall back to this on +// older kernels. AOSP was on a new enough kernel in the Lollipop timeframe, +// so this code should be obsolete by 2025. static FILE* __tmpfile_dir_legacy(const char* tmp_dir) { char* path = nullptr; if (asprintf(&path, "%s/tmp.XXXXXXXXXX", tmp_dir) == -1) { @@ -79,25 +82,18 @@ static FILE* __tmpfile_dir_legacy(const char* tmp_dir) { return __fd_to_fp(fd); } -static FILE* __tmpfile_dir(const char* tmp_dir) { - int fd = open(tmp_dir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); - if (fd == -1) return __tmpfile_dir_legacy(tmp_dir); - return __fd_to_fp(fd); +const char* __get_TMPDIR() { + // Use $TMPDIR if set, or fall back to /data/local/tmp otherwise. + // Useless for apps, but good enough for the shell. + const char* tmpdir = getenv("TMPDIR"); + return (tmpdir == nullptr) ? "/data/local/tmp" : tmpdir; } FILE* tmpfile() { - // TODO: get this app's temporary directory from the framework ("/data/data/app/cache"). - - // $EXTERNAL_STORAGE turns out not to be very useful because it doesn't support hard links. - // This means we can't do the usual trick of calling unlink before handing the file back. - - FILE* fp = __tmpfile_dir("/data/local/tmp"); - if (fp == nullptr) { - // P_tmpdir is "/tmp/", but POSIX explicitly says that tmpdir(3) should try P_tmpdir before - // giving up. This is potentially useful for bionic on the host anyway. - fp = __tmpfile_dir(P_tmpdir); - } - return fp; + const char* tmpdir = __get_TMPDIR(); + int fd = open(tmpdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) return __tmpfile_dir_legacy(tmpdir); + return __fd_to_fp(fd); } __strong_alias(tmpfile64, tmpfile); @@ -107,7 +103,7 @@ char* tempnam(const char* dir, const char* prefix) { // since we can't easily remove it... // $TMPDIR overrides any directory passed in. - char* tmpdir = getenv("TMPDIR"); + const char* tmpdir = getenv("TMPDIR"); if (tmpdir != nullptr) dir = tmpdir; // If we still have no directory, we'll give you a default. @@ -136,12 +132,7 @@ char* tmpnam(char* s) { static char buf[L_tmpnam]; if (s == nullptr) s = buf; - // Use $TMPDIR if set, or fall back to /data/local/tmp otherwise. - // Useless for apps, but good enough for the shell. - const char* dir = getenv("TMPDIR"); - if (dir == nullptr) dir = "/data/local/tmp"; - // Make up a mktemp(3) template and defer to it for the real work. - snprintf(s, L_tmpnam, "%s/tmpnam.XXXXXXXXXX", dir); + snprintf(s, L_tmpnam, "%s/tmpnam.XXXXXXXXXX", __get_TMPDIR()); return mktemp(s); } diff --git a/libc/include/sys/capability.h b/libc/include/sys/capability.h index 4cb698f06..b43bbf081 100644 --- a/libc/include/sys/capability.h +++ b/libc/include/sys/capability.h @@ -44,7 +44,7 @@ __BEGIN_DECLS * * Returns 0 on success, and returns -1 and sets `errno` on failure. */ -int capget(cap_user_header_t __hdr_ptr, cap_user_data_t __data_ptr); +int capget(cap_user_header_t _Nonnull __hdr_ptr, cap_user_data_t _Nullable __data_ptr); /** * [capset(2)](http://man7.org/linux/man-pages/man2/capset.2.html) sets the calling @@ -52,6 +52,6 @@ int capget(cap_user_header_t __hdr_ptr, cap_user_data_t __data_ptr); * * Returns 0 on success, and returns -1 and sets `errno` on failure. */ -int capset(cap_user_header_t __hdr_ptr, const cap_user_data_t __data_ptr); +int capset(cap_user_header_t _Nonnull __hdr_ptr, const cap_user_data_t _Nullable __data_ptr); __END_DECLS diff --git a/libc/include/sys/inotify.h b/libc/include/sys/inotify.h index c3cdc8556..e834d0774 100644 --- a/libc/include/sys/inotify.h +++ b/libc/include/sys/inotify.h @@ -42,7 +42,7 @@ __BEGIN_DECLS int inotify_init(void); int inotify_init1(int __flags) __INTRODUCED_IN(21); -int inotify_add_watch(int __fd, const char* __path, uint32_t __mask); +int inotify_add_watch(int __fd, const char* _Nonnull __path, uint32_t __mask); int inotify_rm_watch(int __fd, uint32_t __watch_descriptor); __END_DECLS diff --git a/libc/include/sys/ipc.h b/libc/include/sys/ipc.h index c81ec1a5a..2e2b8cfd9 100644 --- a/libc/include/sys/ipc.h +++ b/libc/include/sys/ipc.h @@ -52,6 +52,6 @@ __BEGIN_DECLS * * Returns a key on success, and returns -1 and sets `errno` on failure. */ -key_t ftok(const char* __path, int __id); +key_t ftok(const char* _Nonnull __path, int __id); __END_DECLS diff --git a/libc/include/sys/mount.h b/libc/include/sys/mount.h index 4db1ac1a6..aace205a9 100644 --- a/libc/include/sys/mount.h +++ b/libc/include/sys/mount.h @@ -55,7 +55,7 @@ __BEGIN_DECLS * * Returns 0 on success, and returns -1 and sets `errno` on failure. */ -int mount(const char* __source, const char* __target, const char* __fs_type, unsigned long __flags, const void* __data); +int mount(const char* __BIONIC_COMPLICATED_NULLNESS __source, const char* _Nonnull __target, const char* __BIONIC_COMPLICATED_NULLNESS __fs_type, unsigned long __flags, const void* _Nullable __data); /** * [umount(2)](http://man7.org/linux/man-pages/man2/umount.2.html) unmounts the filesystem at @@ -63,7 +63,7 @@ int mount(const char* __source, const char* __target, const char* __fs_type, uns * * Returns 0 on success, and returns -1 and sets `errno` on failure. */ -int umount(const char* __target); +int umount(const char* _Nonnull __target); /** * [umount2(2)](http://man7.org/linux/man-pages/man2/umount2.2.html) unmounts the filesystem at @@ -71,6 +71,6 @@ int umount(const char* __target); * * Returns 0 on success, and returns -1 and sets `errno` on failure. */ -int umount2(const char* __target, int __flags); +int umount2(const char* _Nonnull __target, int __flags); __END_DECLS diff --git a/libc/include/sys/msg.h b/libc/include/sys/msg.h index e19452c4e..ad481a00b 100644 --- a/libc/include/sys/msg.h +++ b/libc/include/sys/msg.h @@ -46,12 +46,12 @@ typedef __kernel_ulong_t msgqnum_t; typedef __kernel_ulong_t msglen_t; /** Not useful on Android; disallowed by SELinux. */ -int msgctl(int __msg_id, int __cmd, struct msqid_ds* __buf) __INTRODUCED_IN(26); +int msgctl(int __msg_id, int __cmd, struct msqid_ds* _Nullable __buf) __INTRODUCED_IN(26); /** Not useful on Android; disallowed by SELinux. */ int msgget(key_t __key, int __flags) __INTRODUCED_IN(26); /** Not useful on Android; disallowed by SELinux. */ -ssize_t msgrcv(int __msg_id, void* __msgbuf_ptr, size_t __size, long __type, int __flags) __INTRODUCED_IN(26); +ssize_t msgrcv(int __msg_id, void* _Nonnull __msgbuf_ptr, size_t __size, long __type, int __flags) __INTRODUCED_IN(26); /** Not useful on Android; disallowed by SELinux. */ -int msgsnd(int __msg_id, const void* __msgbuf_ptr, size_t __size, int __flags) __INTRODUCED_IN(26); +int msgsnd(int __msg_id, const void* _Nonnull __msgbuf_ptr, size_t __size, int __flags) __INTRODUCED_IN(26); __END_DECLS diff --git a/libc/include/sys/random.h b/libc/include/sys/random.h index be52bd9ca..025117653 100644 --- a/libc/include/sys/random.h +++ b/libc/include/sys/random.h @@ -50,7 +50,7 @@ __BEGIN_DECLS * * See also arc4random_buf() which is available in all API levels. */ -int getentropy(void* __buffer, size_t __buffer_size) __wur __INTRODUCED_IN(28); +int getentropy(void* _Nonnull __buffer, size_t __buffer_size) __wur __INTRODUCED_IN(28); /** * [getrandom(2)](http://man7.org/linux/man-pages/man2/getrandom.2.html) fills the given buffer @@ -62,6 +62,6 @@ int getentropy(void* __buffer, size_t __buffer_size) __wur __INTRODUCED_IN(28); * * See also arc4random_buf() which is available in all API levels. */ -ssize_t getrandom(void* __buffer, size_t __buffer_size, unsigned int __flags) __wur __INTRODUCED_IN(28); +ssize_t getrandom(void* _Nonnull __buffer, size_t __buffer_size, unsigned int __flags) __wur __INTRODUCED_IN(28); __END_DECLS diff --git a/libc/include/sys/select.h b/libc/include/sys/select.h index 06914a66a..8c6c2ff41 100644 --- a/libc/include/sys/select.h +++ b/libc/include/sys/select.h @@ -71,9 +71,9 @@ typedef struct { } \ } while (0) -void __FD_CLR_chk(int, fd_set*, size_t) __INTRODUCED_IN(21); -void __FD_SET_chk(int, fd_set*, size_t) __INTRODUCED_IN(21); -int __FD_ISSET_chk(int, const fd_set*, size_t) __INTRODUCED_IN(21); +void __FD_CLR_chk(int, fd_set* _Nonnull , size_t) __INTRODUCED_IN(21); +void __FD_SET_chk(int, fd_set* _Nonnull, size_t) __INTRODUCED_IN(21); +int __FD_ISSET_chk(int, const fd_set* _Nonnull, size_t) __INTRODUCED_IN(21); #define __FD_CLR(fd, set) (__FDS_BITS(fd_set*,set)[__FDELT(fd)] &= ~__FDMASK(fd)) #define __FD_SET(fd, set) (__FDS_BITS(fd_set*,set)[__FDELT(fd)] |= __FDMASK(fd)) @@ -95,7 +95,7 @@ int __FD_ISSET_chk(int, const fd_set*, size_t) __INTRODUCED_IN(21); * Returns the number of ready file descriptors on success, 0 for timeout, * and returns -1 and sets `errno` on failure. */ -int select(int __max_fd_plus_one, fd_set* __read_fds, fd_set* __write_fds, fd_set* __exception_fds, struct timeval* __timeout); +int select(int __max_fd_plus_one, fd_set* _Nullable __read_fds, fd_set* _Nullable __write_fds, fd_set* _Nullable __exception_fds, struct timeval* _Nullable __timeout); /** * [pselect(2)](http://man7.org/linux/man-pages/man2/select.2.html) waits on a @@ -106,7 +106,7 @@ int select(int __max_fd_plus_one, fd_set* __read_fds, fd_set* __write_fds, fd_se * Returns the number of ready file descriptors on success, 0 for timeout, * and returns -1 and sets `errno` on failure. */ -int pselect(int __max_fd_plus_one, fd_set* __read_fds, fd_set* __write_fds, fd_set* __exception_fds, const struct timespec* __timeout, const sigset_t* __mask); +int pselect(int __max_fd_plus_one, fd_set* _Nullable __read_fds, fd_set* _Nullable __write_fds, fd_set* _Nullable __exception_fds, const struct timespec* _Nullable __timeout, const sigset_t* _Nullable __mask); /** * [pselect64(2)](http://man7.org/linux/man-pages/man2/select.2.html) waits on a @@ -119,6 +119,6 @@ int pselect(int __max_fd_plus_one, fd_set* __read_fds, fd_set* __write_fds, fd_s * * Available since API level 28. */ -int pselect64(int __max_fd_plus_one, fd_set* __read_fds, fd_set* __write_fds, fd_set* __exception_fds, const struct timespec* __timeout, const sigset64_t* __mask) __INTRODUCED_IN(28); +int pselect64(int __max_fd_plus_one, fd_set* _Nullable __read_fds, fd_set* _Nullable __write_fds, fd_set* _Nullable __exception_fds, const struct timespec* _Nullable __timeout, const sigset64_t* _Nullable __mask) __INTRODUCED_IN(28); __END_DECLS diff --git a/libc/include/sys/sendfile.h b/libc/include/sys/sendfile.h index 60bbde8b8..4b00d5dc8 100644 --- a/libc/include/sys/sendfile.h +++ b/libc/include/sys/sendfile.h @@ -40,7 +40,7 @@ __BEGIN_DECLS /* See https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */ #if defined(__USE_FILE_OFFSET64) -ssize_t sendfile(int __out_fd, int __in_fd, off_t* __offset, size_t __count) __RENAME(sendfile64) __INTRODUCED_IN(21); +ssize_t sendfile(int __out_fd, int __in_fd, off_t* _Nullable __offset, size_t __count) __RENAME(sendfile64) __INTRODUCED_IN(21); #else /** * [sendfile(2)](http://man7.org/linux/man-pages/man2/sendfile.2.html) copies data directly @@ -50,13 +50,13 @@ ssize_t sendfile(int __out_fd, int __in_fd, off_t* __offset, size_t __count) __R * * Available since API level 21. */ -ssize_t sendfile(int __out_fd, int __in_fd, off_t* __offset, size_t __count); +ssize_t sendfile(int __out_fd, int __in_fd, off_t* _Nullable __offset, size_t __count); #endif /** * Like sendfile() but allows using a 64-bit offset * even from a 32-bit process without `__FILE_OFFSET_BITS=64`. */ -ssize_t sendfile64(int __out_fd, int __in_fd, off64_t* __offset, size_t __count) __INTRODUCED_IN(21); +ssize_t sendfile64(int __out_fd, int __in_fd, off64_t* _Nullable __offset, size_t __count) __INTRODUCED_IN(21); __END_DECLS diff --git a/libc/include/sys/wait.h b/libc/include/sys/wait.h index 96974a25b..e6fb855db 100644 --- a/libc/include/sys/wait.h +++ b/libc/include/sys/wait.h @@ -37,9 +37,9 @@ __BEGIN_DECLS -pid_t wait(int* __status); -pid_t waitpid(pid_t __pid, int* __status, int __options); -pid_t wait4(pid_t __pid, int* __status, int __options, struct rusage* __rusage) __INTRODUCED_IN(18); +pid_t wait(int* _Nullable __status); +pid_t waitpid(pid_t __pid, int* _Nullable __status, int __options); +pid_t wait4(pid_t __pid, int* _Nullable __status, int __options, struct rusage* _Nullable __rusage) __INTRODUCED_IN(18); /* Posix states that idtype_t should be an enumeration type, but * the kernel headers define P_ALL, P_PID and P_PGID as constant macros @@ -47,6 +47,6 @@ pid_t wait4(pid_t __pid, int* __status, int __options, struct rusage* __rusage) */ typedef int idtype_t; -int waitid(idtype_t __type, id_t __id, siginfo_t* __info, int __options); +int waitid(idtype_t __type, id_t __id, siginfo_t* _Nullable __info, int __options); __END_DECLS diff --git a/libc/include/wchar.h b/libc/include/wchar.h index add3606c7..39f937479 100644 --- a/libc/include/wchar.h +++ b/libc/include/wchar.h @@ -44,97 +44,96 @@ __BEGIN_DECLS wint_t btowc(int __ch); -int fwprintf(FILE* __fp, const wchar_t* __fmt, ...); -int fwscanf(FILE* __fp, const wchar_t* __fmt, ...); -wint_t fgetwc(FILE* __fp); -wchar_t* fgetws(wchar_t* __buf, int __size, FILE* __fp); -wint_t fputwc(wchar_t __wc, FILE* __fp); -int fputws(const wchar_t* __s, FILE* __fp); -int fwide(FILE* __fp, int __mode); -wint_t getwc(FILE* __fp); +int fwprintf(FILE* _Nonnull __fp, const wchar_t* _Nonnull __fmt, ...); +int fwscanf(FILE* _Nonnull __fp, const wchar_t* _Nonnull __fmt, ...); +wint_t fgetwc(FILE* _Nonnull __fp); +wchar_t* _Nullable fgetws(wchar_t* _Nonnull __buf, int __size, FILE* _Nonnull __fp); +wint_t fputwc(wchar_t __wc, FILE* _Nonnull __fp); +int fputws(const wchar_t* _Nonnull __s, FILE* _Nonnull __fp); +int fwide(FILE* _Nonnull __fp, int __mode); +wint_t getwc(FILE* _Nonnull __fp); wint_t getwchar(void); -int mbsinit(const mbstate_t* __ps); -size_t mbrlen(const char* __s, size_t __n, mbstate_t* __ps); -size_t mbrtowc(wchar_t* __buf, const char* __s, size_t __n, mbstate_t* __ps); -size_t mbsrtowcs(wchar_t* __dst, const char** __src, size_t __dst_n, mbstate_t* __ps); -size_t mbsnrtowcs(wchar_t* __dst, const char** __src, size_t __src_n, size_t __dst_n, mbstate_t* __ps) __INTRODUCED_IN(21); -wint_t putwc(wchar_t __wc, FILE* __fp); +int mbsinit(const mbstate_t* _Nullable __ps); +size_t mbrlen(const char* _Nullable __s, size_t __n, mbstate_t* _Nullable __ps); +size_t mbrtowc(wchar_t* _Nullable __buf, const char* _Nullable __s, size_t __n, mbstate_t* _Nullable __ps); +size_t mbsrtowcs(wchar_t* _Nullable __dst, const char* _Nullable * _Nonnull __src, size_t __dst_n, mbstate_t* _Nullable __ps); +size_t mbsnrtowcs(wchar_t* _Nullable __dst, const char* _Nullable * _Nullable __src, size_t __src_n, size_t __dst_n, mbstate_t* _Nullable __ps) __INTRODUCED_IN(21); +wint_t putwc(wchar_t __wc, FILE* _Nonnull __fp); wint_t putwchar(wchar_t __wc); -int swprintf(wchar_t* __buf, size_t __n, const wchar_t* __fmt, ...); -int swscanf(const wchar_t* __s, const wchar_t* __fmt, ...); -wint_t ungetwc(wint_t __wc, FILE* __fp); -int vfwprintf(FILE* __fp, const wchar_t* __fmt, va_list __args); -int vfwscanf(FILE* __fp, const wchar_t* __fmt, va_list __args) __INTRODUCED_IN(21); -int vswprintf(wchar_t* __buf, size_t __n, const wchar_t* __fmt, va_list __args); -int vswscanf(const wchar_t* __s, const wchar_t* __fmt, va_list __args) __INTRODUCED_IN(21); -int vwprintf(const wchar_t* __fmt, va_list __args); -int vwscanf(const wchar_t* __fmt, va_list __args) __INTRODUCED_IN(21); -wchar_t* wcpcpy(wchar_t* __dst, const wchar_t* __src); -wchar_t* wcpncpy(wchar_t* __dst, const wchar_t* __src, size_t __n); -size_t wcrtomb(char* __buf, wchar_t __wc, mbstate_t* __ps); -int wcscasecmp(const wchar_t* __lhs, const wchar_t* __rhs); -int wcscasecmp_l(const wchar_t* __lhs, const wchar_t* __rhs, locale_t __l) __INTRODUCED_IN(23); -wchar_t* wcscat(wchar_t* __dst, const wchar_t* __src); -wchar_t* wcschr(const wchar_t* __s, wchar_t __wc); -int wcscmp(const wchar_t* __lhs, const wchar_t* __rhs); -int wcscoll(const wchar_t* __lhs, const wchar_t* __rhs); -wchar_t* wcscpy(wchar_t* __dst, const wchar_t* __src); -size_t wcscspn(const wchar_t* __s, const wchar_t* __accept); -size_t wcsftime(wchar_t* __buf, size_t __n, const wchar_t* __fmt, const struct tm* __tm); -size_t wcsftime_l(wchar_t* __buf, size_t __n, const wchar_t* __fmt, const struct tm* __tm, locale_t __l) __INTRODUCED_IN(28); -size_t wcslen(const wchar_t* __s); -int wcsncasecmp(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n); -int wcsncasecmp_l(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n, locale_t __l) __INTRODUCED_IN(23); -wchar_t* wcsncat(wchar_t* __dst, const wchar_t* __src, size_t __n); -int wcsncmp(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n); -wchar_t* wcsncpy(wchar_t* __dst, const wchar_t* __src, size_t __n); -size_t wcsnrtombs(char* __dst, const wchar_t** __src, size_t __src_n, size_t __dst_n, mbstate_t* __ps) __INTRODUCED_IN(21); -wchar_t* wcspbrk(const wchar_t* __s, const wchar_t* __accept); -wchar_t* wcsrchr(const wchar_t* __s, wchar_t __wc); -size_t wcsrtombs(char* __dst, const wchar_t** __src, size_t __dst_n, mbstate_t* __ps); -size_t wcsspn(const wchar_t* __s, const wchar_t* __accept); -wchar_t* wcsstr(const wchar_t* __haystack, const wchar_t* __needle); -double wcstod(const wchar_t* __s, wchar_t** __end_ptr); -double wcstod_l(const wchar_t* __s, wchar_t** __end_ptr, locale_t __l) __INTRODUCED_IN(28); -float wcstof(const wchar_t* __s, wchar_t** __end_ptr) __INTRODUCED_IN(21); -float wcstof_l(const wchar_t* __s, wchar_t** __end_ptr, locale_t __l) __INTRODUCED_IN(28); -wchar_t* wcstok(wchar_t* __s, const wchar_t* __delimiter, wchar_t** __ptr); -long wcstol(const wchar_t* __s, wchar_t** __end_ptr, int __base); -long wcstol_l(const wchar_t* __s, wchar_t** __end_ptr, int __base, locale_t __l) __INTRODUCED_IN(28); -long long wcstoll(const wchar_t* __s, wchar_t** __end_ptr, int __base) __INTRODUCED_IN(21); -long double wcstold(const wchar_t* __s, wchar_t** __end_ptr) __RENAME_LDBL(wcstod, 3, 21); -unsigned long wcstoul(const wchar_t* __s, wchar_t** __end_ptr, int __base); -unsigned long wcstoul_l(const wchar_t* __s, wchar_t** __end_ptr, int __base, locale_t __l) __INTRODUCED_IN(28); -unsigned long long wcstoull(const wchar_t* __s, wchar_t** __end_ptr, int __base) __INTRODUCED_IN(21); -int wcswidth(const wchar_t* __s, size_t __n); -size_t wcsxfrm(wchar_t* __dst, const wchar_t* __src, size_t __n); +int swprintf(wchar_t* _Nonnull __buf, size_t __n, const wchar_t* _Nonnull __fmt, ...); +int swscanf(const wchar_t* _Nonnull __s, const wchar_t* _Nonnull __fmt, ...); +wint_t ungetwc(wint_t __wc, FILE* _Nonnull __fp); +int vfwprintf(FILE* _Nonnull __fp, const wchar_t* _Nonnull __fmt, va_list __args); +int vfwscanf(FILE* _Nonnull __fp, const wchar_t* _Nonnull __fmt, va_list __args) __INTRODUCED_IN(21); +int vswprintf(wchar_t* _Nonnull __buf, size_t __n, const wchar_t* _Nonnull __fmt, va_list __args); +int vswscanf(const wchar_t* _Nonnull __s, const wchar_t* _Nonnull __fmt, va_list __args) __INTRODUCED_IN(21); +int vwprintf(const wchar_t* _Nonnull __fmt, va_list __args); +int vwscanf(const wchar_t* _Nonnull __fmt, va_list __args) __INTRODUCED_IN(21); +wchar_t* _Nonnull wcpcpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src); +wchar_t* _Nonnull wcpncpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); +size_t wcrtomb(char* _Nullable __buf, wchar_t __wc, mbstate_t* _Nullable __ps); +int wcscasecmp(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs); +int wcscasecmp_l(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs, locale_t _Nonnull __l) __INTRODUCED_IN(23); +wchar_t* _Nonnull wcscat(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src); +wchar_t* _Nullable wcschr(const wchar_t * _Nonnull __s, wchar_t __wc); +int wcscmp(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs); +int wcscoll(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs); +wchar_t* _Nonnull wcscpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src); +size_t wcscspn(const wchar_t* _Nonnull __s, const wchar_t* _Nonnull __accept); +size_t wcsftime(wchar_t* _Nonnull __buf, size_t __n, const wchar_t* _Nullable __fmt, const struct tm* _Nonnull __tm); +size_t wcsftime_l(wchar_t* _Nonnull __buf, size_t __n, const wchar_t* _Nullable __fmt, const struct tm* _Nonnull __tm, locale_t _Nonnull __l) __INTRODUCED_IN(28); +size_t wcslen(const wchar_t* _Nonnull __s); +int wcsncasecmp(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs, size_t __n); +int wcsncasecmp_l(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs, size_t __n, locale_t _Nonnull __l) __INTRODUCED_IN(23); +wchar_t* _Nonnull wcsncat(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); +int wcsncmp(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs, size_t __n); +wchar_t* _Nonnull wcsncpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); +size_t wcsnrtombs(char* _Nullable __dst, const wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __src, size_t __src_n, size_t __dst_n, mbstate_t* _Nullable __ps) __INTRODUCED_IN(21); +wchar_t* _Nullable wcspbrk(const wchar_t* _Nonnull __s, const wchar_t* _Nonnull __accept); +wchar_t* _Nullable wcsrchr(const wchar_t* _Nonnull __s, wchar_t __wc); +size_t wcsrtombs(char* _Nullable __dst, const wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __src, size_t __dst_n, mbstate_t* _Nullable __ps); +size_t wcsspn(const wchar_t* _Nonnull __s, const wchar_t* _Nonnull __accept); +wchar_t* _Nullable wcsstr(const wchar_t* _Nonnull __haystack, const wchar_t* _Nonnull __needle); +double wcstod(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr); +double wcstod_l(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, locale_t _Nonnull __l) __INTRODUCED_IN(28); +float wcstof(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr) __INTRODUCED_IN(21); +float wcstof_l(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, locale_t _Nonnull __l) __INTRODUCED_IN(28); +wchar_t* _Nullable wcstok(wchar_t* _Nullable __s, const wchar_t* _Nonnull __delimiter, wchar_t* _Nonnull * _Nonnull __ptr); +long wcstol(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, int __base); +long wcstol_l(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) __INTRODUCED_IN(28); +long long wcstoll(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, int __base) __INTRODUCED_IN(21); +long double wcstold(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr) __RENAME_LDBL(wcstod, 3, 21); +unsigned long wcstoul(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, int __base); +unsigned long wcstoul_l(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) __INTRODUCED_IN(28); +unsigned long long wcstoull(const wchar_t* _Nonnull __s, wchar_t* __BIONIC_COMPLICATED_NULLNESS * _Nullable __end_ptr, int __base) __INTRODUCED_IN(21); +int wcswidth(const wchar_t* _Nonnull __s, size_t __n); +size_t wcsxfrm(wchar_t* __BIONIC_COMPLICATED_NULLNESS __dst, const wchar_t* _Nonnull __src, size_t __n); int wctob(wint_t __wc); int wcwidth(wchar_t __wc); -wchar_t* wmemchr(const wchar_t* __src, wchar_t __wc, size_t __n); -int wmemcmp(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n); -wchar_t* wmemcpy(wchar_t* __dst, const wchar_t* __src, size_t __n); +wchar_t* _Nullable wmemchr(const wchar_t* _Nonnull __src, wchar_t __wc, size_t __n); +int wmemcmp(const wchar_t* _Nullable __lhs, const wchar_t* _Nullable __rhs, size_t __n); +wchar_t* _Nonnull wmemcpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); #if defined(__USE_GNU) -wchar_t* wmempcpy(wchar_t* __dst, const wchar_t* __src, size_t __n) __INTRODUCED_IN(23); +wchar_t* _Nonnull wmempcpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n) __INTRODUCED_IN(23); #endif -wchar_t* wmemmove(wchar_t* __dst, const wchar_t* __src, size_t __n); -wchar_t* wmemset(wchar_t* __dst, wchar_t __wc, size_t __n); -int wprintf(const wchar_t* __fmt, ...); -int wscanf(const wchar_t* __fmt, ...); +wchar_t* _Nonnull wmemmove(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); +wchar_t* _Nonnull wmemset(wchar_t* _Nonnull __dst, wchar_t __wc, size_t __n); +int wprintf(const wchar_t* _Nonnull __fmt, ...); +int wscanf(const wchar_t* _Nonnull __fmt, ...); -long long wcstoll_l(const wchar_t* __s, wchar_t** __end_ptr, int __base, locale_t __l) __INTRODUCED_IN(21); -unsigned long long wcstoull_l(const wchar_t* __s, wchar_t** __end_ptr, int __base, locale_t __l) __INTRODUCED_IN(21); -long double wcstold_l(const wchar_t* __s, wchar_t** __end_ptr, locale_t __l) __INTRODUCED_IN(21); +long long wcstoll_l(const wchar_t* _Nonnull __s, wchar_t* _Nullable * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) __INTRODUCED_IN(21); +unsigned long long wcstoull_l(const wchar_t* _Nonnull __s, wchar_t* _Nullable * _Nullable __end_ptr, int __base, locale_t _Nonnull __l) __INTRODUCED_IN(21); +long double wcstold_l(const wchar_t* _Nonnull __s, wchar_t* _Nullable * _Nullable __end_ptr, locale_t _Nonnull __l) __INTRODUCED_IN(21); -int wcscoll_l(const wchar_t* __lhs, const wchar_t* __rhs, locale_t __l) __attribute_pure__ +int wcscoll_l(const wchar_t* _Nonnull __lhs, const wchar_t* _Nonnull __rhs, locale_t _Nonnull __l) __attribute_pure__ __INTRODUCED_IN(21); -size_t wcsxfrm_l(wchar_t* __dst, const wchar_t* __src, size_t __n, locale_t __l) __INTRODUCED_IN(21); +size_t wcsxfrm_l(wchar_t* __BIONIC_COMPLICATED_NULLNESS __dst, const wchar_t* _Nonnull __src, size_t __n, locale_t _Nonnull __l) __INTRODUCED_IN(21); +size_t wcslcat(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); +size_t wcslcpy(wchar_t* _Nonnull __dst, const wchar_t* _Nonnull __src, size_t __n); -size_t wcslcat(wchar_t* __dst, const wchar_t* __src, size_t __n); -size_t wcslcpy(wchar_t* __dst, const wchar_t* __src, size_t __n); - -FILE* open_wmemstream(wchar_t** __ptr, size_t* __size_ptr) __INTRODUCED_IN(23); -wchar_t* wcsdup(const wchar_t* __s); -size_t wcsnlen(const wchar_t* __s, size_t __n); +FILE* _Nullable open_wmemstream(wchar_t* _Nonnull * _Nonnull __ptr, size_t* _Nonnull __size_ptr) __INTRODUCED_IN(23); +wchar_t* _Nullable wcsdup(const wchar_t* _Nonnull __s); +size_t wcsnlen(const wchar_t* _Nonnull __s, size_t __n); __END_DECLS diff --git a/linker/Android.bp b/linker/Android.bp index 83077c6e4..020bd7d70 100644 --- a/linker/Android.bp +++ b/linker/Android.bp @@ -374,6 +374,11 @@ cc_binary { ], symlinks: ["linker_asan"], + arch: { + arm64: { + symlinks: ["linker_hwasan"], + }, + }, multilib: { lib64: { suffix: "64", diff --git a/linker/linker.cpp b/linker/linker.cpp index c5a822a6e..17b574fc1 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -34,6 +34,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/auxv.h> #include <sys/mman.h> #include <sys/param.h> #include <sys/vfs.h> @@ -133,6 +134,36 @@ static const char* const kAsanDefaultLdPaths[] = { nullptr }; +#if defined(__aarch64__) +static const char* const kHwasanSystemLibDir = "/system/lib64/hwasan"; +static const char* const kHwasanOdmLibDir = "/odm/lib64/hwasan"; +static const char* const kHwasanVendorLibDir = "/vendor/lib64/hwasan"; + +// HWASan is only supported on aarch64. +static const char* const kHwsanDefaultLdPaths[] = { + kHwasanSystemLibDir, + kSystemLibDir, + kHwasanOdmLibDir, + kOdmLibDir, + kHwasanVendorLibDir, + kVendorLibDir, + nullptr +}; + +// Is HWASAN enabled? +static bool g_is_hwasan = false; +#else +static const char* const kHwsanDefaultLdPaths[] = { + kSystemLibDir, + kOdmLibDir, + kVendorLibDir, + nullptr +}; + +// Never any HWASan. Help the compiler remove the code we don't need. +constexpr bool g_is_hwasan = false; +#endif + // Is ASAN enabled? static bool g_is_asan = false; @@ -2134,26 +2165,46 @@ void* do_dlopen(const char* name, int flags, } // End Workaround for dlopen(/system/lib/<soname>) when .so is in /apex. - std::string asan_name_holder; + std::string translated_name_holder; + assert(!g_is_hwasan || !g_is_asan); const char* translated_name = name; if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') { char original_path[PATH_MAX]; if (realpath(name, original_path) != nullptr) { - asan_name_holder = std::string(kAsanLibDirPrefix) + original_path; - if (file_exists(asan_name_holder.c_str())) { + translated_name_holder = std::string(kAsanLibDirPrefix) + original_path; + if (file_exists(translated_name_holder.c_str())) { soinfo* si = nullptr; if (find_loaded_library_by_realpath(ns, original_path, true, &si)) { PRINT("linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name, - asan_name_holder.c_str()); + translated_name_holder.c_str()); } else { PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name); - translated_name = asan_name_holder.c_str(); + translated_name = translated_name_holder.c_str(); + } + } + } + } else if (g_is_hwasan && translated_name != nullptr && translated_name[0] == '/') { + char original_path[PATH_MAX]; + if (realpath(name, original_path) != nullptr) { + // Keep this the same as CreateHwasanPath in system/linkerconfig/modules/namespace.cc. + std::string path(original_path); + auto slash = path.rfind('/'); + if (slash != std::string::npos || slash != path.size() - 1) { + translated_name_holder = path.substr(0, slash) + "/hwasan" + path.substr(slash); + } + if (!translated_name_holder.empty() && file_exists(translated_name_holder.c_str())) { + soinfo* si = nullptr; + if (find_loaded_library_by_realpath(ns, original_path, true, &si)) { + PRINT("linker_hwasan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name, + translated_name_holder.c_str()); + } else { + PRINT("linker_hwasan dlopen translating \"%s\" -> \"%s\"", name, translated_name); + translated_name = translated_name_holder.c_str(); } } } } - ProtectedDataGuard guard; soinfo* si = find_library(ns, translated_name, flags, extinfo, caller); loading_trace.End(); @@ -3335,9 +3386,10 @@ bool soinfo::protect_relro() { return true; } -static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan) { +static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan, bool is_hwasan) { g_default_namespace.set_isolated(false); - auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths; + auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : ( + is_hwasan ? kHwsanDefaultLdPaths : kDefaultLdPaths); char real_path[PATH_MAX]; std::vector<std::string> ld_default_paths; @@ -3441,6 +3493,7 @@ static std::string get_ld_config_file_path(const char* executable_path) { return kLdConfigFilePath; } + std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) { g_default_namespace.set_name("(default)"); @@ -3454,6 +3507,16 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0); +#if defined(__aarch64__) + // HWASan is only supported on AArch64. + // The AT_SECURE restriction is because this is a debug feature that does + // not need to work on secure binaries, it doesn't hurt to disallow the + // environment variable for them, as it impacts the program execution. + char* hwasan_env = getenv("LD_HWASAN"); + g_is_hwasan = (bname != nullptr && + strcmp(bname, "linker_hwasan64") == 0) || + (hwasan_env != nullptr && !getauxval(AT_SECURE) && strcmp(hwasan_env, "1") == 0); +#endif const Config* config = nullptr; { @@ -3461,7 +3524,7 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable INFO("[ Reading linker config \"%s\" ]", ld_config_file_path.c_str()); ScopedTrace trace(("linker config " + ld_config_file_path).c_str()); std::string error_msg; - if (!Config::read_binary_config(ld_config_file_path.c_str(), executable_path, g_is_asan, + if (!Config::read_binary_config(ld_config_file_path.c_str(), executable_path, g_is_asan, g_is_hwasan, &config, &error_msg)) { if (!error_msg.empty()) { DL_WARN("Warning: couldn't read '%s' for '%s' (using default configuration instead): %s", @@ -3472,7 +3535,7 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable } if (config == nullptr) { - return init_default_namespace_no_config(g_is_asan); + return init_default_namespace_no_config(g_is_asan, g_is_hwasan); } const auto& namespace_configs = config->namespace_configs(); diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp index 1771e8706..ad40c500f 100644 --- a/linker/linker_config.cpp +++ b/linker/linker_config.cpp @@ -463,6 +463,7 @@ class Properties { bool Config::read_binary_config(const char* ld_config_file_path, const char* binary_realpath, bool is_asan, + bool is_hwasan, const Config** config, std::string* error_msg) { g_config.clear(); @@ -579,6 +580,8 @@ bool Config::read_binary_config(const char* ld_config_file_path, // these are affected by is_asan flag if (is_asan) { property_name_prefix += ".asan"; + } else if (is_hwasan) { + property_name_prefix += ".hwasan"; } // search paths are resolved (canonicalized). This is required mainly for diff --git a/linker/linker_config.h b/linker/linker_config.h index fe23ec169..09fea45f6 100644 --- a/linker/linker_config.h +++ b/linker/linker_config.h @@ -166,6 +166,7 @@ class Config { static bool read_binary_config(const char* ld_config_file_path, const char* binary_realpath, bool is_asan, + bool is_hwasan, const Config** config, std::string* error_msg); diff --git a/linker/linker_config_test.cpp b/linker/linker_config_test.cpp index acdf64173..7e947f38e 100644 --- a/linker/linker_config_test.cpp +++ b/linker/linker_config_test.cpp @@ -40,6 +40,7 @@ #include <android-base/file.h> #include <android-base/scopeguard.h> #include <android-base/stringprintf.h> +#include <vector> #if defined(__LP64__) #define ARCH_SUFFIX "64" @@ -64,6 +65,10 @@ static const char* config_str = "namespace.default.asan.search.paths = /data\n" "namespace.default.asan.search.paths += /vendor/${LIB}\n" "namespace.default.asan.permitted.paths = /data:/vendor\n" + "namespace.default.hwasan.search.paths = /vendor/${LIB}/hwasan\n" + "namespace.default.hwasan.search.paths += /vendor/${LIB}\n" + "namespace.default.hwasan.permitted.paths = /vendor/${LIB}/hwasan\n" + "namespace.default.hwasan.permitted.paths += /vendor/${LIB}\n" "namespace.default.links = system\n" "namespace.default.links += vndk\n" // irregular whitespaces are added intentionally for testing purpose @@ -77,11 +82,17 @@ static const char* config_str = "namespace.system.permitted.paths = /system/${LIB}\n" "namespace.system.asan.search.paths = /data:/system/${LIB}\n" "namespace.system.asan.permitted.paths = /data:/system\n" + "namespace.system.hwasan.search.paths = /system/${LIB}/hwasan\n" + "namespace.system.hwasan.search.paths += /system/${LIB}\n" + "namespace.system.hwasan.permitted.paths = /system/${LIB}/hwasan\n" + "namespace.system.hwasan.permitted.paths += /system/${LIB}\n" "namespace.vndk.isolated = tr\n" "namespace.vndk.isolated += ue\n" // should be ignored and return as 'false'. "namespace.vndk.search.paths = /system/${LIB}/vndk\n" "namespace.vndk.asan.search.paths = /data\n" "namespace.vndk.asan.search.paths += /system/${LIB}/vndk\n" + "namespace.vndk.hwasan.search.paths = /system/${LIB}/vndk/hwasan\n" + "namespace.vndk.hwasan.search.paths += /system/${LIB}/vndk\n" "namespace.vndk.links = default\n" "namespace.vndk.link.default.allow_all_shared_libs = true\n" "namespace.vndk.link.vndk_in_system.allow_all_shared_libs = true\n" @@ -107,26 +118,50 @@ static std::vector<std::string> resolve_paths(std::vector<std::string> paths) { return resolved_paths; } -static void run_linker_config_smoke_test(bool is_asan) { - const std::vector<std::string> kExpectedDefaultSearchPath = - resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor/lib" ARCH_SUFFIX }) : - std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX })); - - const std::vector<std::string> kExpectedDefaultPermittedPath = - resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor" }) : - std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX })); - - const std::vector<std::string> kExpectedSystemSearchPath = - resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX }) : - std::vector<std::string>({ "/system/lib" ARCH_SUFFIX })); - - const std::vector<std::string> kExpectedSystemPermittedPath = - resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system" }) : - std::vector<std::string>({ "/system/lib" ARCH_SUFFIX })); +enum class SmokeTestType { + None, + Asan, + Hwasan, +}; + +static void run_linker_config_smoke_test(SmokeTestType type) { + std::vector<std::string> expected_default_search_path; + std::vector<std::string> expected_default_permitted_path; + std::vector<std::string> expected_system_search_path; + std::vector<std::string> expected_system_permitted_path; + std::vector<std::string> expected_vndk_search_path; + + switch (type) { + case SmokeTestType::None: + expected_default_search_path = { "/vendor/lib" ARCH_SUFFIX }; + expected_default_permitted_path = { "/vendor/lib" ARCH_SUFFIX }; + expected_system_search_path = { "/system/lib" ARCH_SUFFIX }; + expected_system_permitted_path = { "/system/lib" ARCH_SUFFIX }; + expected_vndk_search_path = { "/system/lib" ARCH_SUFFIX "/vndk" }; + break; + case SmokeTestType::Asan: + expected_default_search_path = { "/data", "/vendor/lib" ARCH_SUFFIX }; + expected_default_permitted_path = { "/data", "/vendor" }; + expected_system_search_path = { "/data", "/system/lib" ARCH_SUFFIX }; + expected_system_permitted_path = { "/data", "/system" }; + expected_vndk_search_path = { "/data", "/system/lib" ARCH_SUFFIX "/vndk" }; + break; + case SmokeTestType::Hwasan: + expected_default_search_path = { "/vendor/lib" ARCH_SUFFIX "/hwasan", "/vendor/lib" ARCH_SUFFIX }; + expected_default_permitted_path = { "/vendor/lib" ARCH_SUFFIX "/hwasan", "/vendor/lib" ARCH_SUFFIX }; + expected_system_search_path = { "/system/lib" ARCH_SUFFIX "/hwasan" , "/system/lib" ARCH_SUFFIX }; + expected_system_permitted_path = { "/system/lib" ARCH_SUFFIX "/hwasan", "/system/lib" ARCH_SUFFIX }; + expected_vndk_search_path = { "/system/lib" ARCH_SUFFIX "/vndk/hwasan", "/system/lib" ARCH_SUFFIX "/vndk" }; + break; + } - const std::vector<std::string> kExpectedVndkSearchPath = - resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX "/vndk"}) : - std::vector<std::string>({ "/system/lib" ARCH_SUFFIX "/vndk"})); + expected_default_search_path = resolve_paths(expected_default_search_path); + // expected_default_permitted_path is skipped on purpose, permitted paths + // do not get resolved in linker_config.cpp + expected_system_search_path = resolve_paths(expected_system_search_path); + // expected_system_permitted_path is skipped on purpose, permitted paths + // do not get resolved in linker_config.cpp + expected_vndk_search_path = resolve_paths(expected_vndk_search_path); TemporaryFile tmp_file; close(tmp_file.fd); @@ -149,7 +184,8 @@ static void run_linker_config_smoke_test(bool is_asan) { std::string error_msg; ASSERT_TRUE(Config::read_binary_config(tmp_file.path, executable_path.c_str(), - is_asan, + type == SmokeTestType::Asan, + type == SmokeTestType::Hwasan, &config, &error_msg)) << error_msg; ASSERT_TRUE(config != nullptr); @@ -162,8 +198,8 @@ static void run_linker_config_smoke_test(bool is_asan) { ASSERT_TRUE(default_ns_config->isolated()); ASSERT_FALSE(default_ns_config->visible()); - ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths()); - ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths()); + ASSERT_EQ(expected_default_search_path, default_ns_config->search_paths()); + ASSERT_EQ(expected_default_permitted_path, default_ns_config->permitted_paths()); const auto& default_ns_links = default_ns_config->links(); ASSERT_EQ(2U, default_ns_links.size()); @@ -202,14 +238,14 @@ static void run_linker_config_smoke_test(bool is_asan) { ASSERT_TRUE(ns_system->isolated()); ASSERT_TRUE(ns_system->visible()); - ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths()); - ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths()); + ASSERT_EQ(expected_system_search_path, ns_system->search_paths()); + ASSERT_EQ(expected_system_permitted_path, ns_system->permitted_paths()); ASSERT_TRUE(ns_vndk != nullptr) << "vndk namespace was not found"; ASSERT_FALSE(ns_vndk->isolated()); // malformed bool property ASSERT_FALSE(ns_vndk->visible()); // undefined bool property - ASSERT_EQ(kExpectedVndkSearchPath, ns_vndk->search_paths()); + ASSERT_EQ(expected_vndk_search_path, ns_vndk->search_paths()); const auto& ns_vndk_links = ns_vndk->links(); ASSERT_EQ(1U, ns_vndk_links.size()); @@ -223,11 +259,15 @@ static void run_linker_config_smoke_test(bool is_asan) { } TEST(linker_config, smoke) { - run_linker_config_smoke_test(false); + run_linker_config_smoke_test(SmokeTestType::None); } TEST(linker_config, asan_smoke) { - run_linker_config_smoke_test(true); + run_linker_config_smoke_test(SmokeTestType::Asan); +} + +TEST(linker_config, hwasan_smoke) { + run_linker_config_smoke_test(SmokeTestType::Hwasan); } TEST(linker_config, ns_link_shared_libs_invalid_settings) { @@ -259,6 +299,7 @@ TEST(linker_config, ns_link_shared_libs_invalid_settings) { ASSERT_FALSE(Config::read_binary_config(tmp_file.path, executable_path.c_str(), false, + false, &config, &error_msg)); ASSERT_TRUE(config == nullptr); @@ -304,6 +345,7 @@ TEST(linker_config, dir_path_resolve) { ASSERT_TRUE(Config::read_binary_config(tmp_file.path, executable_path.c_str(), false, + false, &config, &error_msg)) << error_msg; diff --git a/tests/Android.bp b/tests/Android.bp index 19490791a..1be1ec3e4 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -541,6 +541,10 @@ cc_test_library { // unsupported relocation type 37 "ifunc_test.cpp", + + // musl #defines utmp to utmpx, causing a collision with + // utmpx_test.cpp + "utmp_test.cpp", ], }, }, @@ -1112,6 +1116,30 @@ cc_test { } cc_test { + name: "hwasan_test", + enabled: false, + // This does not use bionic_tests_defaults because it is not supported on + // host. + arch: { + arm64: { + enabled: true, + }, + }, + sanitize: { + hwaddress: true, + }, + srcs: [ + "hwasan_test.cpp", + ], + shared_libs: [ + "libbase", + ], + data_libs: ["libtest_simple_hwasan", "libtest_simple_hwasan_nohwasan"], + header_libs: ["bionic_libc_platform_headers"], + test_suites: ["device-tests"], +} + +cc_test { name: "bionic-stress-tests", defaults: [ "bionic_tests_defaults", diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 3f70279c1..b68ee7b51 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -971,9 +971,15 @@ TEST(dlfcn, dlopen_executable_by_absolute_path) { } #define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/" ABI_STRING "/" +#if __has_feature(hwaddress_sanitizer) +#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "hwasan/libc.so" +#define PATH_TO_BOOTSTRAP_LIBC PATH_TO_SYSTEM_LIB "bootstrap/hwasan/libc.so" +#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "hwasan/libc.so" +#else #define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so" #define PATH_TO_BOOTSTRAP_LIBC PATH_TO_SYSTEM_LIB "bootstrap/libc.so" #define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so" +#endif TEST(dlfcn, dladdr_libc) { #if defined(__GLIBC__) @@ -981,24 +987,25 @@ TEST(dlfcn, dladdr_libc) { #endif Dl_info info; - void* addr = reinterpret_cast<void*>(puts); // well-known libc function + void* addr = reinterpret_cast<void*>(puts); // An arbitrary libc function. ASSERT_TRUE(dladdr(addr, &info) != 0); - char libc_realpath[PATH_MAX]; - // Check if libc is in canonical path or in alternate path. + const char* expected_path; if (strncmp(ALTERNATE_PATH_TO_SYSTEM_LIB, info.dli_fname, sizeof(ALTERNATE_PATH_TO_SYSTEM_LIB) - 1) == 0) { // Platform with emulated architecture. Symlink on ARC++. - ASSERT_TRUE(realpath(ALTERNATE_PATH_TO_LIBC, libc_realpath) == libc_realpath); + expected_path = ALTERNATE_PATH_TO_LIBC; } else if (strncmp(PATH_TO_BOOTSTRAP_LIBC, info.dli_fname, sizeof(PATH_TO_BOOTSTRAP_LIBC) - 1) == 0) { - ASSERT_TRUE(realpath(PATH_TO_BOOTSTRAP_LIBC, libc_realpath) == libc_realpath); + expected_path = PATH_TO_BOOTSTRAP_LIBC; } else { // /system/lib is symlink when this test is executed on host. - ASSERT_TRUE(realpath(PATH_TO_LIBC, libc_realpath) == libc_realpath); + expected_path = PATH_TO_LIBC; } + char libc_realpath[PATH_MAX]; + ASSERT_TRUE(realpath(expected_path, libc_realpath) != nullptr) << strerror(errno); ASSERT_STREQ(libc_realpath, info.dli_fname); // TODO: add check for dfi_fbase diff --git a/tests/hwasan_test.cpp b/tests/hwasan_test.cpp new file mode 100644 index 000000000..5c2149594 --- /dev/null +++ b/tests/hwasan_test.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 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 <dlfcn.h> +#include <stdlib.h> + +#include <gtest/gtest.h> + +#include <android-base/silent_death_test.h> +#include <android-base/test_utils.h> + +using HwasanDeathTest = SilentDeathTest; + +TEST_F(HwasanDeathTest, UseAfterFree) { + EXPECT_DEATH( + { + void* m = malloc(1); + volatile char* x = const_cast<volatile char*>(reinterpret_cast<char*>(m)); + *x = 1; + free(m); + *x = 2; + }, + "use-after-free"); +} + +TEST_F(HwasanDeathTest, OutOfBounds) { + EXPECT_DEATH( + { + void* m = malloc(1); + volatile char* x = const_cast<volatile char*>(reinterpret_cast<char*>(m)); + x[1] = 1; + }, + "buffer-overflow"); +} + +// Check whether dlopen of /foo/bar.so checks /foo/hwasan/bar.so first. +TEST(HwasanTest, DlopenAbsolutePath) { + std::string path = android::base::GetExecutableDirectory() + "/libtest_simple_hwasan.so"; + ASSERT_EQ(0, access(path.c_str(), F_OK)); // Verify test setup. + std::string hwasan_path = + android::base::GetExecutableDirectory() + "/hwasan/libtest_simple_hwasan.so"; + ASSERT_EQ(0, access(hwasan_path.c_str(), F_OK)); // Verify test setup. + + void* handle = dlopen(path.c_str(), RTLD_NOW); + ASSERT_TRUE(handle != nullptr); + uint32_t* compiled_with_hwasan = + reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_compiled_with_hwasan")); + EXPECT_TRUE(*compiled_with_hwasan); + dlclose(handle); +} + +TEST(HwasanTest, IsRunningWithHWasan) { + EXPECT_TRUE(running_with_hwasan()); +} diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp index 8ae22578e..a2fbe5532 100644 --- a/tests/libs/Android.bp +++ b/tests/libs/Android.bp @@ -243,6 +243,38 @@ cc_test_library { } // ----------------------------------------------------------------------------- +// Libraries used by hwasan_test +// ----------------------------------------------------------------------------- +cc_test_library { + name: "libtest_simple_hwasan", + arch: { + arm64: { + enabled: true, + }, + }, + sanitize: { + hwaddress: true, + }, + relative_install_path: "hwasan", + enabled: false, + srcs: ["dlopen_testlib_simple_hwasan.cpp"], +} + +cc_test_library { + // A weird name. This is the vanilla (non-HWASan) copy of the library that + // is used for the hwasan test. + name: "libtest_simple_hwasan_nohwasan", + arch: { + arm64: { + enabled: true, + }, + }, + stem: "libtest_simple_hwasan", + enabled: false, + srcs: ["dlopen_testlib_simple_hwasan.cpp"], +} + +// ----------------------------------------------------------------------------- // Library used by dlext direct unload on the namespace boundary tests // ----------------------------------------------------------------------------- cc_test_library { diff --git a/tests/libs/dlopen_testlib_simple_hwasan.cpp b/tests/libs/dlopen_testlib_simple_hwasan.cpp new file mode 100644 index 000000000..b92e05fd0 --- /dev/null +++ b/tests/libs/dlopen_testlib_simple_hwasan.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 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 <stdint.h> + +#if __has_feature(hwaddress_sanitizer) +extern "C" uint32_t dlopen_testlib_compiled_with_hwasan = true; +#else +extern "C" uint32_t dlopen_testlib_compiled_with_hwasan = false; +#endif + +extern "C" bool dlopen_testlib_simple_hwasan_func() { + return true; +} diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 590379cb6..1275b45e6 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -36,6 +36,7 @@ #include <android-base/file.h> #include <android-base/silent_death_test.h> +#include <android-base/strings.h> #include <android-base/test_utils.h> #include <android-base/unique_fd.h> @@ -140,6 +141,22 @@ TEST(STDIO_TEST, tmpfile64) { fclose(fp); } +TEST(STDIO_TEST, tmpfile_TMPDIR) { + TemporaryDir td; + setenv("TMPDIR", td.path, 1); + + FILE* fp = tmpfile(); + ASSERT_TRUE(fp != nullptr); + + std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fileno(fp)); + char path[PATH_MAX]; + ASSERT_GT(readlink(fd_path.c_str(), path, sizeof(path)), 0); + // $TMPDIR influenced where our temporary file ended up? + ASSERT_TRUE(android::base::StartsWith(path, td.path)) << path; + // And we used O_TMPFILE, right? + ASSERT_TRUE(android::base::EndsWith(path, " (deleted)")) << path; +} + TEST(STDIO_TEST, dprintf) { TemporaryFile tf; diff --git a/tests/sys_msg_test.cpp b/tests/sys_msg_test.cpp index 200f65437..da45087f9 100644 --- a/tests/sys_msg_test.cpp +++ b/tests/sys_msg_test.cpp @@ -74,9 +74,12 @@ TEST(sys_msg, smoke) { } TEST(sys_msg, msgctl_failure) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" errno = 0; ASSERT_EQ(-1, msgctl(-1, IPC_STAT, nullptr)); ASSERT_TRUE(errno == EINVAL || errno == ENOSYS); +#pragma clang diagnostic pop } TEST(sys_msg, msgget_failure) { @@ -86,9 +89,12 @@ TEST(sys_msg, msgget_failure) { } TEST(sys_msg, msgrcv_failure) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" errno = 0; ASSERT_EQ(-1, msgrcv(-1, nullptr, 0, 0, 0)); ASSERT_TRUE(errno == EINVAL || errno == ENOSYS); +#pragma clang diagnostic pop } TEST(sys_msg, msgsnd_failure) { diff --git a/tests/sys_random_test.cpp b/tests/sys_random_test.cpp index 2e2665b89..e0cbf7857 100644 --- a/tests/sys_random_test.cpp +++ b/tests/sys_random_test.cpp @@ -48,6 +48,8 @@ TEST(sys_random, getentropy) { } TEST(sys_random, getentropy_EFAULT) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" #if defined(HAVE_SYS_RANDOM) errno = 0; ASSERT_EQ(-1, getentropy(nullptr, 1)); @@ -55,6 +57,7 @@ TEST(sys_random, getentropy_EFAULT) { #else GTEST_SKIP() << "<sys/random.h> not available"; #endif +#pragma clang diagnostic pop } TEST(sys_random, getentropy_EIO) { @@ -84,6 +87,8 @@ TEST(sys_random, getrandom) { } TEST(sys_random, getrandom_EFAULT) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" #if defined(HAVE_SYS_RANDOM) errno = 0; ASSERT_EQ(-1, getrandom(nullptr, 256, 0)); @@ -91,6 +96,7 @@ TEST(sys_random, getrandom_EFAULT) { #else GTEST_SKIP() << "<sys/random.h> not available"; #endif +#pragma clang diagnostic pop } TEST(sys_random, getrandom_EINVAL) { diff --git a/tests/wchar_test.cpp b/tests/wchar_test.cpp index 16d434868..871681072 100644 --- a/tests/wchar_test.cpp +++ b/tests/wchar_test.cpp @@ -714,7 +714,8 @@ TEST(stdio, open_wmemstream_EINVAL) { #if defined(__BIONIC__) wchar_t* p; size_t size; - +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnonnull" // Invalid buffer. errno = 0; ASSERT_EQ(nullptr, open_wmemstream(nullptr, &size)); @@ -724,6 +725,7 @@ TEST(stdio, open_wmemstream_EINVAL) { errno = 0; ASSERT_EQ(nullptr, open_wmemstream(&p, nullptr)); ASSERT_EQ(EINVAL, errno); +#pragma clang diagnostic pop #else GTEST_SKIP() << "This test is bionic-specific"; #endif |