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