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_service"
18 
19 #include <assert.h>
20 #include <interface/secure_fb/secure_fb.h>
21 #include <lib/secure_fb/srv/dev.h>
22 #include <lib/secure_fb/srv/srv.h>
23 #include <lib/tipc/tipc.h>
24 #include <lib/tipc/tipc_srv.h>
25 #include <lk/compiler.h>
26 #include <lk/macros.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <trusty_ipc.h>
30 #include <trusty_log.h>
31 #include <uapi/err.h>
32 
33 struct secure_fb_ctx {
34     secure_fb_handle_t session;
35     const struct secure_fb_impl_ops* ops;
36 };
37 
38 /* UUID: {7dee2364-c036-425b-b086-df0f6c233c1b} */
39 static const struct uuid confirmationui_uuid = {
40         0x7dee2364,
41         0xc036,
42         0x425b,
43         {0xb0, 0x86, 0xdf, 0x0f, 0x6c, 0x23, 0x3c, 0x1b},
44 };
45 
46 /* UUID: {e181673c-7d7b-4b98-b962-5a3e6d59d855} */
47 static const struct uuid secure_fb_test_uuid = {
48         0xe181673c,
49         0x7d7b,
50         0x4b98,
51         {0xb9, 0x62, 0x5a, 0x3e, 0x6d, 0x59, 0xd8, 0x55},
52 };
53 
54 /*
55  * TODO: We'll need to configure ACL in a device-specific manner, but right now
56  * we know/control all the clients of this service.
57  */
58 static const struct uuid* allowed_uuids[] = {
59         &confirmationui_uuid,
60         &secure_fb_test_uuid,
61 };
62 
secure_fb_check_impl_ops(const struct secure_fb_impl_ops * ops)63 static int secure_fb_check_impl_ops(const struct secure_fb_impl_ops* ops) {
64     if (!ops->init || !ops->get_fbs || !ops->display_fb || !ops->release) {
65         TLOGE("NULL ops pointers\n");
66         return ERR_INVALID_ARGS;
67     }
68     return NO_ERROR;
69 }
70 
secure_fb_on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)71 static int secure_fb_on_connect(const struct tipc_port* port,
72                                 handle_t chan,
73                                 const struct uuid* peer,
74                                 void** ctx_p) {
75     struct secure_fb_ctx* ctx = malloc(sizeof(*ctx));
76     if (ctx == NULL) {
77         TLOGE("Memory allocation failed.\n");
78         return ERR_NO_MEMORY;
79     }
80 
81     ctx->ops = (const struct secure_fb_impl_ops*)port->priv;
82     assert(ctx->ops);
83     ctx->session = ctx->ops->init();
84     if (ctx->session == NULL) {
85         TLOGE("Driver initialization failed.\n");
86         free(ctx);
87         return ERR_GENERIC;
88     }
89 
90     *ctx_p = ctx;
91     return NO_ERROR;
92 }
93 
secure_fb_on_channel_cleanup(void * _ctx)94 static void secure_fb_on_channel_cleanup(void* _ctx) {
95     struct secure_fb_ctx* ctx = (struct secure_fb_ctx*)_ctx;
96     if (ctx->session != NULL) {
97         ctx->ops->release(ctx->session);
98     }
99     free(ctx);
100 }
101 
handle_get_fbs_req(handle_t chan,struct secure_fb_ctx * ctx)102 static int handle_get_fbs_req(handle_t chan, struct secure_fb_ctx* ctx) {
103     int rc;
104     struct secure_fb_impl_buffers buffers;
105     struct secure_fb_resp hdr;
106     struct secure_fb_get_fbs_resp args;
107     struct secure_fb_desc fbs[SECURE_FB_MAX_FBS];
108     size_t fbs_len;
109     secure_fb_handle_t session = ctx->session;
110 
111     rc = ctx->ops->get_fbs(session, &buffers);
112     if (rc != SECURE_FB_ERROR_OK) {
113         TLOGE("Failed secure_fb_impl_get_fbs() (%d)\n", rc);
114 
115         /* Ensure nothing is returned, but continue to send error code */
116         buffers.num_fbs = 0;
117         buffers.num_handles = 0;
118     }
119 
120     hdr.cmd = SECURE_FB_CMD_GET_FBS | SECURE_FB_CMD_RESP_BIT;
121     hdr.status = rc;
122 
123     args.num_fbs = buffers.num_fbs;
124 
125     fbs_len = sizeof(fbs[0]) * args.num_fbs;
126     memcpy(fbs, buffers.fbs, fbs_len);
127 
128     struct iovec iovs[] = {
129             {
130                     .iov_base = &hdr,
131                     .iov_len = sizeof(hdr),
132             },
133             {
134                     .iov_base = &args,
135                     .iov_len = sizeof(args),
136             },
137             {
138                     .iov_base = fbs,
139                     .iov_len = fbs_len,
140             },
141     };
142     ipc_msg_t msg = {
143             .num_iov = countof(iovs),
144             .iov = iovs,
145             .num_handles = buffers.num_handles,
146             .handles = buffers.handles,
147     };
148     rc = send_msg(chan, &msg);
149     if (rc != (int)(sizeof(hdr) + sizeof(args) + fbs_len)) {
150         TLOGE("Failed to send SECURE_FB_CMD_GET_FBS response (%d)\n", rc);
151         if (rc >= 0) {
152             return ERR_BAD_LEN;
153         }
154     }
155 
156     return NO_ERROR;
157 }
158 
handle_display_fb(handle_t chan,struct secure_fb_display_fb_req * display_fb,struct secure_fb_ctx * ctx)159 static int handle_display_fb(handle_t chan,
160                              struct secure_fb_display_fb_req* display_fb,
161                              struct secure_fb_ctx* ctx) {
162     int rc;
163     struct secure_fb_resp hdr;
164     secure_fb_handle_t session = ctx->session;
165 
166     rc = ctx->ops->display_fb(session, display_fb->buffer_id);
167     if (rc != SECURE_FB_ERROR_OK) {
168         TLOGE("Failed secure_fb_impl_display_fb() (%d)\n", rc);
169 
170         /* Continue to return error code */
171     }
172 
173     hdr.cmd = SECURE_FB_CMD_DISPLAY_FB | SECURE_FB_CMD_RESP_BIT;
174     hdr.status = rc;
175 
176     rc = tipc_send1(chan, &hdr, sizeof(hdr));
177     if (rc != (int)sizeof(hdr)) {
178         TLOGE("Failed to send SECURE_FB_CMD_DISPLAY_FB response (%d)\n", rc);
179         if (rc >= 0) {
180             rc = ERR_BAD_LEN;
181         }
182         return rc;
183     }
184 
185     return NO_ERROR;
186 }
187 
secure_fb_on_message(const struct tipc_port * port,handle_t chan,void * _ctx)188 static int secure_fb_on_message(const struct tipc_port* port,
189                                 handle_t chan,
190                                 void* _ctx) {
191     int rc;
192     struct {
193         struct secure_fb_req hdr;
194         union {
195             struct secure_fb_display_fb_req display_fb;
196         };
197     } req;
198     struct secure_fb_ctx* ctx = (struct secure_fb_ctx*)_ctx;
199 
200     rc = tipc_recv1(chan, sizeof(req.hdr), &req, sizeof(req));
201     if (rc < 0) {
202         TLOGE("Failed to read command %d\n", rc);
203         return ERR_BAD_LEN;
204     }
205 
206     switch (req.hdr.cmd) {
207     case SECURE_FB_CMD_GET_FBS:
208         if (rc != (int)sizeof(req.hdr)) {
209             TLOGE("Failed to read SECURE_FB_CMD_GET_FBS request (%d)\n", rc);
210             return ERR_BAD_LEN;
211         }
212         return handle_get_fbs_req(chan, ctx);
213 
214     case SECURE_FB_CMD_DISPLAY_FB:
215         if (rc != (int)(sizeof(req.hdr) + sizeof(req.display_fb))) {
216             TLOGE("Failed to read SECURE_FB_CMD_DISPLAY_FB request (%d)\n", rc);
217             return ERR_BAD_LEN;
218         }
219         return handle_display_fb(chan, &req.display_fb, ctx);
220 
221     case SECURE_FB_CMD_RELEASE:
222         if (rc != (int)sizeof(req.hdr)) {
223             TLOGE("Failed to read SECURE_FB_CMD_RELEASE request (%d)\n", rc);
224             return ERR_BAD_LEN;
225         }
226         ctx->ops->release(ctx->session);
227         ctx->session = NULL;
228         return NO_ERROR;
229 
230     default:
231         TLOGW("Received unknown command %x\n", req.hdr.cmd);
232         return ERR_CMD_UNKNOWN;
233     }
234 
235     return NO_ERROR;
236 }
237 
add_secure_fb_service(struct tipc_hset * hset,const struct secure_fb_impl_ops * impl_ops,uint32_t num_ops)238 int add_secure_fb_service(struct tipc_hset* hset,
239                           const struct secure_fb_impl_ops* impl_ops,
240                           uint32_t num_ops) {
241     int rc;
242     uint32_t i;
243     char* port_name_base;
244 
245     if (!hset || !impl_ops) {
246         TLOGE("NULL pointer arguments\n");
247         return ERR_INVALID_ARGS;
248     }
249     if (num_ops > SECURE_FB_MAX_INST) {
250         TLOGE("Number of instance exceeds the limitation\n");
251         return ERR_INVALID_ARGS;
252     }
253     for (i = 0; i < num_ops; ++i) {
254         if ((rc = secure_fb_check_impl_ops(&impl_ops[i])) != NO_ERROR) {
255             TLOGE("Failed to check impl ops\n");
256             return rc;
257         }
258     }
259 
260     static struct tipc_port_acl acl = {
261             .flags = IPC_PORT_ALLOW_TA_CONNECT,
262             .uuids = allowed_uuids,
263             .uuid_num = countof(allowed_uuids),
264     };
265 
266     static struct tipc_srv_ops ops = {
267             .on_connect = secure_fb_on_connect,
268             .on_message = secure_fb_on_message,
269             .on_channel_cleanup = secure_fb_on_channel_cleanup,
270     };
271 
272     struct tipc_port* port = calloc(num_ops, sizeof(struct tipc_port));
273     if (port == NULL) {
274         TLOGE("Memory allocation failed.\n");
275         rc = ERR_NO_MEMORY;
276         goto fail_port_alloc;
277     }
278     port_name_base =
279             calloc(num_ops, sizeof(char) * SECURE_FB_MAX_PORT_NAME_SIZE);
280     if (port_name_base == NULL) {
281         TLOGE("Memory allocation failed.\n");
282         rc = ERR_NO_MEMORY;
283         goto fail_port_name_alloc;
284     }
285 
286     for (i = 0; i < num_ops; ++i) {
287         char* port_name = port_name_base + SECURE_FB_MAX_PORT_NAME_SIZE * i;
288         port[i].name = port_name;
289         port[i].msg_max_size = 1024;
290         port[i].msg_queue_len = 1;
291         port[i].acl = &acl;
292         port[i].priv = (void*)&impl_ops[i];
293 
294         int n = sprintf(port_name, "%s.%d", SECURE_FB_PORT_NAME, i);
295         if (n != SECURE_FB_MAX_PORT_NAME_SIZE - 1) {
296             TLOGE("Failed to create port name\n");
297             rc = ERR_BAD_LEN;
298             goto fail;
299         }
300     }
301     /*
302      * The secure display is a limited resource. This means only one client
303      * can have an open session at a time.
304      */
305     rc = tipc_add_service(hset, port, num_ops, num_ops, &ops);
306     if (rc) {
307         TLOGE("Failed to add tipc service\n");
308         goto fail;
309     }
310     return rc;
311 
312 fail:
313     free(port_name_base);
314 fail_port_name_alloc:
315     free(port);
316 fail_port_alloc:
317     return rc;
318 }
319