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