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 <trusty_unittest.h>
20 #include <uapi/err.h>
21
22 #include <cfi-crasher.h>
23 #include <cfi_crasher_consts.h>
24
25 #define TLOG_TAG "cfi-test"
26
27 /*
28 * Sends command to crasher app. Call crasher_wait after to wait for a
29 * reply or channel close. On success, returns zero.
30 */
crasher_command(handle_t chan,enum crasher_command cmd)31 static int crasher_command(handle_t chan, enum crasher_command cmd) {
32 int ret;
33 struct crasher_msg msg = {
34 .cmd = cmd,
35 };
36
37 ret = tipc_send1(chan, &msg, sizeof(msg));
38 ASSERT_GE(ret, 0);
39 ASSERT_EQ(ret, sizeof(msg));
40
41 return 0;
42
43 test_abort:
44 /* Use ERR_IO to indicate internal error with the test app */
45 return ERR_IO;
46 }
47
48 /*
49 * This function should always be called after crasher_command since it
50 * assumes the test app has already sent a message to the crasher app
51 * with the command. In the non-crashing case, returns a positive integer
52 * equaling the message command echoed back by the server.
53 */
crasher_wait(handle_t chan)54 static int crasher_wait(handle_t chan) {
55 int ret;
56 struct uevent evt;
57 ret = wait(chan, &evt, INFINITE_TIME);
58 if (ret) { /* error while waiting on channel */
59 return ret;
60 }
61 /*
62 * Receiving message and crashing the app should never happen with
63 * CFI enabled. If both IPC_HANDLE_POLL_MSG and IPC_HANDLE_POLL_HUP
64 * are set, either an internal error occurred or CRASHER_NOT_ENTRY
65 * ran with CFI not enabled. We expect exactly one of IPC_HANDLE_POLL_MSG
66 * and IPC_HANDLE_POLL_HUP to be set.
67 */
68 if (evt.event & IPC_HANDLE_POLL_HUP) {
69 ASSERT_EQ(evt.event & IPC_HANDLE_POLL_MSG, 0);
70 return ERR_CHANNEL_CLOSED;
71 }
72 ASSERT_NE(evt.event & IPC_HANDLE_POLL_MSG, 0);
73
74 struct crasher_msg msg;
75 ret = tipc_recv1(chan, sizeof(msg), &msg, sizeof(msg));
76 if (ret < 0) {
77 return ret;
78 }
79 ASSERT_EQ(ret, sizeof(msg));
80 /*
81 * Return the cmd if we reach this point, that is the app did not crash.
82 * If the crasher did not crash, it should echo back the original command,
83 * or CRASHER_VOID in the special case where crasher_void executes on
84 * the server side.
85 */
86 return msg.cmd;
87
88 test_abort:
89 /* Use ERR_IO to indicate internal error with the test app */
90 return ERR_IO;
91 }
92
93 typedef struct cfi_crash {
94 handle_t chan;
95 } cfi_crash_t;
96
97 #ifdef CFI_ENABLED
98 #define CHECK_CFI_ENABLED
99 #else
100 #define CHECK_CFI_ENABLED \
101 { \
102 trusty_unittest_printf("[ INFO ] CFI is not supported\n"); \
103 GTEST_SKIP(); \
104 }
105 #endif
106
TEST_F_SETUP(cfi_crash)107 TEST_F_SETUP(cfi_crash) {
108 CHECK_CFI_ENABLED
109 _state->chan = INVALID_IPC_HANDLE;
110 ASSERT_EQ(tipc_connect(&_state->chan, CFI_CRASHER_PORT), 0);
111
112 test_abort:;
113 }
114
TEST_F_TEARDOWN(cfi_crash)115 TEST_F_TEARDOWN(cfi_crash) {
116 close(_state->chan);
117 }
118
TEST_F(cfi_crash,nop)119 TEST_F(cfi_crash, nop) {
120 EXPECT_EQ(crasher_command(_state->chan, CRASHER_NOP), 0);
121 EXPECT_EQ(crasher_wait(_state->chan), CRASHER_NOP);
122 }
123
TEST_F(cfi_crash,correct)124 TEST_F(cfi_crash, correct) {
125 EXPECT_EQ(crasher_command(_state->chan, CRASHER_CORRECT), 0);
126 EXPECT_EQ(crasher_wait(_state->chan), CRASHER_CORRECT);
127 }
128
TEST_F(cfi_crash,entry)129 TEST_F(cfi_crash, entry) {
130 /*
131 * CRASHER_ENTRY suppresses the second reply from crasher_void
132 * so we only expect one message back at the end of crasher_on_message.
133 */
134 EXPECT_EQ(crasher_command(_state->chan, CRASHER_ENTRY), 0);
135 EXPECT_EQ(crasher_wait(_state->chan), CRASHER_ENTRY);
136 }
137
TEST_F(cfi_crash,exclude_wrong_type)138 TEST_F(cfi_crash, exclude_wrong_type) {
139 EXPECT_EQ(crasher_command(_state->chan, CRASHER_EXCLUDE_WRONG_TYPE), 0);
140 EXPECT_EQ(crasher_wait(_state->chan), CRASHER_EXCLUDE_WRONG_TYPE);
141 }
142
TEST_F(cfi_crash,exclude_not_entry)143 TEST_F(cfi_crash, exclude_not_entry) {
144 /*
145 * CRASHER_EXCLUDE_NOT_ENTRY expects one event with a message and a
146 * subsequent event indicating the channel is closed.
147 */
148 EXPECT_EQ(crasher_command(_state->chan, CRASHER_EXCLUDE_NOT_ENTRY), 0);
149 EXPECT_EQ(crasher_wait(_state->chan), CRASHER_VOID);
150 EXPECT_EQ(crasher_wait(_state->chan), ERR_CHANNEL_CLOSED);
151 }
152
TEST_F(cfi_crash,wrong_type)153 TEST_F(cfi_crash, wrong_type) {
154 EXPECT_EQ(crasher_command(_state->chan, CRASHER_WRONG_TYPE), 0);
155 EXPECT_EQ(crasher_wait(_state->chan), ERR_CHANNEL_CLOSED);
156 }
157
TEST_F(cfi_crash,not_entry)158 TEST_F(cfi_crash, not_entry) {
159 EXPECT_EQ(crasher_command(_state->chan, CRASHER_NOT_ENTRY), 0);
160 EXPECT_EQ(crasher_wait(_state->chan), ERR_CHANNEL_CLOSED);
161 }
162
163 PORT_TEST(cfi_crash, "com.android.trusty.cfitest")
164