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