1 /*
2 * Copyright (c) 2011, The Linux Foundation. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <signal.h>
36 #include <syslog.h>
37 #include <unistd.h>
38 #include <linux/random.h>
39 #include <linux/types.h>
40 #include <sys/ioctl.h>
41 #include <sys/stat.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <sys/poll.h>
45 #include <linux/capability.h>
46 #include <sys/prctl.h>
47 #include <private/android_filesystem_config.h>
48
49 #ifdef ANDROID_CHANGES
50 #include <android/log.h>
51 #endif
52
53 #ifndef min
54 #define min(a,b) (((a)>(b))?(b):(a))
55 #endif
56
57 typedef unsigned char bool;
58
59 #define TRUE 1
60 #define FALSE 0
61
62 #define RANDOM_DEVICE "/dev/random"
63 #define RANDOM_DEVICE_HW "/dev/hw_random"
64
65 /* The device (/dev/random) internal limits 4096 bits of entropy, 512 bytes */
66 #define MAX_ENT_POOL_BITS 4096
67 #define MAX_ENT_POOL_BYTES (MAX_ENT_POOL_BITS / 8)
68
69 #define MAX_ENT_POOL_WRITES 128 /* write pool with smaller chunks */
70
71 ///* Burst-mode timeout in us (micro-seconds) */
72 //#define BURST_MODE_TIMEOUT 100000 /* 100ms */
73 ///* Idle-mode wait in us (micro-seconds) */
74 //#define IDLE_MODE_WAIT 10000 /* 10ms */
75
76 /* Buffer to hold hardware entropy bytes (this must be 2KB for FIPS testing */
77 #define MAX_BUFFER 2048 /* do not change this value */
78 static unsigned char databuf[MAX_BUFFER]; /* create buffer for FIPS testing */
79 static unsigned long buffsize; /* size of data in buffer */
80 static unsigned long curridx; /* position of current index */
81
82 /* Globals */
83 //static bool read_blocked = FALSE;
84 //static pid_t qrngd_pid;
85
86 /* User parameters */
87 struct user_options {
88 char input_device_name[128];
89 char output_device_name[128];
90 bool run_as_daemon;
91 };
92
93 /* Version number of this source */
94 #define APP_VERSION "1.01"
95 #define APP_NAME "qrngd"
96
97 const char *program_version =
98 APP_NAME " " APP_VERSION "\n"
99 "Copyright (c) 2011, The Linux Foundation. All rights reserved.\n"
100 "This is free software; see the source for copying conditions. There is NO\n"
101 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n";
102
103 const char *program_usage =
104 "Usage: " APP_NAME " [OPTION...]\n"
105 " -b background - become a daemon (default)\n"
106 " -f foreground - do not fork and become a daemon\n"
107 " -r <device name> hardware random input device (default: /dev/hw_random)\n"
108 " -o <device name> system random output device (default: /dev/random)\n"
109 " -h help (this page)\n";
110
111 /* Logging information */
112 enum log_level {
113 DEBUG = 0,
114 INFO = 1,
115 WARNING = 2,
116 ERROR = 3,
117 FATAL = 4,
118 LOG_MAX = 4,
119 };
120
121 /* Logging function for outputing to stderr or log */
log_print(int level,char * format,...)122 void log_print(int level, char *format, ...)
123 {
124 if (level >= 0 && level <= LOG_MAX) {
125 #ifdef ANDROID_CHANGES
126 static int levels[5] = {
127 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
128 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
129 };
130 va_list ap;
131 va_start(ap, format);
132 __android_log_vprint(levels[level], APP_NAME, format, ap);
133 va_end(ap);
134 #else
135 static char *levels = "DIWEF";
136 va_list ap;
137 fprintf(stderr, "%c: ", levels[level]);
138 va_start(ap, format);
139 vfprintf(stderr, format, ap);
140 va_end(ap);
141 fputc('\n', stderr);
142 #endif
143 }
144 }
145
title(void)146 static void title(void)
147 {
148 printf("%s", program_version);
149 }
150
usage(void)151 static void usage(void)
152 {
153 printf("%s", program_usage);
154 }
155
156 /* Parse command line parameters */
get_user_options(struct user_options * user_ops,int argc,char ** argv)157 static int get_user_options(struct user_options *user_ops, int argc, char **argv)
158 {
159 int max_params = argc;
160 int itr = 1; /* skip program name */
161 while (itr < max_params) {
162 if (argv[itr][0] != '-')
163 return -1;
164
165 switch (argv[itr++][1]) {
166 case 'b':
167 user_ops->run_as_daemon = TRUE;
168 break;
169
170 case 'f':
171 user_ops->run_as_daemon = FALSE;
172 break;
173
174 case 'r':
175 if (itr < max_params) {
176 if (strlen(argv[itr]) < sizeof(user_ops->input_device_name))
177 strcpy(user_ops->input_device_name, argv[itr++]);
178 else
179 return -1;
180 break;
181 }
182 else
183 return -1;
184
185 case 'o':
186 if (itr < max_params) {
187 if (strlen(argv[itr]) < sizeof(user_ops->output_device_name))
188 strcpy(user_ops->output_device_name, argv[itr++]);
189 else
190 return -1;
191 break;
192 }
193 else
194 return -1;
195
196 case 'h':
197 return -1;
198
199
200 default:
201 fprintf(stderr, "ERROR: Bad option: '%s'\n", argv[itr-1]);
202 return -1;
203 }
204 }
205 return 0;
206 }
207
208 /* Only check FIPS 140-2 (Continuous Random Number Generator Test) */
fips_test(const unsigned char * buf,size_t size)209 static int fips_test(const unsigned char *buf, size_t size)
210 {
211 unsigned long *buff_ul = (unsigned long *) buf;
212 size_t size_ul = size >> 2; /* convert byte to word size */
213 unsigned long last_value;
214 unsigned int rnd_ctr[256];
215 int i;
216
217
218 /* Continuous Random Number Generator Test */
219 last_value = *(buff_ul++);
220 size_ul--;
221
222 while (size_ul > 0) {
223 if (*buff_ul == last_value) {
224 log_print(ERROR, "ERROR: Bad word value from hardware.");
225 return -1;
226 } else
227 last_value = *buff_ul;
228 buff_ul++;
229 size_ul--;
230 }
231
232 /* count each random number */
233 for (i = 0; i < size; ++i) {
234 rnd_ctr[buf[i]]++;
235 }
236
237 /* check random numbers to make sure they are not bogus */
238 for (i = 0; i < 256; ++i) {
239 if (rnd_ctr[i] == 0) {
240 log_print(ERROR, "ERROR: Bad spectral random number sample.");
241 return -1;
242 }
243 }
244
245 return 0;
246 }
247
248 /* Read data from the hardware RNG source */
read_src(int fd,void * buf,size_t size)249 static int read_src(int fd, void *buf, size_t size)
250 {
251 size_t offset = 0;
252 char *chr = (char *) buf;
253 ssize_t ret;
254
255 if (!size)
256 return -1;
257 do {
258 ret = read(fd, chr + offset, size);
259 /* any read failure is bad */
260 if (ret == -1)
261 return -1;
262 size -= ret;
263 offset += ret;
264 } while (size > 0);
265
266 /* should have read in all of requested data */
267 if (size > 0)
268 return -1;
269 return 0;
270 }
271
272 /*Hold minimal permissions, so as to get IOCTL working*/
qrng_update_cap()273 static int qrng_update_cap()
274 {
275 int retvalue = 0;
276 struct __user_cap_header_struct header;
277 struct __user_cap_data_struct cap;
278
279 memset(&header, 0, sizeof(header));
280 memset(&cap, 0, sizeof(cap));
281 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
282 if( 0 != setgid(AID_SYSTEM)){
283 fprintf(stderr, "setgid error\n");
284 return -1;
285 }
286 if( 0 != setuid(AID_SYSTEM)){
287 fprintf(stderr, "setuid error\n");
288 return -1;
289 }
290 header.version = _LINUX_CAPABILITY_VERSION;
291 header.pid = 0;
292 cap.effective = (1 << CAP_SYS_ADMIN) | (1 << CAP_NET_RAW);
293 cap.permitted = cap.effective;
294 cap.inheritable = 0;
295 retvalue = capset(&header, &cap);
296 if(retvalue != 0){
297 fprintf(stderr, "capset error\n");
298 return -1;
299 }
300 return 0;
301 }
302
303 /* The beginning of everything */
main(int argc,char ** argv)304 int main(int argc, char **argv)
305 {
306 struct user_options user_ops; /* holds user configuration data */
307 struct rand_pool_info *rand = NULL; /* structure to pass entropy (IOCTL) */
308 int random_fd = 0; /* output file descriptor */
309 int random_hw_fd = 0; /* input file descriptor */
310 int ent_count; /* current system entropy */
311 int write_size; /* max entropy data to pass */
312 struct pollfd fds[1]; /* used for polling file descriptor */
313 int ret;
314 int exitval = 0;
315
316 /* set default parameters */
317 user_ops.run_as_daemon = TRUE;
318 strcpy(user_ops.input_device_name, RANDOM_DEVICE_HW);
319 strcpy(user_ops.output_device_name, RANDOM_DEVICE);
320
321 /* display application header */
322 title();
323
324 /* get user preferences */
325 ret = get_user_options(&user_ops, argc, argv);
326 if (ret < 0) {
327 usage();
328 exitval = 1;
329 goto exit;
330 }
331
332 /* open hardware random device */
333 random_hw_fd = open(user_ops.input_device_name, O_RDONLY);
334 if (random_hw_fd < 0) {
335 fprintf(stderr, "Can't open hardware random device file %s\n", user_ops.input_device_name);
336 exitval = 1;
337 goto exit;
338 }
339
340 /*Hold minimal permissions, just enough to get IOCTL working*/
341 if(0 != qrng_update_cap()){
342 log_print(ERROR, "qrngd permission reset failed, exiting\n");
343 exitval = 1;
344 goto exit;
345 }
346
347 /* open random device */
348 random_fd = open(user_ops.output_device_name, O_RDWR);
349 if (random_fd < 0) {
350 fprintf(stderr, "Can't open random device file %s\n", user_ops.output_device_name);
351 exitval = 1;
352 goto exit;
353 }
354
355 /* allocate memory for ioctl data struct and buffer */
356 rand = malloc(sizeof(struct rand_pool_info) + MAX_ENT_POOL_WRITES);
357 if (!rand) {
358 fprintf(stderr, "Can't allocate memory\n");
359 exitval = 1;
360 goto exit;
361 }
362
363 /* setup poll() data */
364 memset(fds, 0 , sizeof(fds));
365 fds[0].fd = random_fd;
366 fds[0].events = POLLOUT;
367
368 /* run as daemon if requested to do so */
369 if (user_ops.run_as_daemon) {
370 fprintf(stderr, "Starting daemon.\n");
371 if (daemon(0, 0) < 0) {
372 fprintf(stderr, "can't daemonize: %s\n", strerror(errno));
373 exitval = 1;
374 goto exit;
375 }
376 #ifndef ANDROID_CHANGES
377 openlog(APP_NAME, 0, LOG_DAEMON);
378 #endif
379 }
380
381 /* log message */
382 log_print(INFO, APP_NAME " has started:\n" "Reading device:'%s' updating entropy for device:'%s'",
383 user_ops.input_device_name,
384 user_ops.output_device_name);
385
386 /* main loop to get data from hardware and feed RNG entropy pool */
387 while (1) {
388
389 /* Check for empty buffer and fill with hardware random generated numbers */
390 if (buffsize == 0) {
391 /* fill buffer with random data from hardware */
392 ret = read_src(random_hw_fd, databuf, MAX_BUFFER);
393 if (ret < 0) {
394 log_print(ERROR, "ERROR: Can't read from hardware source.");
395 exitval = 1;
396 goto exit;
397 }
398 /* run FIPS test on buffer, if buffer fails then ditch it and get new data */
399 ret = fips_test(databuf, MAX_BUFFER);
400 if (ret < 0) {
401 buffsize = 0;
402 log_print(INFO, "ERROR: Failed FIPS test.");
403 }
404 /* everything good, reset buffer variables to indicate full buffer */
405 else {
406 buffsize = MAX_BUFFER;
407 curridx = 0;
408 }
409 }
410 /* We should have data here, if not then something bad happened above and we should wait and try again */
411 if (buffsize == 0) {
412 log_print(ERROR, "ERROR: Timeout getting valid random data from hardware.");
413 usleep(100000); /* 100ms */
414 continue;
415 }
416
417 /* Get current entropy pool size in bits and convert to bytes */
418 if (ioctl(random_fd, RNDGETENTCNT, &ent_count) != 0) {
419 log_print(ERROR, "ERROR: Can't read entropy count.");
420 exitval = 1;
421 goto exit;
422 }
423 /* convert entropy bits to bytes */
424 ent_count >>= 3;
425
426 /* fill entropy pool */
427 write_size = min(buffsize, MAX_ENT_POOL_WRITES);
428
429 /* Write some data to the device */
430 rand->entropy_count = write_size * 8;
431 rand->buf_size = write_size;
432 memcpy(rand->buf, &databuf[curridx], write_size);
433 curridx += write_size;
434 buffsize -= write_size;
435
436 /* Issue the ioctl to increase the entropy count */
437 if (ioctl(random_fd, RNDADDENTROPY, rand) < 0) {
438 log_print(ERROR,"ERROR: RNDADDENTROPY ioctl() failed.");
439 exitval = 1;
440 goto exit;
441 }
442
443 /* Wait if entropy pool is full */
444 ret = poll(fds, 1, -1);
445 if (ret < 0) {
446 log_print(ERROR,"ERROR: poll call failed.");
447 /* wait if error */
448 usleep(100000);
449 }
450 }
451
452 exit:
453 /* free other resources */
454 if (rand)
455 free(rand);
456 if (random_fd)
457 close(random_fd);
458 if (random_hw_fd)
459 close(random_hw_fd);
460 return exitval;
461 }
462
463