blob: aa5b12fb7d76f2325260c2cfd737aaf34ad6fbb4 [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>
Evgenii Stepanov68ecec12017-01-31 13:19:30 -080018#include <sys/stat.h>
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070019
Christopher Ferrisf3224832020-04-01 16:59:57 -070020#include <vector>
21
Elliott Hughes141b9172021-04-09 17:13:09 -070022#include <gtest/gtest.h>
23
Evgenii Stepanov68ecec12017-01-31 13:19:30 -080024#include "gtest_globals.h"
25#include "utils.h"
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070026
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070027#if defined(__BIONIC__)
28#include "private/CFIShadow.h"
29#endif
30
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070031// Private libdl interface.
32extern "C" {
33void __cfi_slowpath(uint64_t CallSiteTypeId, void* Ptr);
34void __cfi_slowpath_diag(uint64_t CallSiteTypeId, void* Ptr, void* DiagData);
Evgenii Stepanov97c16f82017-08-02 16:34:44 -070035size_t __cfi_shadow_size();
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070036}
37
Elliott Hughes4411b942022-02-09 15:56:27 -080038// Disables debuggerd stack traces to speed up death tests, make them less
39// noisy in logcat, and avoid expected deaths from showing up in stability
40// metrics.
41// We don't use the usual libbase class because (a) we don't care about most
42// of the signals it blocks but (b) we do need to block SIGILL, which normal
43// death tests shouldn't ever hit. (It's possible that a design where a
44// deathtest always declares its expected signals up front is a better one,
45// and maybe that's an interesting future direction for libbase.)
46class cfi_test_DeathTest : public testing::Test {
47 protected:
48 void SetUp() override {
49 struct sigaction64 action = {.sa_handler = SIG_DFL};
50 sigaction64(SIGSEGV, &action, &previous_sigsegv_);
51 sigaction64(SIGILL, &action, &previous_sigill_);
52 }
53
54 void TearDown() override {
55 sigaction64(SIGILL, &previous_sigill_, nullptr);
56 sigaction64(SIGSEGV, &previous_sigsegv_, nullptr);
57 }
58
59 private:
60 struct sigaction64 previous_sigsegv_;
61 struct sigaction64 previous_sigill_;
62};
63
64static bool KilledByCfi(int status) {
65 return WIFSIGNALED(status) && (WTERMSIG(status) == SIGILL || WTERMSIG(status) == SIGSEGV);
66}
Elliott Hughese657eb42021-02-18 17:11:56 -080067
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070068static void f() {}
69
Christopher Ferrisf3224832020-04-01 16:59:57 -070070static void test_cfi_slowpath_with_alloc() {
71 std::vector<void*> allocs;
72 for (size_t i = 0; i < 1000; i++) {
73 allocs.push_back(malloc(4096));
74 __cfi_slowpath(46, allocs.back());
75 }
76}
77
Elliott Hughese657eb42021-02-18 17:11:56 -080078TEST_F(cfi_test_DeathTest, basic) {
Evgenii Stepanov68ecec12017-01-31 13:19:30 -080079#if defined(__BIONIC__)
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070080 void* handle;
81 handle = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
82 ASSERT_TRUE(handle != nullptr) << dlerror();
83
Evgenii Stepanov97c16f82017-08-02 16:34:44 -070084 EXPECT_NE(0U, __cfi_shadow_size());
85
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070086#define SYM(type, name) auto name = reinterpret_cast<type>(dlsym(handle, #name))
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070087 SYM(size_t (*)(), get_count);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070088 SYM(uint64_t(*)(), get_last_type_id);
89 SYM(void* (*)(), get_last_address);
90 SYM(void* (*)(), get_last_diag);
91 SYM(void* (*)(), get_global_address);
92 SYM(void (*)(uint64_t, void*, void*), __cfi_check);
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070093 SYM(char*, bss);
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070094#undef SYM
95
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -070096 size_t c = get_count();
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -070097
98 // CFI check for code inside the DSO. Can't use just any function address - this is only
99 // guaranteed to work for code addresses above __cfi_check.
100 void* code_ptr = reinterpret_cast<char*>(__cfi_check) + 1234;
101 void* diag_ptr = reinterpret_cast<void*>(5678);
102 __cfi_slowpath_diag(42, code_ptr, diag_ptr);
103 EXPECT_EQ(42U, get_last_type_id());
104 EXPECT_EQ(code_ptr, get_last_address());
105 EXPECT_EQ(diag_ptr, get_last_diag());
106 EXPECT_EQ(++c, get_count());
107
108 // __cfi_slowpath passes nullptr for the Diag argument.
109 __cfi_slowpath(42, code_ptr);
110 EXPECT_EQ(42U, get_last_type_id());
111 EXPECT_EQ(code_ptr, get_last_address());
112 EXPECT_EQ(nullptr, get_last_diag());
113 EXPECT_EQ(++c, get_count());
114
115 // CFI check for a data address inside the DSO.
116 __cfi_slowpath(43, get_global_address());
117 EXPECT_EQ(43U, get_last_type_id());
118 EXPECT_EQ(get_global_address(), get_last_address());
119 EXPECT_EQ(++c, get_count());
120
121 // CFI check for a function inside _this_ DSO. It either goes to this DSO's __cfi_check,
122 // or (if missing) is simply ignored. Any way, it does not affect the test lib's counters.
123 __cfi_slowpath(44, reinterpret_cast<void*>(&f));
124 EXPECT_EQ(43U, get_last_type_id());
125 EXPECT_EQ(get_global_address(), get_last_address());
126 EXPECT_EQ(c, get_count());
127
Christopher Ferrisf3224832020-04-01 16:59:57 -0700128 // CFI check for a heap address.
129 // It's possible that this allocation could wind up in the same CFI granule as
130 // an unchecked library, which means the below might not crash. To force a
131 // crash keep allocating up to a max until there is a crash.
Elliott Hughes4411b942022-02-09 15:56:27 -0800132 EXPECT_EXIT(test_cfi_slowpath_with_alloc(), KilledByCfi, "");
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700133
Evgenii Stepanov1dfd76a2017-09-18 17:51:48 -0700134 // Check all the addresses.
135 const size_t bss_size = 1024 * 1024;
136 static_assert(bss_size >= kLibraryAlignment * 2, "test range not big enough");
137 for (size_t i = 0; i < bss_size; ++i) {
138 __cfi_slowpath(47, bss + i);
139 EXPECT_EQ(++c, get_count());
140 }
141
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700142 // Load the same library again.
143 void* handle2 = dlopen("libcfi-test.so", RTLD_NOW | RTLD_LOCAL);
144 ASSERT_TRUE(handle2 != nullptr) << dlerror();
145 EXPECT_EQ(handle2, handle);
146
147 // Check that it is still there.
148 __cfi_slowpath(43, get_global_address());
149 EXPECT_EQ(43U, get_last_type_id());
150 EXPECT_EQ(get_global_address(), get_last_address());
151 EXPECT_EQ(++c, get_count());
152
153 dlclose(handle);
154 dlclose(handle2);
155
156 // CFI check for a function inside the unloaded DSO. This is always invalid and gets the process
157 // killed.
Elliott Hughes4411b942022-02-09 15:56:27 -0800158 EXPECT_EXIT(__cfi_slowpath(45, reinterpret_cast<void*>(code_ptr)), KilledByCfi, "");
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800159#endif
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700160}
161
162TEST(cfi_test, invalid) {
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800163#if defined(__BIONIC__)
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700164 void* handle;
165 handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
166 ASSERT_FALSE(handle != nullptr) << dlerror();
167
168 handle = dlopen("libcfi-test-bad.so", RTLD_NOW | RTLD_LOCAL);
169 ASSERT_FALSE(handle != nullptr) << dlerror();
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800170#endif
171}
172
173// cfi_test_helper exports __cfi_check, which triggers CFI initialization at startup.
174TEST(cfi_test, early_init) {
175#if defined(__BIONIC__)
Colin Crossbadcb382021-09-24 17:49:58 -0700176 std::string helper = GetTestlibRoot() + "/cfi_test_helper";
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800177 chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
178 ExecTestHelper eth;
179 eth.SetArgs({ helper.c_str(), nullptr });
180 eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
181#endif
182}
183
184// cfi_test_helper2 depends on a library that exports __cfi_check, which triggers CFI initialization
185// at startup.
186TEST(cfi_test, early_init2) {
187#if defined(__BIONIC__)
Colin Crossbadcb382021-09-24 17:49:58 -0700188 std::string helper = GetTestlibRoot() + "/cfi_test_helper2";
Evgenii Stepanov68ecec12017-01-31 13:19:30 -0800189 chmod(helper.c_str(), 0755); // TODO: "x" lost in CTS, b/34945607
190 ExecTestHelper eth;
191 eth.SetArgs({ helper.c_str(), nullptr });
192 eth.Run([&]() { execve(helper.c_str(), eth.GetArgs(), eth.GetEnv()); }, 0, nullptr);
193#endif
Evgenii Stepanov0a3637d2016-07-06 13:20:59 -0700194}