1 /*
2 * Copyright 2019 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 #define TLOG_TAG "confirmationui"
18
19 #ifdef WITH_HANDLE_PROT
20 #include <lib/handle_prot/handle_prot.h>
21 #endif
22 #include <lib/keymaster/keymaster.h>
23 #include <lib/tipc/tipc.h>
24 #include <lib/tipc/tipc_srv.h>
25 #include <lk/err_ptr.h>
26 #include <lk/macros.h>
27 #include <sys/mman.h>
28 #include <trusty_log.h>
29 #include <uapi/err.h>
30
31 #include <memory>
32
33 #include "ipc.h"
34 #include "trusty_operation.h"
35
36 struct chan_ctx {
37 void* shm_base;
38 size_t shm_len;
39 std::unique_ptr<TrustyOperation> op;
40 };
41
is_inited(struct chan_ctx * ctx)42 static inline bool is_inited(struct chan_ctx* ctx) {
43 return ctx->shm_base;
44 }
45
get_auth_token_key(teeui::AuthTokenKey & authKey)46 static bool get_auth_token_key(teeui::AuthTokenKey& authKey) {
47 long rc = keymaster_open();
48 bool result = false;
49
50 if (rc < 0) {
51 return false;
52 }
53
54 keymaster_session_t session = (keymaster_session_t)rc;
55 uint8_t* key = nullptr;
56 uint32_t local_length = 0;
57 rc = keymaster_get_auth_token_key(session, &key, &local_length);
58 keymaster_close(session);
59
60 if (rc == NO_ERROR) {
61 if (local_length == teeui::kAuthTokenKeySize) {
62 /* Success - store the key */
63 memcpy(authKey.data(), key, teeui::kAuthTokenKeySize);
64 result = true;
65 }
66
67 free(key);
68 }
69
70 return result;
71 }
72
73 struct __attribute__((__packed__)) confirmationui_req {
74 struct confirmationui_hdr hdr;
75 union {
76 struct confirmationui_init_req init_args;
77 struct confirmationui_msg_args msg_args;
78 };
79 };
80
confirmationui_recv(handle_t chan,confirmationui_req * req,handle_t * h)81 static int confirmationui_recv(handle_t chan,
82 confirmationui_req* req,
83 handle_t* h) {
84 int rc;
85 ipc_msg_info msg_info;
86 uint32_t max_num_handles = h ? 1 : 0;
87 struct iovec iov = {
88 .iov_base = req,
89 .iov_len = sizeof(*req),
90 };
91 struct ipc_msg ipc_msg = {
92 .num_iov = 1,
93 .iov = &iov,
94 .num_handles = max_num_handles,
95 .handles = h,
96 };
97
98 rc = get_msg(chan, &msg_info);
99 if (rc != NO_ERROR) {
100 TLOGE("Failed to get message (%d)\n", rc);
101 return rc;
102 }
103
104 if (msg_info.len > sizeof(*req)) {
105 TLOGE("Message is too long (%zd)\n", msg_info.len);
106 rc = ERR_BAD_LEN;
107 goto out;
108 }
109
110 if (msg_info.num_handles > max_num_handles) {
111 TLOGE("Message has too many handles (%u)\n", msg_info.num_handles);
112 rc = ERR_TOO_BIG;
113 goto out;
114 }
115
116 rc = read_msg(chan, msg_info.id, 0, &ipc_msg);
117
118 out:
119 put_msg(chan, msg_info.id);
120 return rc;
121 }
122
handle_init(handle_t chan,handle_t shm_handle,uint32_t shm_len,struct chan_ctx * ctx)123 static int handle_init(handle_t chan,
124 handle_t shm_handle,
125 uint32_t shm_len,
126 struct chan_ctx* ctx) {
127 int rc;
128 struct confirmationui_hdr hdr;
129
130 if (is_inited(ctx)) {
131 TLOGE("TA is already initialized.\n");
132 return ERR_BAD_STATE;
133 }
134
135 if (shm_len > CONFIRMATIONUI_MAX_MSG_SIZE) {
136 TLOGE("Shared memory too long\n");
137 return ERR_BAD_LEN;
138 }
139 #ifdef WITH_HANDLE_PROT
140 rc = handle_prot_secure(shm_handle, false);
141 if (rc < 0) {
142 TLOGE("Shared memory should be non-secure, rc=%d\n", rc);
143 return rc;
144 }
145
146 rc = handle_prot_prot_id(shm_handle, 0);
147 if (rc < 0) {
148 TLOGE("Shared memory prot Id invalid, rc=%d.\n", rc);
149 return rc;
150 }
151 #endif
152 void* shm_base = mmap(0, shm_len, PROT_READ | PROT_WRITE, 0, shm_handle, 0);
153 if (shm_base == MAP_FAILED) {
154 TLOGE("Failed to mmap() handle\n");
155 return ERR_BAD_HANDLE;
156 }
157
158 hdr.cmd = CONFIRMATIONUI_CMD_INIT | CONFIRMATIONUI_RESP_BIT;
159 rc = tipc_send1(chan, &hdr, sizeof(hdr));
160 if (rc != (int)sizeof(hdr)) {
161 TLOGE("Failed to send response (%d)\n", rc);
162 if (rc >= 0) {
163 rc = ERR_BAD_LEN;
164 }
165 goto err;
166 }
167
168 ctx->shm_base = shm_base;
169 ctx->shm_len = shm_len;
170 return NO_ERROR;
171
172 err:
173 int rc1 = munmap(shm_base, shm_len);
174 if (rc1 != NO_ERROR) {
175 TLOGW("munmap() failed: %d\n", rc1);
176 }
177 return rc;
178 }
179
handle_msg(handle_t chan,uint32_t req_len,struct chan_ctx * ctx)180 static int handle_msg(handle_t chan, uint32_t req_len, struct chan_ctx* ctx) {
181 int rc;
182 uint8_t msg[CONFIRMATIONUI_MAX_MSG_SIZE];
183 uint32_t resp_len = ctx->shm_len;
184 struct confirmationui_hdr hdr;
185 struct confirmationui_msg_args args;
186
187 if (!is_inited(ctx)) {
188 TLOGE("TA is not initialized.\n");
189 return ERR_BAD_STATE;
190 }
191
192 if (req_len > ctx->shm_len) {
193 TLOGE("Message too long (%u)\n", req_len);
194 return ERR_BAD_LEN;
195 }
196
197 assert(req_len <= sizeof(msg));
198 memcpy(msg, ctx->shm_base, req_len);
199
200 ctx->op->handleMsg(msg, req_len, ctx->shm_base, &resp_len);
201
202 hdr.cmd = CONFIRMATIONUI_CMD_MSG | CONFIRMATIONUI_RESP_BIT;
203 args.msg_len = resp_len;
204 rc = tipc_send2(chan, &hdr, sizeof(hdr), &args, sizeof(args));
205 if (rc != (int)(sizeof(hdr) + sizeof(args))) {
206 TLOGE("Failed to send response (%d)\n", rc);
207 if (rc >= 0) {
208 rc = ERR_BAD_LEN;
209 }
210 return rc;
211 }
212
213 return NO_ERROR;
214 }
215
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)216 static int on_connect(const struct tipc_port* port,
217 handle_t chan,
218 const struct uuid* peer,
219 void** ctx_p) {
220 auto op = std::make_unique<TrustyOperation>();
221 if (!op) {
222 TLOGE("Failed to allocate TrustyOperation\n");
223 return ERR_NO_MEMORY;
224 }
225
226 struct chan_ctx* ctx = (struct chan_ctx*)calloc(1, sizeof(*ctx));
227 if (!ctx) {
228 TLOGE("Failed to allocate channel context\n");
229 return ERR_NO_MEMORY;
230 }
231
232 #if defined(PLATFORM_GENERIC_ARM64)
233 /* Use the test key for emulator. */
234 constexpr const auto kTestKey = teeui::AuthTokenKey::fill(
235 static_cast<uint8_t>(teeui::TestKeyBits::BYTE));
236 op->setHmacKey(kTestKey);
237 #else
238 teeui::AuthTokenKey authKey;
239 if (get_auth_token_key(authKey) == true) {
240 TLOGD("%s, get auth token key successfully\n", __func__);
241 } else {
242 TLOGE("%s, get auth token key failed\n", __func__);
243 /* Abort operation and free all resources. */
244 op->abort();
245 free(ctx);
246 return ERR_GENERIC;
247 }
248 op->setHmacKey(authKey);
249 #endif
250
251 ctx->op = std::move(op);
252 *ctx_p = ctx;
253 return NO_ERROR;
254 }
255
on_channel_cleanup(void * _ctx)256 static void on_channel_cleanup(void* _ctx) {
257 struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
258 /* Abort operation and free all resources. */
259 int rc = munmap(ctx->shm_base, ctx->shm_len);
260 if (rc != NO_ERROR) {
261 TLOGW("munmap() failed: %d\n", rc);
262 }
263 ctx->op->abort();
264 ctx->op.reset();
265 free(ctx);
266 }
267
on_message(const struct tipc_port * port,handle_t chan,void * _ctx)268 static int on_message(const struct tipc_port* port, handle_t chan, void* _ctx) {
269 int rc;
270 struct confirmationui_req req;
271 handle_t shm_handle = INVALID_IPC_HANDLE;
272 struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
273
274 assert(ctx);
275
276 rc = confirmationui_recv(chan, &req, &shm_handle);
277 if (rc < 0) {
278 TLOGE("Failed to receive confirmationui request (%d)\n", rc);
279 return rc;
280 }
281
282 if (rc != (int)sizeof(req)) {
283 TLOGE("Receive request of unexpected size(%d)\n", rc);
284 rc = ERR_BAD_LEN;
285 goto out;
286 }
287
288 switch (req.hdr.cmd) {
289 case CONFIRMATIONUI_CMD_INIT:
290 rc = handle_init(chan, shm_handle, req.init_args.shm_len, ctx);
291 goto out;
292
293 case CONFIRMATIONUI_CMD_MSG:
294 rc = handle_msg(chan, req.msg_args.msg_len, ctx);
295 goto out;
296
297 default:
298 TLOGE("cmd 0x%x: unknown command\n", req.hdr.cmd);
299 rc = ERR_CMD_UNKNOWN;
300 goto out;
301 }
302
303 out:
304 close(shm_handle);
305 return rc;
306 }
307
308 static struct tipc_port_acl confirmationui_port_acl = {
309 .flags = IPC_PORT_ALLOW_NS_CONNECT,
310 };
311
312 static struct tipc_port confirmationui_port = {
313 .name = CONFIRMATIONUI_PORT,
314 .msg_max_size = sizeof(confirmationui_req),
315 .msg_queue_len = 1,
316 .acl = &confirmationui_port_acl,
317 };
318
319 static struct tipc_srv_ops confirmationui_ops = {
320 .on_connect = on_connect,
321 .on_message = on_message,
322 .on_channel_cleanup = on_channel_cleanup,
323 };
324
main(void)325 int main(void) {
326 int rc;
327 struct tipc_hset* hset;
328
329 TLOGD("Initializing ConfirmationUI app\n");
330
331 hset = tipc_hset_create();
332 if (IS_ERR(hset)) {
333 TLOGE("Failed to create handle set (%d)\n", PTR_ERR(hset));
334 return PTR_ERR(hset);
335 }
336
337 rc = tipc_add_service(hset, &confirmationui_port, 1, 1,
338 &confirmationui_ops);
339 if (rc != NO_ERROR) {
340 return rc;
341 }
342
343 return tipc_run_event_loop(hset);
344 }
345