Merge "Fix mte tests to allow auto-upgrade."
diff --git a/tests/heap_tagging_level_test.cpp b/tests/heap_tagging_level_test.cpp
index cfb2490..c493e1d 100644
--- a/tests/heap_tagging_level_test.cpp
+++ b/tests/heap_tagging_level_test.cpp
@@ -81,10 +81,20 @@
#endif // defined(__BIONIC__)
}
+namespace {
#if defined(__BIONIC__) && defined(__aarch64__)
void ExitWithSiCode(int, siginfo_t* info, void*) {
_exit(info->si_code);
}
+
+template <typename Pred>
+class Or {
+ Pred A, B;
+
+ public:
+ Or(Pred A, Pred B) : A(A), B(B) {}
+ bool operator()(int exit_status) { return A(exit_status) || B(exit_status); }
+};
#endif
TEST(heap_tagging_level, sync_async_bad_accesses_die) {
@@ -94,6 +104,7 @@
}
std::unique_ptr<int[]> p = std::make_unique<int[]>(4);
+ volatile int sink ATTRIBUTE_UNUSED;
// We assume that scudo is used on all MTE enabled hardware; scudo inserts a header with a
// mismatching tag before each allocation.
@@ -104,6 +115,12 @@
p[-1] = 42;
},
testing::ExitedWithCode(SEGV_MTESERR), "");
+ EXPECT_EXIT(
+ {
+ ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO);
+ sink = p[-1];
+ },
+ testing::ExitedWithCode(SEGV_MTESERR), "");
EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_ASYNC));
EXPECT_EXIT(
@@ -111,14 +128,21 @@
ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO);
p[-1] = 42;
},
- testing::ExitedWithCode(SEGV_MTEAERR), "");
+ Or(testing::ExitedWithCode(SEGV_MTESERR), testing::ExitedWithCode(SEGV_MTEAERR)), "");
+ EXPECT_EXIT(
+ {
+ ScopedSignalHandler ssh(SIGSEGV, ExitWithSiCode, SA_SIGINFO);
+ sink = p[-1];
+ },
+ Or(testing::ExitedWithCode(SEGV_MTESERR), testing::ExitedWithCode(SEGV_MTEAERR)), "");
EXPECT_TRUE(SetHeapTaggingLevel(M_HEAP_TAGGING_LEVEL_NONE));
- volatile int oob ATTRIBUTE_UNUSED = p[-1];
+ sink = p[-1];
#else
GTEST_SKIP() << "bionic/arm64 only";
#endif
}
+} // namespace
TEST(heap_tagging_level, none_pointers_untagged) {
#if defined(__BIONIC__)
@@ -205,7 +229,9 @@
const char* kNoteSuffix[] = {"disabled", "async", "sync"};
const char* kExpectedOutputHWASAN[] = {".*tag-mismatch.*", ".*tag-mismatch.*",
".*tag-mismatch.*"};
- const char* kExpectedOutputMTE[] = {"normal exit\n", "SEGV_MTEAERR\n", "SEGV_MTESERR\n"};
+ // Note that we do not check the exact si_code of the "async" variant, as it may be auto-upgraded
+ // to asymm or even sync.
+ const char* kExpectedOutputMTE[] = {"normal exit\n", "SEGV_MTE[AS]ERR\n", "SEGV_MTESERR\n"};
const char* kExpectedOutputNonMTE[] = {"normal exit\n", "normal exit\n", "normal exit\n"};
const char** kExpectedOutput =
withHWASAN ? kExpectedOutputHWASAN : (withMTE ? kExpectedOutputMTE : kExpectedOutputNonMTE);
@@ -215,7 +241,6 @@
bool isStatic = std::get<1>(GetParam());
std::string helper_base = std::string("heap_tagging_") + (isStatic ? "static_" : "") +
kNoteSuffix[static_cast<int>(note)] + "_helper";
- fprintf(stderr, "=== %s\n", helper_base.c_str());
std::string helper = GetTestlibRoot() + "/" + helper_base;
chmod(helper.c_str(), 0755);
ExecTestHelper eth;
diff --git a/tests/libs/heap_tagging_helper.cpp b/tests/libs/heap_tagging_helper.cpp
index 1a970f2..16a8c8b 100644
--- a/tests/libs/heap_tagging_helper.cpp
+++ b/tests/libs/heap_tagging_helper.cpp
@@ -16,7 +16,9 @@
#include <signal.h>
#include <stdio.h>
+#include <sys/auxv.h>
#include <sys/cdefs.h>
+#include <sys/mman.h>
#include <unistd.h>
#include <memory>
@@ -37,6 +39,11 @@
_exit(0);
}
+void action2(int signo, siginfo_t* info __unused, void*) {
+ fprintf(stderr, "unexpected signal %d\n", signo);
+ _exit(0);
+}
+
__attribute__((optnone)) int main() {
struct sigaction sa = {};
sa.sa_sigaction = action;
@@ -47,6 +54,37 @@
volatile int oob = p[-1];
(void)oob;
+#if defined(__BIONIC__) && defined(__aarch64__)
+ // If we get here, bad access on system heap memory did not trigger a fault.
+ // This suggests that MTE is disabled. Make sure that explicitly tagged PROT_MTE memory does not
+ // trigger a fault either.
+ if (getauxval(AT_HWCAP2) & HWCAP2_MTE) {
+ sa.sa_sigaction = action2;
+ sigaction(SIGSEGV, &sa, nullptr);
+
+ size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
+ void* p = mmap(nullptr, page_size, PROT_READ | PROT_WRITE | PROT_MTE,
+ MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
+ if (!p) {
+ fprintf(stderr, "mmap failed\n");
+ return 1;
+ }
+
+ void* q = p;
+ __asm__ __volatile__(
+ ".arch_extension memtag\n"
+ "irg %[Ptr], %[Ptr], xzr\n"
+ "stg %[Ptr], [%[Ptr]]\n"
+ "addg %[Ptr], %[Ptr], 0, 1\n"
+ "str xzr, [%[Ptr]]\n"
+ : [Ptr] "+&r"(q)
+ :
+ : "memory");
+
+ munmap(p, page_size);
+ }
+#endif // __aarch64__
+
fprintf(stderr, "normal exit\n");
return 0;
}