1 /*
2 * Copyright (C) 2021 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
17 #include <lib/tipc/tipc.h>
18 #include <lib/unittest/unittest.h>
19 #include <stdlib.h>
20 #include <sys/auxv.h>
21 #include <trusty/memref.h>
22 #include <trusty_unittest.h>
23 #include <uapi/err.h>
24 #include <uapi/mm.h>
25
26 #include <scudo_app.h>
27 #include <scudo_consts.h>
28
29 #define TLOG_TAG "scudo_test"
30
31 #ifndef HWCAP2_MTE
32 #define HWCAP2_MTE (1 << 18)
33 #endif
34
35 #define PAGE_SIZE getauxval(AT_PAGESZ)
36
send_memref_msg(handle_t chan,const void * buf,size_t len,handle_t memref)37 int send_memref_msg(handle_t chan,
38 const void* buf,
39 size_t len,
40 handle_t memref) {
41 struct iovec iov = {
42 .iov_base = (void*)buf,
43 .iov_len = len,
44 };
45 ipc_msg_t msg = {
46 .iov = &iov,
47 .num_iov = 1,
48 .handles = memref < 0 ? NULL : &memref,
49 .num_handles = memref < 0 ? 0 : 1,
50 };
51 return send_msg(chan, &msg);
52 }
53
54 /*
55 * Sends command to app and then waits for a
56 * reply or channel close. In the non-crashing case, the server
57 * should echo back the original command and scudo_srv_rpc returns
58 * NO_ERROR.
59 */
scudo_srv_rpc_memref(handle_t chan,enum scudo_command cmd,int memref)60 static int scudo_srv_rpc_memref(handle_t chan,
61 enum scudo_command cmd,
62 int memref) {
63 int ret;
64 struct scudo_msg msg = {
65 .cmd = cmd,
66 };
67
68 ret = send_memref_msg(chan, &msg, sizeof(msg), memref);
69 ASSERT_GE(ret, 0);
70 ASSERT_EQ(ret, sizeof(msg));
71
72 struct uevent evt;
73 ret = wait(chan, &evt, INFINITE_TIME);
74 if (ret) {
75 /* error while waiting on channel */
76 return ret;
77 }
78
79 if (evt.event & IPC_HANDLE_POLL_HUP) {
80 ASSERT_EQ(evt.event & IPC_HANDLE_POLL_MSG, 0);
81 return ERR_CHANNEL_CLOSED;
82 }
83 ASSERT_NE(evt.event & IPC_HANDLE_POLL_MSG, 0);
84
85 ret = tipc_recv1(chan, sizeof(msg), &msg, sizeof(msg));
86 if (ret < 0) {
87 return ret;
88 }
89 ASSERT_EQ(ret, sizeof(msg));
90 if (msg.cmd == cmd) {
91 return NO_ERROR;
92 }
93 return msg.cmd;
94
95 test_abort:
96 /* Use ERR_IO to indicate internal error with the test app */
97 return ERR_IO;
98 }
99
scudo_srv_rpc(handle_t chan,enum scudo_command cmd)100 static int scudo_srv_rpc(handle_t chan, enum scudo_command cmd) {
101 return scudo_srv_rpc_memref(chan, cmd, -1);
102 }
103
104 typedef struct scudo_info {
105 handle_t chan;
106 } scudo_info_t;
107
has_mte(void)108 static bool has_mte(void) {
109 return getauxval(AT_HWCAP2) & HWCAP2_MTE;
110 }
111
TEST_F_SETUP(scudo_info)112 TEST_F_SETUP(scudo_info) {
113 _state->chan = INVALID_IPC_HANDLE;
114 ASSERT_EQ(tipc_connect(&_state->chan, SCUDO_TEST_SRV_PORT), 0);
115
116 test_abort:;
117 }
118
TEST_F_TEARDOWN(scudo_info)119 TEST_F_TEARDOWN(scudo_info) {
120 close(_state->chan);
121 }
122
TEST_F(scudo_info,nop)123 TEST_F(scudo_info, nop) {
124 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_NOP), NO_ERROR);
125 }
126
TEST_F(scudo_info,one_malloc)127 TEST_F(scudo_info, one_malloc) {
128 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ONE_MALLOC), NO_ERROR);
129 }
130
TEST_F(scudo_info,one_calloc)131 TEST_F(scudo_info, one_calloc) {
132 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ONE_CALLOC), NO_ERROR);
133 }
134
TEST_F(scudo_info,one_realloc)135 TEST_F(scudo_info, one_realloc) {
136 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ONE_REALLOC), NO_ERROR);
137 }
138
TEST_F(scudo_info,many_malloc)139 TEST_F(scudo_info, many_malloc) {
140 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_MANY_MALLOC), NO_ERROR);
141 }
142
TEST_F(scudo_info,one_new)143 TEST_F(scudo_info, one_new) {
144 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ONE_NEW), NO_ERROR);
145 }
146
TEST_F(scudo_info,one_new_arr)147 TEST_F(scudo_info, one_new_arr) {
148 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ONE_NEW_ARR), NO_ERROR);
149 }
150
TEST_F(scudo_info,malloc_and_new)151 TEST_F(scudo_info, malloc_and_new) {
152 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_MALLOC_AND_NEW), NO_ERROR);
153 }
154
TEST_F(scudo_info,double_free)155 TEST_F(scudo_info, double_free) {
156 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_DOUBLE_FREE),
157 ERR_CHANNEL_CLOSED);
158 }
159
TEST_F(scudo_info,realloc_after_free)160 TEST_F(scudo_info, realloc_after_free) {
161 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_REALLOC_AFTER_FREE),
162 ERR_CHANNEL_CLOSED);
163 }
164
TEST_F(scudo_info,dealloc_type_mismatch)165 TEST_F(scudo_info, dealloc_type_mismatch) {
166 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_DEALLOC_TYPE_MISMATCH),
167 ERR_CHANNEL_CLOSED);
168 }
169
TEST_F(scudo_info,realloc_type_mismatch)170 TEST_F(scudo_info, realloc_type_mismatch) {
171 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_REALLOC_TYPE_MISMATCH),
172 ERR_CHANNEL_CLOSED);
173 }
174
TEST_F(scudo_info,alloc_large)175 TEST_F(scudo_info, alloc_large) {
176 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ALLOC_LARGE), NO_ERROR);
177 }
178
TEST_F(scudo_info,mte_tagged_memref_small)179 TEST_F(scudo_info, mte_tagged_memref_small) {
180 if (!has_mte()) {
181 trusty_unittest_printf("[ SKIPPED ] MTE is not available\n");
182 return;
183 }
184 int ref = -1;
185 void* mem = memalign(PAGE_SIZE, PAGE_SIZE);
186 ASSERT_NE(mem, NULL);
187 memset(mem, 0x33, PAGE_SIZE);
188 ref = memref_create(
189 mem, PAGE_SIZE,
190 MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE | MMAP_FLAG_PROT_MTE);
191 ASSERT_GT(ref, 0);
192 printf("created memref %d for %p\n", ref, mem);
193 int rc = scudo_srv_rpc_memref(_state->chan, SCUDO_TAGGED_MEMREF_SMALL, ref);
194 EXPECT_EQ(rc, NO_ERROR);
195 EXPECT_EQ(*((volatile char*)mem), 0x77);
196 test_abort:
197 close(ref);
198 free(mem);
199 }
200
TEST_F(scudo_info,mte_tagged_memref_large)201 TEST_F(scudo_info, mte_tagged_memref_large) {
202 if (!has_mte()) {
203 trusty_unittest_printf("[ SKIPPED ] MTE is not available\n");
204 return;
205 }
206 int ref = -1;
207 void* mem = memalign(PAGE_SIZE, PAGE_SIZE * 32);
208 ASSERT_NE(mem, NULL);
209 memset(mem, 0x33, PAGE_SIZE);
210 ref = memref_create(
211 mem, PAGE_SIZE * 32,
212 MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE | MMAP_FLAG_PROT_MTE);
213 ASSERT_GT(ref, 0);
214 printf("created memref %d for %p\n", ref, mem);
215 int rc = scudo_srv_rpc_memref(_state->chan, SCUDO_TAGGED_MEMREF_LARGE, ref);
216 EXPECT_EQ(rc, NO_ERROR);
217 EXPECT_EQ(*((volatile char*)mem), 0x77);
218 test_abort:
219 close(ref);
220 free(mem);
221 }
222
TEST_F(scudo_info,mte_untagged_memref_small)223 TEST_F(scudo_info, mte_untagged_memref_small) {
224 int ref = -1;
225 void* mem = memalign(PAGE_SIZE, PAGE_SIZE);
226 ASSERT_NE(mem, NULL);
227 memset(mem, 0x33, PAGE_SIZE);
228 ref = memref_create(mem, PAGE_SIZE,
229 MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE);
230 ASSERT_GT(ref, 0);
231 printf("created memref %d for %p\n", ref, mem);
232 int rc = scudo_srv_rpc_memref(_state->chan, SCUDO_UNTAGGED_MEMREF_SMALL,
233 ref);
234 EXPECT_EQ(rc, NO_ERROR);
235 EXPECT_EQ(*((volatile char*)mem), 0x77);
236 test_abort:
237 close(ref);
238 free(mem);
239 }
240
TEST_F(scudo_info,mte_untagged_memref_large)241 TEST_F(scudo_info, mte_untagged_memref_large) {
242 int ref = -1;
243 void* mem = memalign(PAGE_SIZE, PAGE_SIZE * 32);
244 ASSERT_NE(mem, NULL);
245 memset(mem, 0x33, PAGE_SIZE);
246 ref = memref_create(mem, PAGE_SIZE * 32,
247 MMAP_FLAG_PROT_READ | MMAP_FLAG_PROT_WRITE);
248 ASSERT_GT(ref, 0);
249 printf("created memref %d for %p\n", ref, mem);
250 int rc = scudo_srv_rpc_memref(_state->chan, SCUDO_UNTAGGED_MEMREF_LARGE,
251 ref);
252 EXPECT_EQ(rc, NO_ERROR);
253 EXPECT_EQ(*((volatile char*)mem), 0x77);
254 test_abort:
255 close(ref);
256 free(mem);
257 }
258
TEST_F(scudo_info,mte_mismatched_tag_read)259 TEST_F(scudo_info, mte_mismatched_tag_read) {
260 if (!has_mte()) {
261 trusty_unittest_printf("[ SKIPPED ] MTE is not available\n");
262 return;
263 }
264 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_MEMTAG_MISMATCHED_READ),
265 ERR_CHANNEL_CLOSED);
266 }
267
TEST_F(scudo_info,mte_mismatched_tag_write)268 TEST_F(scudo_info, mte_mismatched_tag_write) {
269 if (!has_mte()) {
270 trusty_unittest_printf("[ SKIPPED ] MTE is not available\n");
271 return;
272 }
273 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_MEMTAG_MISMATCHED_WRITE),
274 ERR_CHANNEL_CLOSED);
275 }
276
TEST_F(scudo_info,mte_memtag_read_after_free)277 TEST_F(scudo_info, mte_memtag_read_after_free) {
278 if (!has_mte()) {
279 trusty_unittest_printf("[ SKIPPED ] MTE is not available\n");
280 return;
281 }
282 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_MEMTAG_READ_AFTER_FREE),
283 ERR_CHANNEL_CLOSED);
284 }
285
TEST_F(scudo_info,mte_memtag_write_after_free)286 TEST_F(scudo_info, mte_memtag_write_after_free) {
287 if (!has_mte()) {
288 trusty_unittest_printf("[ SKIPPED ] MTE is not available\n");
289 return;
290 }
291 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_MEMTAG_WRITE_AFTER_FREE),
292 ERR_CHANNEL_CLOSED);
293 }
294
TEST_F(scudo_info,alloc_benchmark)295 TEST_F(scudo_info, alloc_benchmark) {
296 EXPECT_EQ(scudo_srv_rpc(_state->chan, SCUDO_ALLOC_BENCHMARK), NO_ERROR);
297 }
298
299 PORT_TEST(scudo_info, "com.android.trusty.scudotest")
300