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