diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Android.bp | 7 | ||||
-rw-r--r-- | tests/NOTICE | 28 | ||||
-rw-r--r-- | tests/dlext_test.cpp | 14 | ||||
-rw-r--r-- | tests/fdsan_test.cpp | 1 | ||||
-rw-r--r-- | tests/grp_pwd_test.cpp | 38 | ||||
-rw-r--r-- | tests/libs/Android.bp | 46 | ||||
-rw-r--r-- | tests/libs/CHECK.h (renamed from tests/libs/libs_utils.h) | 13 | ||||
-rw-r--r-- | tests/libs/cfi_test_helper.cpp | 3 | ||||
-rw-r--r-- | tests/libs/cfi_test_helper2.cpp | 3 | ||||
-rw-r--r-- | tests/libs/dlopen_b.cpp | 7 | ||||
-rw-r--r-- | tests/libs/dlopen_testlib_depends_on_simple.cpp | 36 | ||||
-rw-r--r-- | tests/libs/preinit_getauxval_test_helper.cpp | 2 | ||||
-rw-r--r-- | tests/libs/preinit_syscall_test_helper.cpp | 2 | ||||
-rw-r--r-- | tests/libs/stack_tagging_helper.cpp | 2 | ||||
-rw-r--r-- | tests/libs/testbinary_is_stack_mte.cpp | 50 | ||||
-rw-r--r-- | tests/libs/testbinary_is_stack_mte_after_dlopen.cpp | 145 | ||||
-rw-r--r-- | tests/memtag_stack_dlopen_test.cpp | 153 | ||||
-rw-r--r-- | tests/mte_utils.h | 43 | ||||
-rw-r--r-- | tests/netinet_ether_test.cpp | 1 | ||||
-rw-r--r-- | tests/unistd_test.cpp | 44 |
20 files changed, 490 insertions, 148 deletions
diff --git a/tests/Android.bp b/tests/Android.bp index 0ba91eac2..78c2c1083 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -1127,7 +1127,12 @@ cc_test { shared_libs: [ "libbase", ], - data_libs: ["libtest_simple_memtag_stack"], + data_libs: ["libtest_simple_memtag_stack", "libtest_depends_on_simple_memtag_stack"], + data_bins: [ + "testbinary_depends_on_simple_memtag_stack", + "testbinary_depends_on_depends_on_simple_memtag_stack", + "testbinary_is_stack_mte_after_dlopen" + ], header_libs: ["bionic_libc_platform_headers"], test_suites: ["device-tests"], } diff --git a/tests/NOTICE b/tests/NOTICE index cc99d2053..de95698cf 100644 --- a/tests/NOTICE +++ b/tests/NOTICE @@ -454,3 +454,31 @@ SUCH DAMAGE. ------------------------------------------------------------------- +Copyright (C) 2024 The Android Open Source Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +------------------------------------------------------------------- + diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 6883da9b5..d078e500b 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -31,7 +31,6 @@ #include <android-base/test_utils.h> #include <sys/mman.h> -#include <sys/stat.h> #include <sys/types.h> #include <sys/vfs.h> #include <sys/wait.h> @@ -2047,11 +2046,6 @@ TEST(dlext, ns_anonymous) { -1, 0)); ASSERT_TRUE(reinterpret_cast<void*>(reserved_addr) != MAP_FAILED); - struct stat file_stat; - int ret = TEMP_FAILURE_RETRY(stat(private_library_absolute_path.c_str(), &file_stat)); - ASSERT_EQ(ret, 0) << "Failed to stat library"; - size_t file_size = file_stat.st_size; - for (const auto& rec : maps_to_copy) { uintptr_t offset = rec.addr_start - addr_start; size_t size = rec.addr_end - rec.addr_start; @@ -2059,13 +2053,7 @@ TEST(dlext, ns_anonymous) { void* map = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0); ASSERT_TRUE(map != MAP_FAILED); - size_t seg_size = size; - // See comment on file map fault in ElfReader::LoadSegments() - // bionic/linker/linker_phdr.cpp - if (rec.offset + size > file_size) { - seg_size = file_size - rec.offset; - } - memcpy(map, reinterpret_cast<void*>(rec.addr_start), seg_size); + memcpy(map, reinterpret_cast<void*>(rec.addr_start), size); mprotect(map, size, rec.perms); } diff --git a/tests/fdsan_test.cpp b/tests/fdsan_test.cpp index 016970ffb..c1e926b14 100644 --- a/tests/fdsan_test.cpp +++ b/tests/fdsan_test.cpp @@ -33,7 +33,6 @@ #include <android-base/silent_death_test.h> #include <android-base/unique_fd.h> -#define FDSAN_TEST(test_name) TEST_F(FdsanTest, test_name) #define EXPECT_FDSAN_DEATH(expression, regex) \ EXPECT_DEATH((android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL), expression), \ (regex)) diff --git a/tests/grp_pwd_test.cpp b/tests/grp_pwd_test.cpp index d3acf03d1..ddc0fc15c 100644 --- a/tests/grp_pwd_test.cpp +++ b/tests/grp_pwd_test.cpp @@ -444,16 +444,33 @@ static void expect_ids(T ids, bool is_group) { return result; }; - // AID_PRNG_SEEDER (1092) was added in TM-QPR2, but CTS is shared - // across Android 13 versions so we may or may not find it in this - // test (b/253185870). - if (android::base::GetIntProperty("ro.build.version.sdk", 0) == __ANDROID_API_T__) { -#ifndef AID_PRNG_SEEDER -#define AID_PRNG_SEEDER 1092 + // AID_UPROBESTATS (1093) was added in V, but "trunk stable" means + // that the 2024Q builds don't have branches like the QPR builds used + // to, and are tested with the _previous_ release's CTS. + if (android::base::GetIntProperty("ro.build.version.sdk", 0) == __ANDROID_API_U__) { +#if !defined(AID_UPROBESTATS) +#define AID_UPROBESTATS 1093 #endif - ids.erase(AID_PRNG_SEEDER); - expected_ids.erase(AID_PRNG_SEEDER); + ids.erase(AID_UPROBESTATS); + expected_ids.erase(AID_UPROBESTATS); + if (getpwuid(AID_UPROBESTATS)) { + EXPECT_STREQ(getpwuid(AID_UPROBESTATS)->pw_name, "uprobestats"); + } + } + // AID_VIRTUALMACHINE (3013) was added in V, but "trunk stable" means + // that the 2024Q builds don't have branches like the QPR builds used + // to, and are tested with the _previous_ release's CTS. + if (android::base::GetIntProperty("ro.build.version.sdk", 0) == __ANDROID_API_U__) { +#if !defined(AID_VIRTUALMACHINE) +#define AID_VIRTUALMACHINE 3013 +#endif + ids.erase(AID_VIRTUALMACHINE); + expected_ids.erase(AID_VIRTUALMACHINE); + if (getpwuid(AID_VIRTUALMACHINE)) { + EXPECT_STREQ(getpwuid(AID_VIRTUALMACHINE)->pw_name, "virtualmachine"); + } } + EXPECT_EQ(expected_ids, ids) << return_differences(); } #endif @@ -851,6 +868,11 @@ TEST(grp, getgrouplist) { #endif } +TEST(grp, initgroups) { + if (getuid() != 0) GTEST_SKIP() << "test requires root"; + ASSERT_EQ(0, initgroups("root", 0)); +} + #if defined(__BIONIC__) static void TestAidNamePrefix(const std::string& file_path) { std::string file_contents; diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp index 68efbd970..06ee132d4 100644 --- a/tests/libs/Android.bp +++ b/tests/libs/Android.bp @@ -234,7 +234,7 @@ cc_test_library { } // ----------------------------------------------------------------------------- -// Library used by memtag_stack_dlopen_test tests +// Libraries and binaries used by memtag_stack_dlopen_test tests // ----------------------------------------------------------------------------- cc_test_library { name: "libtest_simple_memtag_stack", @@ -244,6 +244,50 @@ cc_test_library { srcs: ["dlopen_testlib_simple.cpp"], } +cc_test_library { + name: "libtest_depends_on_simple_memtag_stack", + sanitize: { + memtag_stack: false, + }, + shared_libs: [ + "libtest_simple_memtag_stack", + ], + srcs: ["dlopen_testlib_depends_on_simple.cpp"], +} + +cc_binary { + name: "testbinary_is_stack_mte_after_dlopen", + sanitize: { + memtag_stack: false, + memtag_heap: true, + }, + srcs: ["testbinary_is_stack_mte_after_dlopen.cpp"], +} + +cc_binary { + name: "testbinary_depends_on_simple_memtag_stack", + sanitize: { + memtag_stack: false, + memtag_heap: true, + }, + shared_libs: [ + "libtest_simple_memtag_stack", + ], + srcs: ["testbinary_is_stack_mte.cpp"], +} + +cc_binary { + name: "testbinary_depends_on_depends_on_simple_memtag_stack", + sanitize: { + memtag_stack: false, + memtag_heap: true, + }, + shared_libs: [ + "libtest_depends_on_simple_memtag_stack", + ], + srcs: ["testbinary_is_stack_mte.cpp"], +} + // ----------------------------------------------------------------------------- // Libraries used by hwasan_test // ----------------------------------------------------------------------------- diff --git a/tests/libs/libs_utils.h b/tests/libs/CHECK.h index 7dae2414d..2575d5b79 100644 --- a/tests/libs/libs_utils.h +++ b/tests/libs/CHECK.h @@ -14,14 +14,13 @@ * limitations under the License. */ -#ifndef LIBS_UTILS_H -#define LIBS_UTILS_H +#pragma once + +// Tests proper can use libbase, but libraries for testing dlopen() +// should probably avoid dependencies other than ones we're specifically +// trying to test. #include <assert.h> -#include <stdio.h> -#include <stdlib.h> #define CHECK(e) \ - ((e) ? static_cast<void>(0) : __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, #e)) - -#endif // LIBS_UTILS_H + ((e) ? static_cast<void>(0) : __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__, #e)) diff --git a/tests/libs/cfi_test_helper.cpp b/tests/libs/cfi_test_helper.cpp index c1a7b6d18..71cdc8975 100644 --- a/tests/libs/cfi_test_helper.cpp +++ b/tests/libs/cfi_test_helper.cpp @@ -14,11 +14,10 @@ * limitations under the License. */ -#include <assert.h> #include <stdint.h> #include <stdlib.h> -#include "libs_utils.h" +#include "CHECK.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. diff --git a/tests/libs/cfi_test_helper2.cpp b/tests/libs/cfi_test_helper2.cpp index 11a6036c0..d7cd4957a 100644 --- a/tests/libs/cfi_test_helper2.cpp +++ b/tests/libs/cfi_test_helper2.cpp @@ -14,10 +14,9 @@ * limitations under the License. */ -#include <assert.h> #include <dlfcn.h> -#include "libs_utils.h" +#include "CHECK.h" int main(void) { void* handle; diff --git a/tests/libs/dlopen_b.cpp b/tests/libs/dlopen_b.cpp index 092c96c95..5b3624292 100644 --- a/tests/libs/dlopen_b.cpp +++ b/tests/libs/dlopen_b.cpp @@ -1,8 +1,9 @@ #include <dlfcn.h> -extern "C" void *dlopen_b() { - // Work around for http://b/20049306, which isn't going to be fixed. - static int defeat_sibling_call_optimization = 0; +// Work around for http://b/20049306, which isn't going to be fixed. +int defeat_sibling_call_optimization = 0; + +extern "C" void* dlopen_b() { // This is supposed to succeed because this library has DT_RUNPATH // for libtest_dt_runpath_x.so which should be taken into account // by dlopen. diff --git a/tests/libs/dlopen_testlib_depends_on_simple.cpp b/tests/libs/dlopen_testlib_depends_on_simple.cpp new file mode 100644 index 000000000..3652be8da --- /dev/null +++ b/tests/libs/dlopen_testlib_depends_on_simple.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdlib.h> + +extern "C" bool dlopen_testlib_simple_func(); + +extern "C" bool dlopen_testlib_call_simple_func() { + return dlopen_testlib_simple_func(); +} diff --git a/tests/libs/preinit_getauxval_test_helper.cpp b/tests/libs/preinit_getauxval_test_helper.cpp index 2a79b97a1..53d4cc9c6 100644 --- a/tests/libs/preinit_getauxval_test_helper.cpp +++ b/tests/libs/preinit_getauxval_test_helper.cpp @@ -19,7 +19,7 @@ #include <unistd.h> #include <sys/auxv.h> -#include "libs_utils.h" +#include "CHECK.h" static unsigned long g_AT_RANDOM; static unsigned long g_AT_PAGESZ; diff --git a/tests/libs/preinit_syscall_test_helper.cpp b/tests/libs/preinit_syscall_test_helper.cpp index 9b6b6dfc4..3ca8131ac 100644 --- a/tests/libs/preinit_syscall_test_helper.cpp +++ b/tests/libs/preinit_syscall_test_helper.cpp @@ -19,7 +19,7 @@ #include <unistd.h> #include <sys/auxv.h> -#include "libs_utils.h" +#include "CHECK.h" static ssize_t g_result; static int g_errno; diff --git a/tests/libs/stack_tagging_helper.cpp b/tests/libs/stack_tagging_helper.cpp index 7396dd00d..e7e26aff3 100644 --- a/tests/libs/stack_tagging_helper.cpp +++ b/tests/libs/stack_tagging_helper.cpp @@ -28,7 +28,7 @@ #include <bionic/malloc.h> -#include "libs_utils.h" +#include "CHECK.h" #if defined(__aarch64__) diff --git a/tests/libs/testbinary_is_stack_mte.cpp b/tests/libs/testbinary_is_stack_mte.cpp new file mode 100644 index 000000000..d8074d55d --- /dev/null +++ b/tests/libs/testbinary_is_stack_mte.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "../mte_utils.h" +#include "CHECK.h" + +#if defined(__BIONIC__) && defined(__aarch64__) + +extern "C" int main(int, char**) { + int ret = is_stack_mte_on() ? 0 : 1; + printf("RAN\n"); + return ret; +} + +#else + +extern "C" int main(int, char**) { + printf("RAN\n"); + return 1; +} +#endif diff --git a/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp b/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp new file mode 100644 index 000000000..937ac4c38 --- /dev/null +++ b/tests/libs/testbinary_is_stack_mte_after_dlopen.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <condition_variable> +#include <thread> + +#include <dlfcn.h> +#include <inttypes.h> +#include <stdlib.h> +#include <unistd.h> + +#include "../mte_utils.h" +#include "CHECK.h" + +#if defined(__BIONIC__) && defined(__aarch64__) + +enum State { kInit, kThreadStarted, kStackRemapped }; + +// We can't use pthread_getattr_np because that uses the rlimit rather than the actual mapping +// bounds. +static void find_main_stack_limits(uintptr_t* low, uintptr_t* high) { + uintptr_t startstack = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); + + // Hunt for the region that contains that address. + FILE* fp = fopen("/proc/self/maps", "re"); + if (fp == nullptr) { + abort(); + } + char line[BUFSIZ]; + while (fgets(line, sizeof(line), fp) != nullptr) { + uintptr_t lo, hi; + if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) { + if (lo <= startstack && startstack <= hi) { + *low = lo; + *high = hi; + fclose(fp); + return; + } + } + } + abort(); +} + +template <typename Fn> +unsigned int fault_new_stack_page(uintptr_t low, Fn f) { + uintptr_t new_low; + uintptr_t new_high; + volatile char buf[4096]; + buf[4095] = 1; + find_main_stack_limits(&new_low, &new_high); + if (new_low < low) { + f(); + return new_high; + } + // Useless, but should defeat TCO. + return new_low + fault_new_stack_page(low, f); +} +extern "C" int main(int argc, char** argv) { + if (argc < 2) { + return 1; + } + const char* path = argv[1]; + CHECK(access(path, F_OK) == 0); // Verify test setup. + CHECK(!is_stack_mte_on()); + std::mutex m; + std::condition_variable cv; + State state = kInit; + + bool is_early_thread_mte_on = false; + std::thread early_th([&] { + { + std::lock_guard lk(m); + state = kThreadStarted; + } + cv.notify_one(); + { + std::unique_lock lk(m); + cv.wait(lk, [&] { return state == kStackRemapped; }); + } + is_early_thread_mte_on = is_stack_mte_on(); + }); + { + std::unique_lock lk(m); + cv.wait(lk, [&] { return state == kThreadStarted; }); + } + void* handle = dlopen(path, RTLD_NOW); + { + std::lock_guard lk(m); + state = kStackRemapped; + } + cv.notify_one(); + CHECK(handle != nullptr); + CHECK(is_stack_mte_on()); + + bool new_stack_page_mte_on = false; + uintptr_t low; + uintptr_t high; + find_main_stack_limits(&low, &high); + fault_new_stack_page(low, [&] { new_stack_page_mte_on = is_stack_mte_on(); }); + CHECK(new_stack_page_mte_on); + + bool is_late_thread_mte_on = false; + std::thread late_th([&] { is_late_thread_mte_on = is_stack_mte_on(); }); + late_th.join(); + early_th.join(); + CHECK(is_late_thread_mte_on); + CHECK(is_early_thread_mte_on); + printf("RAN\n"); + return 0; +} + +#else +extern "C" int main(int, char**) { + return 1; +} +#endif diff --git a/tests/memtag_stack_dlopen_test.cpp b/tests/memtag_stack_dlopen_test.cpp index 308af1eb9..68ddb81bd 100644 --- a/tests/memtag_stack_dlopen_test.cpp +++ b/tests/memtag_stack_dlopen_test.cpp @@ -35,113 +35,82 @@ #include <android-base/silent_death_test.h> #include <android-base/test_utils.h> +#include "mte_utils.h" #include "utils.h" +TEST(MemtagStackDlopenTest, DependentBinaryGetsMemtagStack) { #if defined(__BIONIC__) && defined(__aarch64__) -__attribute__((target("mte"))) bool is_stack_mte_on() { - alignas(16) int x = 0; - void* p = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(&x) + (1UL << 57)); - void* p_cpy = p; - __builtin_arm_stg(p); - p = __builtin_arm_ldg(p); - __builtin_arm_stg(&x); - return p == p_cpy; -} - -// We can't use pthread_getattr_np because that uses the rlimit rather than the actual mapping -// bounds. -static void find_main_stack_limits(uintptr_t* low, uintptr_t* high) { - uintptr_t startstack = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); + if (!running_with_mte()) GTEST_SKIP() << "Test requires MTE."; + if (is_stack_mte_on()) + GTEST_SKIP() << "Stack MTE needs to be off for this test. Are you running fullmte?"; - // Hunt for the region that contains that address. - FILE* fp = fopen("/proc/self/maps", "re"); - if (fp == nullptr) { - abort(); - } - char line[BUFSIZ]; - while (fgets(line, sizeof(line), fp) != nullptr) { - uintptr_t lo, hi; - if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR, &lo, &hi) == 2) { - if (lo <= startstack && startstack <= hi) { - *low = lo; - *high = hi; - fclose(fp); - return; - } - } - } - abort(); + std::string path = + android::base::GetExecutableDirectory() + "/testbinary_depends_on_simple_memtag_stack"; + ExecTestHelper eth; + std::string ld_library_path = "LD_LIBRARY_PATH=" + android::base::GetExecutableDirectory(); + eth.SetArgs({path.c_str(), nullptr}); + eth.SetEnv({ld_library_path.c_str(), nullptr}); + eth.Run([&]() { execve(path.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "RAN"); +#else + GTEST_SKIP() << "requires bionic arm64"; +#endif } -template <typename Fn> -unsigned int fault_new_stack_page(uintptr_t low, Fn f) { - uintptr_t new_low; - uintptr_t new_high; - volatile char buf[4096]; - buf[4095] = 1; - find_main_stack_limits(&new_low, &new_high); - if (new_low < low) { - f(); - return new_high; - } - // Useless, but should defeat TCO. - return new_low + fault_new_stack_page(low, f); -} +TEST(MemtagStackDlopenTest, DependentBinaryGetsMemtagStack2) { +#if defined(__BIONIC__) && defined(__aarch64__) + if (!running_with_mte()) GTEST_SKIP() << "Test requires MTE."; + if (is_stack_mte_on()) + GTEST_SKIP() << "Stack MTE needs to be off for this test. Are you running fullmte?"; + std::string path = android::base::GetExecutableDirectory() + + "/testbinary_depends_on_depends_on_simple_memtag_stack"; + ExecTestHelper eth; + std::string ld_library_path = "LD_LIBRARY_PATH=" + android::base::GetExecutableDirectory(); + eth.SetArgs({path.c_str(), nullptr}); + eth.SetEnv({ld_library_path.c_str(), nullptr}); + eth.Run([&]() { execve(path.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "RAN"); +#else + GTEST_SKIP() << "requires bionic arm64"; #endif - -enum State { kInit, kThreadStarted, kStackRemapped }; +} TEST(MemtagStackDlopenTest, DlopenRemapsStack) { #if defined(__BIONIC__) && defined(__aarch64__) + // If this test is failing, look at crash logcat for why the test binary died. if (!running_with_mte()) GTEST_SKIP() << "Test requires MTE."; + if (is_stack_mte_on()) + GTEST_SKIP() << "Stack MTE needs to be off for this test. Are you running fullmte?"; - std::string path = android::base::GetExecutableDirectory() + "/libtest_simple_memtag_stack.so"; - ASSERT_EQ(0, access(path.c_str(), F_OK)); // Verify test setup. - EXPECT_FALSE(is_stack_mte_on()); - std::mutex m; - std::condition_variable cv; - State state = kInit; - - bool is_early_thread_mte_on = false; - std::thread early_th([&] { - { - std::lock_guard lk(m); - state = kThreadStarted; - } - cv.notify_one(); - { - std::unique_lock lk(m); - cv.wait(lk, [&] { return state == kStackRemapped; }); - } - is_early_thread_mte_on = is_stack_mte_on(); - }); - { - std::unique_lock lk(m); - cv.wait(lk, [&] { return state == kThreadStarted; }); - } - void* handle = dlopen(path.c_str(), RTLD_NOW); - { - std::lock_guard lk(m); - state = kStackRemapped; - } - cv.notify_one(); - ASSERT_NE(handle, nullptr); - EXPECT_TRUE(is_stack_mte_on()); + std::string path = + android::base::GetExecutableDirectory() + "/testbinary_is_stack_mte_after_dlopen"; + std::string lib_path = + android::base::GetExecutableDirectory() + "/libtest_simple_memtag_stack.so"; + ExecTestHelper eth; + std::string ld_library_path = "LD_LIBRARY_PATH=" + android::base::GetExecutableDirectory(); + eth.SetArgs({path.c_str(), lib_path.c_str(), nullptr}); + eth.SetEnv({ld_library_path.c_str(), nullptr}); + eth.Run([&]() { execve(path.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "RAN"); +#else + GTEST_SKIP() << "requires bionic arm64"; +#endif +} - bool new_stack_page_mte_on = false; - uintptr_t low; - uintptr_t high; - find_main_stack_limits(&low, &high); - fault_new_stack_page(low, [&] { new_stack_page_mte_on = is_stack_mte_on(); }); - EXPECT_TRUE(new_stack_page_mte_on); +TEST(MemtagStackDlopenTest, DlopenRemapsStack2) { +#if defined(__BIONIC__) && defined(__aarch64__) + // If this test is failing, look at crash logcat for why the test binary died. + if (!running_with_mte()) GTEST_SKIP() << "Test requires MTE."; + if (is_stack_mte_on()) + GTEST_SKIP() << "Stack MTE needs to be off for this test. Are you running fullmte?"; - bool is_late_thread_mte_on = false; - std::thread late_th([&] { is_late_thread_mte_on = is_stack_mte_on(); }); - late_th.join(); - early_th.join(); - EXPECT_TRUE(is_early_thread_mte_on); - EXPECT_TRUE(is_late_thread_mte_on); + std::string path = + android::base::GetExecutableDirectory() + "/testbinary_is_stack_mte_after_dlopen"; + std::string lib_path = + android::base::GetExecutableDirectory() + "/libtest_depends_on_simple_memtag_stack.so"; + ExecTestHelper eth; + std::string ld_library_path = "LD_LIBRARY_PATH=" + android::base::GetExecutableDirectory(); + eth.SetArgs({path.c_str(), lib_path.c_str(), nullptr}); + eth.SetEnv({ld_library_path.c_str(), nullptr}); + eth.Run([&]() { execve(path.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, "RAN"); #else GTEST_SKIP() << "requires bionic arm64"; #endif diff --git a/tests/mte_utils.h b/tests/mte_utils.h new file mode 100644 index 000000000..6e8385cc6 --- /dev/null +++ b/tests/mte_utils.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma once + +#if defined(__BIONIC__) && defined(__aarch64__) + +__attribute__((target("mte"))) static bool is_stack_mte_on() { + alignas(16) int x = 0; + void* p = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(&x) + (1UL << 57)); + void* p_cpy = p; + __builtin_arm_stg(p); + p = __builtin_arm_ldg(p); + __builtin_arm_stg(&x); + return p == p_cpy; +} + +#endif diff --git a/tests/netinet_ether_test.cpp b/tests/netinet_ether_test.cpp index af020ec93..d7b81eb8d 100644 --- a/tests/netinet_ether_test.cpp +++ b/tests/netinet_ether_test.cpp @@ -56,4 +56,5 @@ TEST(netinet_ether, ether_aton_r_failures) { ASSERT_TRUE(ether_aton_r("12:34:56:78:9a:bc ", &addr) == nullptr); ASSERT_TRUE(ether_aton_r("g2:34:56:78:9a:bc ", &addr) == nullptr); ASSERT_TRUE(ether_aton_r("1G:34:56:78:9a:bc ", &addr) == nullptr); + ASSERT_TRUE(ether_aton_r("123:34:56:78:9a:bc ", &addr) == nullptr); } diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp index e9a30809f..6c08972e6 100644 --- a/tests/unistd_test.cpp +++ b/tests/unistd_test.cpp @@ -753,22 +753,36 @@ TEST(UNISTD_TEST, gethostname) { TEST(UNISTD_TEST, pathconf_fpathconf) { TemporaryFile tf; - long rc = 0L; + long l; + // As a file system's block size is always power of 2, the configure values // for ALLOC and XFER should be power of 2 as well. - rc = pathconf(tf.path, _PC_ALLOC_SIZE_MIN); - ASSERT_TRUE(rc > 0 && powerof2(rc)); - rc = pathconf(tf.path, _PC_REC_MIN_XFER_SIZE); - ASSERT_TRUE(rc > 0 && powerof2(rc)); - rc = pathconf(tf.path, _PC_REC_XFER_ALIGN); - ASSERT_TRUE(rc > 0 && powerof2(rc)); - - rc = fpathconf(tf.fd, _PC_ALLOC_SIZE_MIN); - ASSERT_TRUE(rc > 0 && powerof2(rc)); - rc = fpathconf(tf.fd, _PC_REC_MIN_XFER_SIZE); - ASSERT_TRUE(rc > 0 && powerof2(rc)); - rc = fpathconf(tf.fd, _PC_REC_XFER_ALIGN); - ASSERT_TRUE(rc > 0 && powerof2(rc)); + l = pathconf(tf.path, _PC_ALLOC_SIZE_MIN); + ASSERT_TRUE(l > 0 && powerof2(l)); + l = pathconf(tf.path, _PC_REC_MIN_XFER_SIZE); + ASSERT_TRUE(l > 0 && powerof2(l)); + l = pathconf(tf.path, _PC_REC_XFER_ALIGN); + ASSERT_TRUE(l > 0 && powerof2(l)); + + l = fpathconf(tf.fd, _PC_ALLOC_SIZE_MIN); + ASSERT_TRUE(l > 0 && powerof2(l)); + l = fpathconf(tf.fd, _PC_REC_MIN_XFER_SIZE); + ASSERT_TRUE(l > 0 && powerof2(l)); + l = fpathconf(tf.fd, _PC_REC_XFER_ALIGN); + ASSERT_TRUE(l > 0 && powerof2(l)); + + // Check that the "I can't answer that, you'll have to try it and see" + // cases don't set errno. + int names[] = { + _PC_ASYNC_IO, _PC_PRIO_IO, _PC_REC_INCR_XFER_SIZE, _PC_REC_MAX_XFER_SIZE, _PC_SYMLINK_MAX, + _PC_SYNC_IO, -1}; + for (size_t i = 0; names[i] != -1; i++) { + errno = 0; + ASSERT_EQ(-1, pathconf(tf.path, names[i])) << names[i]; + ASSERT_ERRNO(0) << names[i]; + ASSERT_EQ(-1, fpathconf(tf.fd, names[i])) << names[i]; + ASSERT_ERRNO(0) << names[i]; + } } TEST(UNISTD_TEST, _POSIX_constants) { @@ -968,7 +982,7 @@ TEST(UNISTD_TEST, sysconf) { VERIFY_SYSCONF_POSIX_VERSION(_SC_CPUTIME); VERIFY_SYSCONF_POSITIVE(_SC_EXPR_NEST_MAX); VERIFY_SYSCONF_POSITIVE(_SC_LINE_MAX); - VERIFY_SYSCONF_POSITIVE(_SC_NGROUPS_MAX); + VerifySysconf(_SC_NGROUPS_MAX, "_SC_NGROUPS_MAX", [](long v){return v >= 0 && v <= NGROUPS_MAX;}); VERIFY_SYSCONF_POSITIVE(_SC_OPEN_MAX); VERIFY_SYSCONF_POSITIVE(_SC_PASS_MAX); VERIFY_SYSCONF_POSIX_VERSION(_SC_2_C_BIND); |