]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/random-util.c
Merge pull request #1681 from ssahani/journal
[thirdparty/systemd.git] / src / basic / random-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <linux/random.h>
23 #include <stdint.h>
24 #ifdef HAVE_SYS_AUXV_H
25 #include <sys/auxv.h>
26 #endif
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <time.h>
30
31 #include "fd-util.h"
32 #include "missing.h"
33 #include "random-util.h"
34 #include "time-util.h"
35 #include "util.h"
36
37 int dev_urandom(void *p, size_t n) {
38 static int have_syscall = -1;
39
40 _cleanup_close_ int fd = -1;
41 int r;
42
43 /* Gathers some randomness from the kernel. This call will
44 * never block, and will always return some data from the
45 * kernel, regardless if the random pool is fully initialized
46 * or not. It thus makes no guarantee for the quality of the
47 * returned entropy, but is good enough for or usual usecases
48 * of seeding the hash functions for hashtable */
49
50 /* Use the getrandom() syscall unless we know we don't have
51 * it, or when the requested size is too large for it. */
52 if (have_syscall != 0 || (size_t) (int) n != n) {
53 r = getrandom(p, n, GRND_NONBLOCK);
54 if (r == (int) n) {
55 have_syscall = true;
56 return 0;
57 }
58
59 if (r < 0) {
60 if (errno == ENOSYS)
61 /* we lack the syscall, continue with
62 * reading from /dev/urandom */
63 have_syscall = false;
64 else if (errno == EAGAIN)
65 /* not enough entropy for now. Let's
66 * remember to use the syscall the
67 * next time, again, but also read
68 * from /dev/urandom for now, which
69 * doesn't care about the current
70 * amount of entropy. */
71 have_syscall = true;
72 else
73 return -errno;
74 } else
75 /* too short read? */
76 return -ENODATA;
77 }
78
79 fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY);
80 if (fd < 0)
81 return errno == ENOENT ? -ENOSYS : -errno;
82
83 return loop_read_exact(fd, p, n, true);
84 }
85
86 void initialize_srand(void) {
87 static bool srand_called = false;
88 unsigned x;
89 #ifdef HAVE_SYS_AUXV_H
90 void *auxv;
91 #endif
92
93 if (srand_called)
94 return;
95
96 x = 0;
97
98 #ifdef HAVE_SYS_AUXV_H
99 /* The kernel provides us with a bit of entropy in auxv, so
100 * let's try to make use of that to seed the pseudo-random
101 * generator. It's better than nothing... */
102
103 auxv = (void*) getauxval(AT_RANDOM);
104 if (auxv)
105 x ^= *(unsigned*) auxv;
106 #endif
107
108 x ^= (unsigned) now(CLOCK_REALTIME);
109 x ^= (unsigned) gettid();
110
111 srand(x);
112 srand_called = true;
113 }
114
115 void random_bytes(void *p, size_t n) {
116 uint8_t *q;
117 int r;
118
119 r = dev_urandom(p, n);
120 if (r >= 0)
121 return;
122
123 /* If some idiot made /dev/urandom unavailable to us, he'll
124 * get a PRNG instead. */
125
126 initialize_srand();
127
128 for (q = p; q < (uint8_t*) p + n; q ++)
129 *q = rand();
130 }