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