1 /*
2  * Copyright (C) 2022 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 <dlmalloc_app.h>
18 #include <dlmalloc_consts.h>
19 #include <errno.h>
20 #include <lib/tipc/tipc.h>
21 #include <lib/unittest/unittest.h>
22 #include <stdlib.h>
23 #include <trusty_unittest.h>
24 #include <uapi/err.h>
25 
26 #define TLOG_TAG "dlmalloc_test"
27 
28 /*
29  * Sends command to app and then waits for a
30  * reply or channel close. In the non-crashing case, the server
31  * should echo back the original command and dlmalloc_srv_rpc returns
32  * NO_ERROR.
33  */
dlmalloc_srv_rpc_expect(handle_t chan,enum dlmalloc_test_command cmd,int expected)34 static void dlmalloc_srv_rpc_expect(handle_t chan,
35                                     enum dlmalloc_test_command cmd,
36                                     int expected) {
37     int ret;
38     struct dlmalloc_test_msg msg = {
39             .cmd = cmd,
40     };
41 
42     ret = tipc_send1(chan, &msg, sizeof(msg));
43     ASSERT_EQ(ret, sizeof(msg));
44 
45     struct uevent evt;
46     ret = wait(chan, &evt, INFINITE_TIME);
47     ASSERT_EQ(NO_ERROR, ret);
48 
49     int event = evt.event & IPC_HANDLE_POLL_MSG;
50     if (evt.event & IPC_HANDLE_POLL_HUP) {
51         ASSERT_EQ(event, 0);
52         ASSERT_EQ(ERR_CHANNEL_CLOSED, expected);
53         goto test_abort;
54     }
55     ASSERT_NE(event, 0);
56 
57     ret = tipc_recv1(chan, sizeof(msg), &msg, sizeof(msg));
58     ASSERT_EQ(ret, sizeof(msg));
59     ASSERT_EQ(msg.cmd, cmd);
60 
61 test_abort:;
62 }
63 
dlmalloc_srv_rpc(handle_t chan,enum dlmalloc_test_command cmd)64 static void dlmalloc_srv_rpc(handle_t chan, enum dlmalloc_test_command cmd) {
65     dlmalloc_srv_rpc_expect(chan, cmd, NO_ERROR);
66 }
67 
68 typedef struct dlmalloc_info {
69     handle_t chan;
70 } dlmalloc_info_t;
71 
TEST_F_SETUP(dlmalloc_info)72 TEST_F_SETUP(dlmalloc_info) {
73     _state->chan = INVALID_IPC_HANDLE;
74     ASSERT_EQ(tipc_connect(&_state->chan, DLMALLOC_TEST_SRV_PORT), 0);
75 
76 test_abort:;
77 }
78 
TEST_F_TEARDOWN(dlmalloc_info)79 TEST_F_TEARDOWN(dlmalloc_info) {
80     close(_state->chan);
81 }
82 
TEST_F(dlmalloc_info,nop)83 TEST_F(dlmalloc_info, nop) {
84     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_NOP);
85 }
86 
TEST_F(dlmalloc_info,one_malloc)87 TEST_F(dlmalloc_info, one_malloc) {
88     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_MALLOC);
89 }
90 
TEST_F(dlmalloc_info,one_calloc)91 TEST_F(dlmalloc_info, one_calloc) {
92     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_CALLOC);
93 }
94 
TEST_F(dlmalloc_info,one_realloc)95 TEST_F(dlmalloc_info, one_realloc) {
96     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_REALLOC);
97 }
98 
TEST_F(dlmalloc_info,many_malloc)99 TEST_F(dlmalloc_info, many_malloc) {
100     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_MANY_MALLOC);
101 }
102 
TEST_F(dlmalloc_info,one_new)103 TEST_F(dlmalloc_info, one_new) {
104     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_NEW);
105 }
106 
TEST_F(dlmalloc_info,one_new_arr)107 TEST_F(dlmalloc_info, one_new_arr) {
108     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ONE_NEW_ARR);
109 }
110 
TEST_F(dlmalloc_info,malloc_and_new)111 TEST_F(dlmalloc_info, malloc_and_new) {
112     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_MALLOC_AND_NEW);
113 }
114 
TEST_F(dlmalloc_info,double_free)115 TEST_F(dlmalloc_info, double_free) {
116     dlmalloc_srv_rpc_expect(_state->chan, DLMALLOC_TEST_DOUBLE_FREE,
117                             ERR_CHANNEL_CLOSED);
118 }
119 
TEST_F(dlmalloc_info,realloc_after_free)120 TEST_F(dlmalloc_info, realloc_after_free) {
121     dlmalloc_srv_rpc_expect(_state->chan, DLMALLOC_TEST_REALLOC_AFTER_FREE,
122                             ERR_CHANNEL_CLOSED);
123 }
124 
TEST_F(dlmalloc_info,alloc_large)125 TEST_F(dlmalloc_info, alloc_large) {
126     dlmalloc_srv_rpc(_state->chan, DLMALLOC_TEST_ALLOC_LARGE);
127 }
128 
TEST_F(dlmalloc_info,malloc_loop)129 TEST_F(dlmalloc_info, malloc_loop) {
130     for (int i = 0; i < 1024; i++) {
131         void* ptr = malloc(4096 * 3);
132         ASSERT_NE(0, ptr, "iteration %d", i);
133         free(ptr);
134     }
135 
136 test_abort:;
137 }
138 
139 #define CLEAR_ERRNO() \
140     do {              \
141         errno = 0;    \
142     } while (0)
143 
TEST_F(dlmalloc_info,malloc_oom)144 TEST_F(dlmalloc_info, malloc_oom) {
145     void* ptr = malloc(8192 * 1024);
146     ASSERT_EQ(0, ptr);
147     /* TODO: ENOMEM */
148     CLEAR_ERRNO();
149 
150 test_abort:;
151 }
152 
expected_malloc_alignment(size_t size)153 static uintptr_t expected_malloc_alignment(size_t size) {
154     /* TODO use ffs? */
155     if (size >= 16) {
156         return sizeof(void*) * 2;
157     } else if (size >= 8) {
158         return 8;
159     } else if (size >= 4) {
160         return 4;
161     } else if (size >= 2) {
162         return 2;
163     } else {
164         return 1;
165     }
166 }
167 
TEST_F(dlmalloc_info,malloc_alignment)168 TEST_F(dlmalloc_info, malloc_alignment) {
169     for (int size = 2; size < 256; size++) {
170         const uintptr_t alignment_mask = expected_malloc_alignment(size) - 1;
171         void* ptr1 = malloc(size);
172         void* ptr2 = malloc(size / 2); /* Try to shake up the alignment. */
173         void* ptr3 = malloc(size);
174 
175         ASSERT_EQ(0, (uintptr_t)ptr1 & alignment_mask, "size %d / align %zu",
176                   size, alignment_mask + 1);
177         ASSERT_EQ(0, (uintptr_t)ptr3 & alignment_mask, "size %d / align %zu",
178                   size, alignment_mask + 1);
179 
180         free(ptr3);
181         free(ptr2);
182         free(ptr1);
183     }
184 test_abort:;
185 }
186 
187 PORT_TEST(dlmalloc_info, "com.android.trusty.dlmalloctest")
188