blob: 46454c5e9d66c726ea2dcb37cd31d83349694eaf [file] [log] [blame]
Evgenii Stepanov68ecec12017-01-31 13:19:30 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Evgenii Stepanovbeb3eb12017-01-31 17:10:03 -080017#include <dlfcn.h>
hanglfda4c102025-04-30 12:13:05 -070018#include <link.h>
Evgenii Stepanov68ecec12017-01-31 13:19:30 -080019#include <sys/stat.h>
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070020
Christopher Ferrisf3224832020-04-01 16:59:57 -070021#include <vector>
22
Elliott Hughes141b9172021-04-09 17:13:09 -070023#include <gtest/gtest.h>
24
Evgenii Stepanov68ecec12017-01-31 13:19:30 -080025#include "gtest_globals.h"
26#include "utils.h"
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070027
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070028#if defined(__BIONIC__)
29#include "private/CFIShadow.h"
30#endif
31
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070032// Private libdl interface.
33extern "C" {
34void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr);
35void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData);
Evgenii Stepanov97c16f82017-08-02 16:34:44 -070036size_t __cfi_shadow_size();
hanglfda4c102025-04-30 12:13:05 -070037uintptr_t __cfi_shadow_load(void* p);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070038}
39
Elliott Hughes4411b942022-02-09 15:56:27 -080040// Disables debuggerd stack traces to speed up death tests, make them less
41// noisy in logcat, and avoid expected deaths from showing up in stability
42// metrics.
43// We don't use the usual libbase class because (a) we don't care about most
44// of the signals it blocks but (b) we do need to block SIGILL, which normal
45// death tests shouldn't ever hit. (It's possible that a design where a
46// deathtest always declares its expected signals up front is a better one,
47// and maybe that's an interesting future direction for libbase.)
Elliott Hughes82e24a52022-02-15 10:12:23 -080048//
49// We include SIGSEGV because there's a test that passes heap addresses to
50// __cfi_slowpath and we only map the executable code shadow as readable.
51// We don't always get SIGSEGV there though: if the heap allocation happens
52// to be close enough to an executable mapping that its shadow is in the
53// same page as the executable shadow, we'll get SIGILL/SIGTRAP.
Elliott Hughes4411b942022-02-09 15:56:27 -080054class cfi_test_DeathTest : public testing::Test {
55 protected:
56 void SetUp() override {
57 struct sigaction64 action = {.sa_handler = SIG_DFL};
Elliott Hughes4411b942022-02-09 15:56:27 -080058 sigaction64(SIGILL, &action, &previous_sigill_);
Elliott Hughes82e24a52022-02-15 10:12:23 -080059 sigaction64(SIGSEGV, &action, &previous_sigsegv_);
60 sigaction64(SIGTRAP, &action, &previous_sigtrap_);
Elliott Hughes4411b942022-02-09 15:56:27 -080061 }
62
63 void TearDown() override {
Elliott Hughes82e24a52022-02-15 10:12:23 -080064 sigaction64(SIGTRAP, &previous_sigtrap_, nullptr);
Elliott Hughes4411b942022-02-09 15:56:27 -080065 sigaction64(SIGSEGV, &previous_sigsegv_, nullptr);
Elliott Hughes82e24a52022-02-15 10:12:23 -080066 sigaction64(SIGILL, &previous_sigill_, nullptr);
Elliott Hughes4411b942022-02-09 15:56:27 -080067 }
68
69 private:
Elliott Hughes4411b942022-02-09 15:56:27 -080070 struct sigaction64 previous_sigill_;
Elliott Hughes82e24a52022-02-15 10:12:23 -080071 struct sigaction64 previous_sigsegv_;
72 struct sigaction64 previous_sigtrap_;
Elliott Hughes4411b942022-02-09 15:56:27 -080073};
74
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070075static void f() {}
76
Elliott Hughese657eb42021-02-18 17:11:56 -080077TEST_F(cfi_test_DeathTest, basic) {
Evgenii Stepanov68ecec12017-01-31 13:19:30 -080078#if defined(__BIONIC__)
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070079 void* handle;
80 handle = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
81 ASSERT_TRUE(handle != nullptr) << dlerror();
82
Evgenii Stepanov97c16f82017-08-02 16:34:44 -070083 EXPECT_NE(0U, __cfi_shadow_size());
84
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070085#define SYM(type, name) auto name = reinterpret_cast<type>(dlsym(handle, #name))
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070086 SYM(size_t (*)(), get_count);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070087 SYM(uint64_t(*)(), get_last_type_id);
88 SYM(void* (*)(), get_last_address);
89 SYM(void* (*)(), get_last_diag);
90 SYM(void* (*)(), get_global_address);
91 SYM(void (*)(uint64_t, void*, void*), __cfi_check);
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070092 SYM(char*, bss);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070093#undef SYM
94
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070095 size_t c = get_count();
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070096
97 // CFI check for code inside the DSO. Can't use just any function address - this is only
98 // guaranteed to work for code addresses above __cfi_check.
99 void* code_ptr = reinterpret_cast<char*>(__cfi_check) + 1234;
100 void* diag_ptr = reinterpret_cast<void*>(5678);
101 __cfi_slowpath_diag(42, code_ptr, diag_ptr);
102 EXPECT_EQ(42U, get_last_type_id());
103 EXPECT_EQ(code_ptr, get_last_address());
104 EXPECT_EQ(diag_ptr, get_last_diag());
105 EXPECT_EQ(++c, get_count());
106
107 // __cfi_slowpath passes nullptr for the Diag argument.
108 __cfi_slowpath(42, code_ptr);
109 EXPECT_EQ(42U, get_last_type_id());
110 EXPECT_EQ(code_ptr, get_last_address());
111 EXPECT_EQ(nullptr, get_last_diag());
112 EXPECT_EQ(++c, get_count());
113
114 // CFI check for a data address inside the DSO.
115 __cfi_slowpath(43, get_global_address());
116 EXPECT_EQ(43U, get_last_type_id());
117 EXPECT_EQ(get_global_address(), get_last_address());
118 EXPECT_EQ(++c, get_count());
119
120 // CFI check for a function inside _this_ DSO. It either goes to this DSO's __cfi_check,
121 // or (if missing) is simply ignored. Any way, it does not affect the test lib's counters.
122 __cfi_slowpath(44, reinterpret_cast<void*>(&f));
123 EXPECT_EQ(43U, get_last_type_id());
124 EXPECT_EQ(get_global_address(), get_last_address());
125 EXPECT_EQ(c, get_count());
126
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -0700127 // Check all the addresses.
128 const size_t bss_size = 1024 * 1024;
129 static_assert(bss_size >= kLibraryAlignment * 2, "test range not big enough");
130 for (size_t i = 0; i < bss_size; ++i) {
131 __cfi_slowpath(47, bss + i);
132 EXPECT_EQ(++c, get_count());
133 }
134
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700135 // Load the same library again.
136 void* handle2 = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
137 ASSERT_TRUE(handle2 != nullptr) << dlerror();
138 EXPECT_EQ(handle2, handle);
139
140 // Check that it is still there.
141 __cfi_slowpath(43, get_global_address());
142 EXPECT_EQ(43U, get_last_type_id());
143 EXPECT_EQ(get_global_address(), get_last_address());
144 EXPECT_EQ(++c, get_count());
145
146 dlclose(handle);
147 dlclose(handle2);
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800148#endif
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700149}
150
151TEST(cfi_test, invalid) {
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800152#if defined(__BIONIC__)
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700153 void* handle;
154 handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
155 ASSERT_FALSE(handle != nullptr) << dlerror();
156
157 handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
158 ASSERT_FALSE(handle != nullptr) << dlerror();
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800159#endif
160}
161
162// cfi_test_helper exports __cfi_check, which triggers CFI initialization at startup.
163TEST(cfi_test, early_init) {
164#if defined(__BIONIC__)
Elliott Hughes8d8138a2024-03-12 22:37:13 +0000165 std::string helper = GetTestLibRoot() + "/cfi_test_helper";
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800166 ExecTestHelper eth;
167 eth.SetArgs({ helper.c_str(), nullptr });
168 eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
169#endif
170}
171
172// cfi_test_helper2 depends on a library that exports __cfi_check, which triggers CFI initialization
173// at startup.
174TEST(cfi_test, early_init2) {
175#if defined(__BIONIC__)
Elliott Hughes8d8138a2024-03-12 22:37:13 +0000176 std::string helper = GetTestLibRoot() + "/cfi_test_helper2";
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800177 ExecTestHelper eth;
178 eth.SetArgs({ helper.c_str(), nullptr });
179 eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
180#endif
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700181}
hanglfda4c102025-04-30 12:13:05 -0700182
183TEST(cfi_test, every_loaded_dso_has_valid_shadow) {
184#if defined(__BIONIC__)
185 if (__cfi_shadow_size() == 0) GTEST_SKIP();
186
187 auto callback = [](dl_phdr_info* info, size_t, void*) {
188 if (info->dlpi_phnum == 0 || !info->dlpi_phdr) return 0;
189 for (ElfW(Half) i = 0; i < info->dlpi_phnum; ++i) {
190 auto& ph = info->dlpi_phdr[i];
191 if (ph.p_type != PT_LOAD || !(ph.p_flags & PF_X)) continue;
192 uintptr_t sample_addr = info->dlpi_addr + ph.p_vaddr;
193 uint16_t v = __cfi_shadow_load(reinterpret_cast<void*>(sample_addr));
194
195 EXPECT_NE(uint16_t(CFIShadow::kInvalidShadow), v)
196 << "ERROR: cfi shadow value is invalid, " << info->dlpi_name
197 << " @ 0x" << std::hex << sample_addr
198 << " → shadow=0x" << v
199 << " (" << std::dec << v << ")";
200 }
201 return 0;
202 };
203
204 dl_iterate_phdr(callback, nullptr);
205#endif
206}