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_fb_ipc"
18 
19 #include <lib/secure_fb/secure_fb.h>
20 
21 #include <assert.h>
22 #include <inttypes.h>
23 #include <lib/tipc/tipc.h>
24 #include <lk/compiler.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/mman.h>
28 #include <trusty_ipc.h>
29 #include <trusty_log.h>
30 #include <uapi/err.h>
31 
32 struct secure_fb_session {
33     handle_t chan;
34     size_t next_fb;
35     size_t num_fbs;
36     struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
37 };
38 
new_secure_fb_session(void)39 static struct secure_fb_session* new_secure_fb_session(void) {
40     struct secure_fb_session* s = calloc(1, sizeof(*s));
41     if (s == NULL) {
42         return NULL;
43     }
44 
45     s->chan = INVALID_IPC_HANDLE;
46     return s;
47 }
48 
free_secure_fb_session(struct secure_fb_session * s)49 static void free_secure_fb_session(struct secure_fb_session* s) {
50     for (size_t i = 0; i < SECURE_FB_MAX_FBS; ++i) {
51         uint8_t** buffer = &s->fbs[i].fb_info.buffer;
52         if (*buffer) {
53             int rc = munmap(*buffer, s->fbs[i].fb_info.size);
54             if (rc != NO_ERROR) {
55                 TLOGW("munmap() failed: %d\n", rc);
56             }
57             *buffer = NULL;
58         }
59     }
60     free(s);
61 }
62 
new_connected_session(uint32_t idx)63 static struct secure_fb_session* new_connected_session(uint32_t idx) {
64     char port_name[SECURE_FB_MAX_PORT_NAME_SIZE] = {0};
65     struct secure_fb_session* s;
66     int rc;
67 
68     if (idx >= SECURE_FB_MAX_INST) {
69         TLOGE("Invalid index %" PRIu32 "\n", idx);
70         return NULL;
71     }
72 
73     int n = snprintf(port_name, sizeof(port_name), "%s.%d", SECURE_FB_PORT_NAME,
74                      idx);
75     if (n != SECURE_FB_MAX_PORT_NAME_SIZE - 1) {
76         TLOGE("Failed to create port name\n");
77         return NULL;
78     }
79 
80     s = new_secure_fb_session();
81     if (s == NULL) {
82         TLOGE("Failed to create session\n");
83         return NULL;
84     }
85 
86     rc = tipc_connect(&s->chan, port_name);
87     if (rc != NO_ERROR) {
88         TLOGE("Failed to connect to \"%s_%d\" (%d)\n", SECURE_FB_PORT_NAME, idx,
89               rc);
90         free_secure_fb_session(s);
91         return NULL;
92     }
93 
94     return s;
95 }
96 
free_connected_session(struct secure_fb_session * s)97 static void free_connected_session(struct secure_fb_session* s) {
98     if (s->chan != INVALID_IPC_HANDLE) {
99         close(s->chan);
100     }
101     free_secure_fb_session(s);
102 }
103 
await_resp(handle_t chan,struct ipc_msg * msg)104 static int await_resp(handle_t chan, struct ipc_msg* msg) {
105     int rc;
106     uevent_t event;
107 
108     rc = wait(chan, &event, INFINITE_TIME);
109     if (rc < 0) {
110         TLOGE("Failed to wait for response (%d)\n", rc);
111         return rc;
112     }
113 
114     ipc_msg_info_t msg_info;
115     rc = get_msg(chan, &msg_info);
116     if (rc != 0) {
117         TLOGE("Failed to get_msg (%d)\n", rc);
118         return rc;
119     }
120 
121     rc = read_msg(chan, msg_info.id, 0, msg);
122     put_msg(chan, msg_info.id);
123     return rc;
124 }
125 
mmap_fbs(struct secure_fb_desc * fbs,size_t num_fbs,handle_t * handles)126 static int mmap_fbs(struct secure_fb_desc* fbs,
127                     size_t num_fbs,
128                     handle_t* handles) {
129     struct secure_fb_desc* fb;
130 
131     for (size_t i = 0; i < num_fbs; i++) {
132         fb = &fbs[i];
133         fb->fb_info.buffer =
134                 mmap(NULL, fb->fb_info.size, PROT_READ | PROT_WRITE, 0,
135                      handles[fb->handle_index], fb->offset);
136         if (fb->fb_info.buffer == MAP_FAILED) {
137             goto err;
138         }
139     }
140     return NO_ERROR;
141 
142 err:
143     for (size_t i = 0; i < num_fbs; i++) {
144         fb = &fbs[i];
145         if (fb->fb_info.buffer) {
146             int rc = munmap(fb->fb_info.buffer, fb->fb_info.size);
147             if (rc != NO_ERROR) {
148                 TLOGW("munmap() failed: %d\n", rc);
149             }
150         }
151         memset(fb, 0, sizeof(*fb));
152     }
153     return ERR_BAD_HANDLE;
154 }
155 
handle_get_fbs_resp(struct secure_fb_session * s)156 static int handle_get_fbs_resp(struct secure_fb_session* s) {
157     int rc;
158     struct secure_fb_resp hdr;
159     struct secure_fb_get_fbs_resp args;
160     struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
161     size_t fbs_len;
162     handle_t handles[SECURE_FB_MAX_FBS] = {[0 ... SECURE_FB_MAX_FBS - 1] =
163                                                    INVALID_IPC_HANDLE};
164     struct iovec iovs[] = {
165             {
166                     .iov_base = &hdr,
167                     .iov_len = sizeof(hdr),
168             },
169             {
170                     .iov_base = &args,
171                     .iov_len = sizeof(args),
172             },
173             {
174                     .iov_base = fbs,
175                     .iov_len = sizeof(fbs),
176             },
177     };
178     struct ipc_msg msg = {
179             .num_iov = countof(iovs),
180             .iov = iovs,
181             .num_handles = SECURE_FB_MAX_FBS,
182             .handles = handles,
183     };
184 
185     rc = await_resp(s->chan, &msg);
186     if (rc < 0) {
187         return rc;
188     }
189 
190     if (rc < (int)(sizeof(hdr) + sizeof(args))) {
191         return ERR_BAD_LEN;
192     }
193 
194     fbs_len = sizeof(fbs[0]) * args.num_fbs;
195 
196     if (rc != (int)(sizeof(hdr) + sizeof(args) + fbs_len)) {
197         if (rc >= 0) {
198             return ERR_BAD_LEN;
199         }
200         return rc;
201     }
202 
203     if (hdr.cmd != (SECURE_FB_CMD_GET_FBS | SECURE_FB_CMD_RESP_BIT)) {
204         return ERR_CMD_UNKNOWN;
205     }
206 
207     if (hdr.status != SECURE_FB_ERROR_OK) {
208         TLOGE("Failed SECURE_FB_CMD_DISPLAY_FB request (%d)\n", hdr.status);
209         return ERR_GENERIC;
210     }
211 
212     rc = mmap_fbs(fbs, args.num_fbs, handles);
213     /* Close all received handles. We don't need to keep them around. */
214     for (size_t i = 0; i < SECURE_FB_MAX_FBS; ++i) {
215         if (handles[i] != INVALID_IPC_HANDLE) {
216             close(handles[i]);
217         }
218     }
219 
220     if (rc != NO_ERROR) {
221         TLOGE("Failed to mmap() framebuffers (%d)\n", hdr.status);
222         return rc;
223     }
224 
225     for (size_t i = 0; i < (size_t)args.num_fbs; ++i) {
226         s->fbs[i] = fbs[i];
227     }
228     s->num_fbs = args.num_fbs;
229     s->next_fb = 0;
230     return NO_ERROR;
231 }
232 
get_fbs(struct secure_fb_session * s)233 static int get_fbs(struct secure_fb_session* s) {
234     int rc;
235     struct secure_fb_req req;
236 
237     assert(s->chan != INVALID_IPC_HANDLE);
238 
239     req.cmd = SECURE_FB_CMD_GET_FBS;
240     rc = tipc_send1(s->chan, &req, sizeof(req));
241     if (rc != (int)sizeof(req)) {
242         TLOGE("Failed to send SECURE_FB_CMD_GET_FBS request (%d)\n", rc);
243         if (rc >= 0) {
244             rc = ERR_BAD_LEN;
245         }
246         return rc;
247     }
248 
249     return handle_get_fbs_resp(s);
250 }
251 
handle_display_fb_resp(handle_t chan)252 static int handle_display_fb_resp(handle_t chan) {
253     int rc;
254     struct uevent evt;
255     struct secure_fb_resp hdr;
256 
257     rc = wait(chan, &evt, INFINITE_TIME);
258     if (rc != NO_ERROR) {
259         TLOGE("Error waiting for response (%d)\n", rc);
260         return rc;
261     }
262 
263     rc = tipc_recv1(chan, sizeof(hdr), &hdr, sizeof(hdr));
264     if (rc < 0) {
265         TLOGE("Failed to receive SECURE_FB_CMD_DISPLAY_FB response (%d)\n", rc);
266         return rc;
267     }
268 
269     if (hdr.cmd != (SECURE_FB_CMD_DISPLAY_FB | SECURE_FB_CMD_RESP_BIT)) {
270         return ERR_CMD_UNKNOWN;
271     }
272 
273     if (hdr.status != SECURE_FB_ERROR_OK) {
274         TLOGE("Failed SECURE_FB_CMD_DISPLAY_FB (%d)\n", hdr.status);
275         return ERR_GENERIC;
276     }
277 
278     return NO_ERROR;
279 }
280 
display_fb(handle_t chan,uint32_t buffer_id)281 static int display_fb(handle_t chan, uint32_t buffer_id) {
282     int rc;
283     struct secure_fb_req hdr;
284     struct secure_fb_display_fb_req args;
285 
286     hdr.cmd = SECURE_FB_CMD_DISPLAY_FB;
287     args.buffer_id = buffer_id;
288 
289     rc = tipc_send2(chan, &hdr, sizeof(hdr), &args, sizeof(args));
290     if (rc != (int)(sizeof(hdr) + sizeof(args))) {
291         TLOGE("Failed to send SECURE_FB_CMD_DISPLAY_FB request (%d)\n", rc);
292         return rc;
293     }
294 
295     return handle_display_fb_resp(chan);
296 }
297 
secure_fb_open(secure_fb_handle_t * session,struct secure_fb_info * fb_info,uint32_t idx)298 secure_fb_error secure_fb_open(secure_fb_handle_t* session,
299                                struct secure_fb_info* fb_info,
300                                uint32_t idx) {
301     int rc;
302     struct secure_fb_session* s;
303 
304     if (!session) {
305         return TTUI_ERROR_UNEXPECTED_NULL_PTR;
306     }
307 
308     s = new_connected_session(idx);
309     if (s == NULL) {
310         return TTUI_ERROR_NO_SERVICE;
311     }
312 
313     rc = get_fbs(s);
314     if (rc != NO_ERROR) {
315         free_connected_session(s);
316         return TTUI_ERROR_MEMORY_ALLOCATION_FAILED;
317     }
318 
319     *fb_info = s->fbs[s->next_fb].fb_info;
320     *session = (secure_fb_handle_t)s;
321     return TTUI_ERROR_OK;
322 }
323 
secure_fb_display_next(secure_fb_handle_t session,struct secure_fb_info * fb_info)324 secure_fb_error secure_fb_display_next(secure_fb_handle_t session,
325                                        struct secure_fb_info* fb_info) {
326     int rc;
327     uint32_t buffer_id;
328     struct secure_fb_session* s = (struct secure_fb_session*)session;
329 
330     if (!fb_info || !s) {
331         return TTUI_ERROR_UNEXPECTED_NULL_PTR;
332     }
333 
334     buffer_id = s->fbs[s->next_fb].buffer_id;
335     rc = display_fb(s->chan, buffer_id);
336     if (rc != NO_ERROR) {
337         return TTUI_ERROR_NO_FRAMEBUFFER;
338     }
339 
340     s->next_fb = (s->next_fb + 1) % s->num_fbs;
341     *fb_info = s->fbs[s->next_fb].fb_info;
342     return TTUI_ERROR_OK;
343 }
344 
secure_fb_close(secure_fb_handle_t session)345 void secure_fb_close(secure_fb_handle_t session) {
346     int rc;
347     struct secure_fb_req req;
348     struct secure_fb_session* s = (struct secure_fb_session*)session;
349 
350     if (!s || s->chan == INVALID_IPC_HANDLE) {
351         return;
352     }
353 
354     req.cmd = SECURE_FB_CMD_RELEASE;
355     rc = tipc_send1(s->chan, &req, sizeof(req));
356     if (rc != (int)sizeof(req)) {
357         TLOGE("Failed to send SECURE_FB_CMD_RELEASE request (%d)\n", rc);
358     }
359 
360     free_connected_session(s);
361 }
362