1 /*
2 * Copyright 2020, 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 "secure_dpu"
18
19 #include <assert.h>
20 #include <lib/tipc/tipc.h>
21 #include <lib/tipc/tipc_srv.h>
22 #include <lk/compiler.h>
23 #include <lk/macros.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/auxv.h>
27 #include <sys/mman.h>
28 #include <trusty_ipc.h>
29 #include <trusty_log.h>
30 #include <uapi/err.h>
31
32 #include <interface/secure_dpu/secure_dpu.h>
33 #include <lib/secure_dpu/secure_dpu.h>
34
35 struct secure_dpu_ctx {
36 /*
37 * This pointer is passed from user.
38 * Update this pointer when connecting / disconnecting.
39 */
40 handle_t* chan;
41 };
42
43 static struct secure_dpu_ctx ctx;
44
45 static struct tipc_port_acl acl = {
46 .flags = IPC_PORT_ALLOW_NS_CONNECT,
47 };
48 static struct tipc_port port = {
49 .name = SECURE_DPU_PORT_NAME,
50 .msg_max_size = SECURE_DPU_MAX_MSG_SIZE,
51 .msg_queue_len = 1,
52 .acl = &acl,
53 .priv = &ctx,
54 };
55
handle_allocate_buffer_resp(handle_t chan,size_t buffer_len,struct secure_dpu_buf_info * buf_info)56 static int handle_allocate_buffer_resp(handle_t chan,
57 size_t buffer_len,
58 struct secure_dpu_buf_info* buf_info) {
59 int rc = NO_ERROR;
60 struct uevent evt;
61 struct secure_dpu_resp hdr;
62 struct secure_dpu_allocate_buffer_resp resp;
63 handle_t buf_handle;
64
65 struct iovec iov[] = {
66 {
67 .iov_base = &hdr,
68 .iov_len = sizeof(hdr),
69 },
70 {
71 .iov_base = &resp,
72 .iov_len = sizeof(resp),
73 },
74 };
75
76 struct ipc_msg msg = {
77 .iov = iov,
78 .num_iov = countof(iov),
79 .handles = &buf_handle,
80 .num_handles = 1,
81 };
82
83 rc = wait(chan, &evt, INFINITE_TIME);
84 if (rc != NO_ERROR) {
85 TLOGE("Error waiting for response (%d)\n", rc);
86 return rc;
87 }
88
89 struct ipc_msg_info msg_inf;
90 rc = get_msg(chan, &msg_inf);
91 if (rc) {
92 return rc;
93 }
94
95 if (msg_inf.num_handles != 1) {
96 TLOGE("Message had no handles\n");
97 return ERR_INVALID_ARGS;
98 }
99
100 rc = read_msg(chan, msg_inf.id, 0, &msg);
101 put_msg(chan, msg_inf.id);
102 if (rc != (int)(sizeof(hdr) + sizeof(resp))) {
103 TLOGE("Read length does not match\n");
104 close(buf_handle);
105 return ERR_BAD_LEN;
106 }
107
108 if (hdr.cmd != (SECURE_DPU_CMD_ALLOCATE_BUFFER | SECURE_DPU_CMD_RESP_BIT)) {
109 close(buf_handle);
110 return ERR_CMD_UNKNOWN;
111 }
112
113 if (hdr.status != SECURE_DPU_ERROR_OK) {
114 TLOGE("Failed SECURE_DPU_CMD_ALLOCATE_BUFFER (%d)\n", hdr.status);
115 close(buf_handle);
116 return ERR_GENERIC;
117 }
118
119 if ((size_t)resp.buffer_len < buffer_len) {
120 TLOGE("Not allocated enough buffer length, "
121 "requested (%zu), allocated (%zu)\n", (size_t)buffer_len,
122 (size_t)resp.buffer_len);
123 close(buf_handle);
124 return ERR_NOT_ENOUGH_BUFFER;
125 }
126
127 buf_info->handle = buf_handle;
128 buf_info->len = (size_t)resp.buffer_len;
129
130 return NO_ERROR;
131 }
132
secure_dpu_allocate_buffer(handle_t chan,size_t buffer_len,struct secure_dpu_buf_info * buf_info)133 int secure_dpu_allocate_buffer(handle_t chan,
134 size_t buffer_len,
135 struct secure_dpu_buf_info* buf_info) {
136
137 int rc;
138 struct secure_dpu_req hdr;
139 struct secure_dpu_allocate_buffer_req args;
140 if (!buf_info) {
141 TLOGE("Invalid arguments to allocate DPU buffer\n");
142 return ERR_INVALID_ARGS;
143 }
144 if (chan == INVALID_IPC_HANDLE) {
145 TLOGE("Channel is not ready\n");
146 return ERR_NOT_READY;
147 }
148
149 hdr.cmd = SECURE_DPU_CMD_ALLOCATE_BUFFER;
150 args.buffer_len = (uint64_t)buffer_len;
151
152 rc = tipc_send2(chan, &hdr, sizeof(hdr), &args, sizeof(args));
153 if (rc != (int)(sizeof(hdr) + sizeof(args))) {
154 TLOGE("Failed to send SECURE_DPU_CMD_ALLOCATE_BUFFER request (%d)\n", rc);
155 return rc;
156 }
157
158 rc = handle_allocate_buffer_resp(chan, buffer_len, buf_info);
159 if (rc < 0) {
160 TLOGE("Failed to handle allocate buffer\n");
161 return rc;
162 }
163 return rc;
164 }
165
secure_dpu_release_buffer(struct secure_dpu_buf_info * buf_info)166 int secure_dpu_release_buffer(struct secure_dpu_buf_info* buf_info) {
167 if (!buf_info) {
168 TLOGE("Invalid arguments to release DPU buffer\n");
169 return ERR_INVALID_ARGS;
170 }
171
172 close(buf_info->handle);
173
174 return NO_ERROR;
175 }
176
handle_start_secure_display_resp(handle_t chan)177 static int handle_start_secure_display_resp(handle_t chan) {
178 int rc;
179 struct uevent evt;
180 struct secure_dpu_resp hdr;
181
182 rc = wait(chan, &evt, INFINITE_TIME);
183 if (rc != NO_ERROR) {
184 TLOGE("Error waiting for response (%d)\n", rc);
185 return rc;
186 }
187
188 rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
189 if (rc != sizeof(hdr)) {
190 TLOGE("Failed to receive SECURE_DPU_CMD_START_SECURE_DISPLAY response (%d)\n", rc);
191 return rc;
192 }
193
194 if (hdr.cmd != (SECURE_DPU_CMD_START_SECURE_DISPLAY | SECURE_DPU_CMD_RESP_BIT)) {
195 return ERR_CMD_UNKNOWN;
196 }
197
198 if (hdr.status != SECURE_DPU_ERROR_OK) {
199 TLOGE("Failed SECURE_DPU_CMD_START_SECURE_DISPLAY (%d)\n", hdr.status);
200 return ERR_GENERIC;
201 }
202
203 return NO_ERROR;
204 }
205
secure_dpu_start_secure_display(handle_t chan)206 int secure_dpu_start_secure_display(handle_t chan) {
207 int rc;
208 struct secure_dpu_req hdr;
209
210 if (chan == INVALID_IPC_HANDLE) {
211 TLOGE("Invalid arguments to start display\n");
212 return ERR_INVALID_ARGS;
213 }
214
215 hdr.cmd = SECURE_DPU_CMD_START_SECURE_DISPLAY;
216
217 rc = tipc_send1(chan, &hdr, sizeof(hdr));
218 if (rc != (int)(sizeof(hdr))) {
219 TLOGE("Failed to send SECURE_DPU_CMD_START_SECURE_DISPLAY request (%d)\n", rc);
220 return rc;
221 }
222
223 return handle_start_secure_display_resp(chan);
224 }
225
handle_stop_secure_display_resp(handle_t chan)226 static int handle_stop_secure_display_resp(handle_t chan) {
227 int rc;
228 struct uevent evt;
229 struct secure_dpu_resp hdr;
230
231 rc = wait(chan, &evt, INFINITE_TIME);
232 if (rc != NO_ERROR) {
233 TLOGE("Error waiting for response (%d)\n", rc);
234 return rc;
235 }
236
237 rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
238 if (rc != sizeof(hdr)) {
239 TLOGE("Failed to receive SECURE_DPU_CMD_STOP_SECURE_DISPLAY response (%d)\n", rc);
240 return rc;
241 }
242
243 if (hdr.cmd != (SECURE_DPU_CMD_STOP_SECURE_DISPLAY | SECURE_DPU_CMD_RESP_BIT)) {
244 return ERR_CMD_UNKNOWN;
245 }
246
247 if (hdr.status != SECURE_DPU_ERROR_OK) {
248 TLOGE("Failed SECURE_DPU_CMD_STOP_SECURE_DISPLAY (%d)\n", hdr.status);
249 return ERR_GENERIC;
250 }
251
252 return NO_ERROR;
253 }
254
secure_dpu_stop_secure_display(handle_t chan)255 int secure_dpu_stop_secure_display(handle_t chan) {
256 int rc;
257 struct secure_dpu_req hdr;
258
259 if (chan == INVALID_IPC_HANDLE) {
260 TLOGE("Invalid arguments to stop display\n");
261 return ERR_INVALID_ARGS;
262 }
263
264 hdr.cmd = SECURE_DPU_CMD_STOP_SECURE_DISPLAY;
265
266 rc = tipc_send1(chan, &hdr, sizeof(hdr));
267 if (rc != (int)(sizeof(hdr))) {
268 TLOGE("Failed to send SECURE_DPU_CMD_STOP_SECURE_DISPLAY request (%d)\n", rc);
269 return rc;
270 }
271
272 return handle_stop_secure_display_resp(chan);
273 }
274
275 /* Default message handler, not being used for normal case */
secure_dpu_on_message(const struct tipc_port * port,handle_t chan,void * _ctx)276 static int secure_dpu_on_message(const struct tipc_port* port,
277 handle_t chan,
278 void* _ctx) {
279 /* Not expect any incoming message to this default handler */
280 return ERR_CMD_UNKNOWN;
281 }
282
secure_dpu_on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)283 static int secure_dpu_on_connect(const struct tipc_port* port,
284 handle_t chan,
285 const struct uuid* peer,
286 void** ctx_p) {
287 struct secure_dpu_ctx* priv = (struct secure_dpu_ctx*)port->priv;
288
289 /* WORKAROUND(b/267744475):
290 * The secure display is a limited resource. This means only one client
291 * can have an open session at a time.
292 * Ideally the port's max_chan_cnt = 1 so we don't have to handle this
293 * case, but a stuck port or remote process could 'jam' the port / TA.
294 * So we accept the newest connection and drop anything previous.
295 */
296 if (*(priv->chan) != INVALID_IPC_HANDLE) {
297 TLOGE("New connection while connected, closing old\n");
298 close(*(priv->chan));
299 }
300
301 /* Update the handle to user provided pointer */
302 *(priv->chan) = chan;
303
304 return NO_ERROR;
305 }
306
secure_dpu_on_disconnect(const struct tipc_port * port,handle_t chan,void * ctx)307 void secure_dpu_on_disconnect(const struct tipc_port* port,
308 handle_t chan,
309 void* ctx) {
310 struct secure_dpu_ctx* priv = (struct secure_dpu_ctx*)port->priv;
311
312 assert(priv->chan);
313 *(priv->chan) = INVALID_IPC_HANDLE;
314 }
315
add_secure_dpu_service(struct tipc_hset * hset,handle_t * chan)316 int add_secure_dpu_service(struct tipc_hset* hset, handle_t* chan) {
317 if (!hset || !chan) {
318 return ERR_INVALID_ARGS;
319 }
320
321 ctx.chan = chan;
322
323 static struct tipc_srv_ops ops = {
324 .on_connect = secure_dpu_on_connect,
325 .on_disconnect = secure_dpu_on_disconnect,
326 .on_message = secure_dpu_on_message,
327 };
328
329 return tipc_add_service(hset, &port, 1 /* num_ports */,
330 2 /* max_chan_cnt */, &ops);
331 }
332