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