1 /*
2 * Copyright (C) 2016-2017 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 #include <assert.h>
18 #include <inttypes.h>
19 #include <lk/list.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <trusty_ipc.h>
25 #include <uapi/err.h>
26
27 #include <interface/hwrng/hwrng.h>
28
29 #include "common.h"
30 #include "hwrng_srv_priv.h"
31
32 #define TLOG_TAG "hwrng_srv"
33 #include <trusty_log.h>
34
35 #define HWRNG_SRV_NAME HWRNG_PORT
36 #define MAX_HWRNG_MSG_SIZE 4096
37
38 struct hwrng_chan_ctx {
39 tipc_event_handler_t evt_handler;
40 struct list_node node;
41 handle_t chan;
42 size_t req_size;
43 bool send_blocked;
44 };
45
46 static void hwrng_port_handler(const uevent_t* ev, void* priv);
47 static void hwrng_chan_handler(const uevent_t* ev, void* priv);
48
49 static handle_t hwrng_port = INVALID_IPC_HANDLE;
50
51 static tipc_event_handler_t hwrng_port_evt_handler = {
52 .proc = hwrng_port_handler,
53 };
54
55 static uint8_t rng_data[MAX_HWRNG_MSG_SIZE];
56
57 static struct list_node hwrng_req_list = LIST_INITIAL_VALUE(hwrng_req_list);
58
59 /****************************************************************************/
60
61 /*
62 * Hexdump content of memory region
63 */
_hexdump8(const void * ptr,size_t len)64 static void _hexdump8(const void* ptr, size_t len) {
65 uintptr_t address = (uintptr_t)ptr;
66 size_t count;
67 size_t i;
68
69 for (count = 0; count < len; count += 16) {
70 fprintf(stderr, "0x%08" PRIxPTR ": ", address);
71 for (i = 0; i < MIN(len - count, 16); i++) {
72 fprintf(stderr, "0x%02hhx ", *(const uint8_t*)(address + i));
73 }
74 fprintf(stderr, "\n");
75 address += 16;
76 }
77 }
78
79 /*
80 * Close specified HWRNG service channel
81 */
hwrng_close_chan(struct hwrng_chan_ctx * ctx)82 static void hwrng_close_chan(struct hwrng_chan_ctx* ctx) {
83 close(ctx->chan);
84
85 if (list_in_list(&ctx->node))
86 list_delete(&ctx->node);
87
88 free(ctx);
89 }
90
91 /*
92 * Handle HWRNG request queue
93 */
hwrng_handle_req_queue(void)94 static bool hwrng_handle_req_queue(void) {
95 struct hwrng_chan_ctx* ctx;
96 struct hwrng_chan_ctx* temp;
97
98 /* service channels */
99 bool need_more = false;
100
101 /* for all pending requests */
102 list_for_every_entry_safe(&hwrng_req_list, ctx, temp, struct hwrng_chan_ctx,
103 node) {
104 if (ctx->send_blocked)
105 continue; /* cant service it rignt now */
106
107 size_t len = ctx->req_size;
108
109 if (len > MAX_HWRNG_MSG_SIZE)
110 len = MAX_HWRNG_MSG_SIZE;
111
112 /* get rng data */
113 hwrng_dev_get_rng_data(rng_data, len);
114
115 /* send reply */
116 int rc = tipc_send_single_buf(ctx->chan, rng_data, len);
117 if (rc < 0) {
118 if (rc == ERR_NOT_ENOUGH_BUFFER) {
119 /* mark it as send_blocked */
120 ctx->send_blocked = true;
121 } else {
122 /* just close HWRNG request channel */
123 TLOGE("failed (%d) to send_reply\n", rc);
124 hwrng_close_chan(ctx);
125 }
126 continue;
127 }
128
129 ctx->req_size -= len;
130
131 if (ctx->req_size == 0) {
132 /* remove it from pending list */
133 list_delete(&ctx->node);
134 } else {
135 need_more = true;
136 }
137 }
138
139 return need_more;
140 }
141
142 /*
143 * Check if we can handle request queue
144 */
hwrng_kick_req_queue(void)145 static void hwrng_kick_req_queue(void) {
146 hwrng_handle_req_queue();
147 }
148
149 /*
150 * Read and queue HWRNG request message
151 */
hwrng_chan_handle_msg(struct hwrng_chan_ctx * ctx)152 static int hwrng_chan_handle_msg(struct hwrng_chan_ctx* ctx) {
153 int rc;
154 struct hwrng_req req;
155
156 assert(ctx);
157
158 /* read request */
159 rc = tipc_recv_single_buf(ctx->chan, &req, sizeof(req));
160 if (rc != sizeof(req)) {
161 TLOGE("failed (%d) to receive msg for chan %d\n", rc, ctx->chan);
162 return rc;
163 }
164
165 /* check if we already have request in progress */
166 if (list_in_list(&ctx->node)) {
167 /* extend it */
168 ctx->req_size += req.len;
169 } else {
170 /* queue it */
171 ctx->req_size = req.len;
172 list_add_tail(&hwrng_req_list, &ctx->node);
173 }
174
175 return 0;
176 }
177
178 /*
179 * Channel handler where HWRNG requests are coming from
180 */
hwrng_chan_handler(const uevent_t * ev,void * priv)181 static void hwrng_chan_handler(const uevent_t* ev, void* priv) {
182 struct hwrng_chan_ctx* ctx = priv;
183
184 assert(ctx);
185 assert(ev->handle == ctx->chan);
186
187 tipc_handle_chan_errors(ev);
188
189 if (ev->event & IPC_HANDLE_POLL_HUP) {
190 hwrng_close_chan(ctx);
191 } else {
192 if (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
193 ctx->send_blocked = false;
194 }
195
196 if (ev->event & IPC_HANDLE_POLL_MSG) {
197 int rc = hwrng_chan_handle_msg(ctx);
198 if (rc) {
199 hwrng_close_chan(ctx);
200 }
201 }
202 }
203
204 /* kick state machine */
205 hwrng_kick_req_queue();
206 }
207
208 /*
209 * Port were HWRNG requests are coming from
210 */
hwrng_port_handler(const uevent_t * ev,void * priv)211 static void hwrng_port_handler(const uevent_t* ev, void* priv) {
212 uuid_t peer_uuid;
213
214 tipc_handle_port_errors(ev);
215
216 if (ev->event & IPC_HANDLE_POLL_READY) {
217 handle_t chan;
218
219 /* incoming connection: accept it */
220 int rc = accept(ev->handle, &peer_uuid);
221 if (rc < 0) {
222 TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
223 return;
224 }
225 chan = (handle_t)rc;
226
227 /* allocate state */
228 struct hwrng_chan_ctx* ctx = calloc(1, sizeof(*ctx));
229 if (!ctx) {
230 TLOGE("failed to alloc state for chan %d\n", chan);
231 close(chan);
232 return;
233 }
234
235 /* init channel state */
236 ctx->evt_handler.priv = ctx;
237 ctx->evt_handler.proc = hwrng_chan_handler;
238 ctx->chan = chan;
239
240 /* attach channel handler */
241 rc = set_cookie(chan, &ctx->evt_handler);
242 if (rc) {
243 TLOGE("failed (%d) to set_cookie on chan %d\n", rc, chan);
244 free(ctx);
245 close(chan);
246 return;
247 }
248 }
249 }
250
251 /*
252 * Initialize HWRNG services
253 */
hwrng_start_service(void)254 int hwrng_start_service(void) {
255 int rc;
256
257 TLOGD("Start HWRNG service\n");
258
259 /* create HWRNG port */
260 rc = port_create(HWRNG_SRV_NAME, 1, MAX_HWRNG_MSG_SIZE,
261 IPC_PORT_ALLOW_TA_CONNECT);
262 if (rc < 0) {
263 TLOGE("Failed (%d) to create port '%s'\n", rc, HWRNG_SRV_NAME);
264 return rc;
265 } else {
266 hwrng_port = (handle_t)rc;
267 set_cookie(hwrng_port, &hwrng_port_evt_handler);
268 }
269
270 return NO_ERROR;
271 }
272