1 /*
2 * Copyright (C) 2016 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 "hwrng_srv"
18
19 #include <assert.h>
20 #include <inttypes.h>
21 #include <lk/list.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <uapi/err.h>
26
27 #include <hwcrypto/hwrng_dev.h>
28 #include <interface/hwrng/hwrng.h>
29 #include <lib/tipc/tipc.h>
30 #include <lib/tipc/tipc_srv.h>
31 #include <trusty_log.h>
32
33 #define HWRNG_SRV_NAME HWRNG_PORT
34 #define MAX_HWRNG_MSG_SIZE 4096
35
36 /* 0 means unlimited number of connections */
37 #define HWRNG_MAX_NUM_CHANNELS 0
38
39 struct hwrng_chan_ctx {
40 struct tipc_event_handler evt_handler;
41 struct list_node node;
42 handle_t chan;
43 size_t req_size;
44 int error;
45 bool send_blocked;
46 };
47
48 static uint8_t rng_data[MAX_HWRNG_MSG_SIZE];
49
50 static struct list_node hwrng_req_list = LIST_INITIAL_VALUE(hwrng_req_list);
51
52 /****************************************************************************/
53
54 /*
55 * Hexdump content of memory region
56 */
_hexdump8(const void * ptr,size_t len)57 static void _hexdump8(const void* ptr, size_t len) {
58 uintptr_t address = (uintptr_t)ptr;
59 size_t count;
60 size_t i;
61
62 for (count = 0; count < len; count += 16) {
63 fprintf(stderr, "0x%08" PRIxPTR ": ", address);
64 for (i = 0; i < MIN(len - count, 16); i++) {
65 fprintf(stderr, "0x%02hhx ", *(const uint8_t*)(address + i));
66 }
67 fprintf(stderr, "\n");
68 address += 16;
69 }
70 }
71
72 /*
73 * Handle HWRNG request queue
74 */
hwrng_handle_req_queue(void)75 static void hwrng_handle_req_queue(void) {
76 int rc;
77 struct hwrng_chan_ctx* ctx;
78 struct hwrng_chan_ctx* temp;
79
80 /* for all pending requests */
81 bool more_requests;
82 do {
83 more_requests = false;
84 list_for_every_entry_safe(&hwrng_req_list, ctx, temp,
85 struct hwrng_chan_ctx, node) {
86 if (ctx->error || ctx->send_blocked) {
87 continue; /* can't service it right now */
88 }
89
90 size_t len = ctx->req_size;
91
92 if (len > MAX_HWRNG_MSG_SIZE)
93 len = MAX_HWRNG_MSG_SIZE;
94
95 /* get hwrng data */
96 rc = trusty_rng_hw_rand(rng_data, len);
97 if (rc != NO_ERROR) {
98 TLOGE("failed (%d) to get hwrng data\n", rc);
99 ctx->error = rc;
100 continue;
101 }
102
103 /* send reply */
104 rc = tipc_send1(ctx->chan, rng_data, len);
105 if (rc < 0) {
106 if (rc == ERR_NOT_ENOUGH_BUFFER) {
107 /* mark it as send_blocked */
108 ctx->send_blocked = true;
109 } else {
110 /* just close HWRNG request channel */
111 TLOGE("failed (%d) to send_reply\n", rc);
112 ctx->error = rc;
113 }
114 continue;
115 }
116
117 ctx->req_size -= len;
118
119 if (ctx->req_size == 0) {
120 /* remove it from pending list */
121 list_delete(&ctx->node);
122 } else {
123 more_requests = true;
124 }
125 }
126 } while (more_requests);
127 }
128
129 /*
130 * Read and queue HWRNG request message
131 */
hwrng_chan_handle_msg(const struct tipc_port * port,handle_t chan,void * received_ctx)132 static int hwrng_chan_handle_msg(const struct tipc_port* port,
133 handle_t chan,
134 void* received_ctx) {
135 int rc;
136 struct hwrng_req req;
137
138 struct hwrng_chan_ctx* ctx = (struct hwrng_chan_ctx*)received_ctx;
139
140 assert(ctx);
141
142 /* check for an error from a previous send attempt */
143 if (ctx->error) {
144 return ctx->error;
145 }
146
147 /* read request */
148 rc = tipc_recv1(chan, sizeof(req), &req, sizeof(req));
149 if (rc < 0) {
150 TLOGE("failed (%d) to receive msg for chan %d\n", rc, chan);
151 return rc;
152 }
153
154 /* check if we already have request in progress */
155 if (list_in_list(&ctx->node)) {
156 /* extend it */
157 ctx->req_size += req.len;
158 } else {
159 /* queue it */
160 ctx->req_size = req.len;
161 list_add_tail(&hwrng_req_list, &ctx->node);
162 }
163
164 hwrng_handle_req_queue();
165
166 return ctx->error;
167 }
168
169 /*
170 * Create hwrng channel context
171 */
hwrng_chan_ctx_create(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx)172 static int hwrng_chan_ctx_create(const struct tipc_port* port,
173 handle_t chan,
174 const struct uuid* peer,
175 void** ctx) {
176 struct hwrng_chan_ctx* chan_ctx = calloc(1, sizeof(*chan_ctx));
177
178 if (!chan_ctx) {
179 return ERR_NO_MEMORY;
180 }
181
182 /* init channel state */
183 chan_ctx->chan = chan;
184 *ctx = chan_ctx;
185
186 return NO_ERROR;
187 }
188
189 /*
190 * Close specified hwrng channel context
191 */
hwrng_chan_ctx_close(void * ctx_rcv)192 static void hwrng_chan_ctx_close(void* ctx_rcv) {
193 struct hwrng_chan_ctx* ctx = (struct hwrng_chan_ctx*)ctx_rcv;
194
195 if (list_in_list(&ctx->node))
196 list_delete(&ctx->node);
197
198 close(ctx->chan);
199 free(ctx);
200 }
201
hwrng_handle_send_unblocked(const struct tipc_port * port,handle_t chan,void * ctx_v)202 static int hwrng_handle_send_unblocked(const struct tipc_port* port,
203 handle_t chan,
204 void* ctx_v) {
205 struct hwrng_chan_ctx* ctx = ctx_v;
206
207 if (ctx->error) {
208 return ctx->error;
209 }
210
211 ctx->send_blocked = false;
212
213 hwrng_handle_req_queue();
214
215 return ctx->error;
216 }
217
218 /*
219 * Initialize HWRNG services
220 */
hwrng_start_service(struct tipc_hset * hset)221 int hwrng_start_service(struct tipc_hset* hset) {
222 int rc;
223
224 TLOGD("Start HWRNG service\n");
225
226 static struct tipc_port_acl acl = {
227 .flags = IPC_PORT_ALLOW_TA_CONNECT,
228 .uuid_num = 0,
229 .uuids = NULL,
230 };
231
232 static struct tipc_port port = {
233 .name = HWRNG_SRV_NAME,
234 .msg_max_size = MAX_HWRNG_MSG_SIZE,
235 .msg_queue_len = 1,
236 .acl = &acl,
237 };
238
239 static struct tipc_srv_ops ops = {
240 .on_message = hwrng_chan_handle_msg,
241 .on_connect = hwrng_chan_ctx_create,
242 .on_channel_cleanup = hwrng_chan_ctx_close,
243 .on_send_unblocked = hwrng_handle_send_unblocked,
244 };
245
246 rc = hwrng_dev_init();
247 if (rc != NO_ERROR) {
248 TLOGE("Failed (%d) to initialize HWRNG device\n", rc);
249 return rc;
250 }
251
252 return tipc_add_service(hset, &port, 1, HWRNG_MAX_NUM_CHANNELS, &ops);
253 }
254