diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/Makefile.am | 2 | ||||
-rw-r--r-- | src/shared/hashmap.c | 1 | ||||
-rw-r--r-- | src/shared/random-util.c | 127 | ||||
-rw-r--r-- | src/shared/random-util.h | 38 | ||||
-rw-r--r-- | src/shared/util.c | 114 | ||||
-rw-r--r-- | src/shared/util.h | 5 |
6 files changed, 181 insertions, 106 deletions
diff --git a/src/shared/Makefile.am b/src/shared/Makefile.am index 9f2df41e70..b0b4f59a6c 100644 --- a/src/shared/Makefile.am +++ b/src/shared/Makefile.am @@ -20,6 +20,7 @@ libudev_shared_la_SOURCES=\ MurmurHash2.c \ path-util.c \ process-util.c \ + random-util.c \ selinux-util.c \ siphash24.c \ smack-util.c \ @@ -53,6 +54,7 @@ noinst_HEADERS = \ MurmurHash2.h \ path-util.h \ process-util.h \ + random-util.h \ selinux-util.h \ set.h \ siphash24.h \ diff --git a/src/shared/hashmap.c b/src/shared/hashmap.c index 084743e4fb..49bccacb5c 100644 --- a/src/shared/hashmap.c +++ b/src/shared/hashmap.c @@ -33,6 +33,7 @@ #include "strv.h" #include "list.h" #include "mempool.h" +#include "random-util.h" /* * Implementation of hashmaps. diff --git a/src/shared/random-util.c b/src/shared/random-util.c new file mode 100644 index 0000000000..88f5182508 --- /dev/null +++ b/src/shared/random-util.c @@ -0,0 +1,127 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdint.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <sys/auxv.h> +#include <linux/random.h> + +#include "random-util.h" +#include "time-util.h" +#include "missing.h" +#include "util.h" + +int dev_urandom(void *p, size_t n) { + static int have_syscall = -1; + + _cleanup_close_ int fd = -1; + int r; + + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + /* Use the getrandom() syscall unless we know we don't have + * it, or when the requested size is too large for it. */ + if (have_syscall != 0 || (size_t) (int) n != n) { + r = getrandom(p, n, GRND_NONBLOCK); + if (r == (int) n) { + have_syscall = true; + return 0; + } + + if (r < 0) { + if (errno == ENOSYS) + /* we lack the syscall, continue with + * reading from /dev/urandom */ + have_syscall = false; + else if (errno == EAGAIN) + /* not enough entropy for now. Let's + * remember to use the syscall the + * next time, again, but also read + * from /dev/urandom for now, which + * doesn't care about the current + * amount of entropy. */ + have_syscall = true; + else + return -errno; + } else + /* too short read? */ + return -ENODATA; + } + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return errno == ENOENT ? -ENOSYS : -errno; + + return loop_read_exact(fd, p, n, true); +} + +void initialize_srand(void) { + static bool srand_called = false; + unsigned x; +#ifdef HAVE_SYS_AUXV_H + void *auxv; +#endif + + if (srand_called) + return; + + x = 0; + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned*) auxv; +#endif + + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); + srand_called = true; +} + +void random_bytes(void *p, size_t n) { + uint8_t *q; + int r; + + r = dev_urandom(p, n); + if (r >= 0) + return; + + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ + + initialize_srand(); + + for (q = p; q < (uint8_t*) p + n; q ++) + *q = rand(); +} diff --git a/src/shared/random-util.h b/src/shared/random-util.h new file mode 100644 index 0000000000..f7862c8c8b --- /dev/null +++ b/src/shared/random-util.h @@ -0,0 +1,38 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdint.h> + +int dev_urandom(void *p, size_t n); +void random_bytes(void *p, size_t n); +void initialize_srand(void); + +static inline uint64_t random_u64(void) { + uint64_t u; + random_bytes(&u, sizeof(u)); + return u; +} + +static inline uint32_t random_u32(void) { + uint32_t u; + random_bytes(&u, sizeof(u)); + return u; +} diff --git a/src/shared/util.c b/src/shared/util.c index d22ab8631f..0b04411f82 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -70,6 +70,7 @@ #include "fileio.h" #include "virt.h" #include "process-util.h" +#include "random-util.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -719,6 +720,17 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { return n; } +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { + ssize_t n; + + n = loop_read(fd, buf, nbytes, do_poll); + if (n < 0) + return n; + if ((size_t) n != nbytes) + return -EIO; + return 0; +} + char* dirname_malloc(const char *path) { char *d, *dir, *dir2; @@ -737,108 +749,6 @@ char* dirname_malloc(const char *path) { return dir; } -int dev_urandom(void *p, size_t n) { - static int have_syscall = -1; - int r, fd; - ssize_t k; - - /* Gathers some randomness from the kernel. This call will - * never block, and will always return some data from the - * kernel, regardless if the random pool is fully initialized - * or not. It thus makes no guarantee for the quality of the - * returned entropy, but is good enough for or usual usecases - * of seeding the hash functions for hashtable */ - - /* Use the getrandom() syscall unless we know we don't have - * it, or when the requested size is too large for it. */ - if (have_syscall != 0 || (size_t) (int) n != n) { - r = getrandom(p, n, GRND_NONBLOCK); - if (r == (int) n) { - have_syscall = true; - return 0; - } - - if (r < 0) { - if (errno == ENOSYS) - /* we lack the syscall, continue with - * reading from /dev/urandom */ - have_syscall = false; - else if (errno == EAGAIN) - /* not enough entropy for now. Let's - * remember to use the syscall the - * next time, again, but also read - * from /dev/urandom for now, which - * doesn't care about the current - * amount of entropy. */ - have_syscall = true; - else - return -errno; - } else - /* too short read? */ - return -EIO; - } - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return errno == ENOENT ? -ENOSYS : -errno; - - k = loop_read(fd, p, n, true); - safe_close(fd); - - if (k < 0) - return (int) k; - if ((size_t) k != n) - return -EIO; - - return 0; -} - -void initialize_srand(void) { - static bool srand_called = false; - unsigned x; -#ifdef HAVE_SYS_AUXV_H - void *auxv; -#endif - - if (srand_called) - return; - - x = 0; - -#ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in auxv, so - * let's try to make use of that to seed the pseudo-random - * generator. It's better than nothing... */ - - auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; -#endif - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; -} - -void random_bytes(void *p, size_t n) { - uint8_t *q; - int r; - - r = dev_urandom(p, n); - if (r >= 0) - return; - - /* If some idiot made /dev/urandom unavailable to us, he'll - * get a PRNG instead. */ - - initialize_srand(); - - for (q = p; q < (uint8_t*) p + n; q ++) - *q = rand(); -} - _pure_ static int is_temporary_fs(struct statfs *s) { assert(s); diff --git a/src/shared/util.h b/src/shared/util.h index 0f97873d8b..c5e535069c 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -160,10 +160,6 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pu bool hidden_file(const char *filename) _pure_; -int dev_urandom(void *p, size_t n); -void random_bytes(void *p, size_t n); -void initialize_srand(void); - /* For basic lookup tables with strictly enumerated entries */ #define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ scope const char *name##_to_string(type i) { \ @@ -234,6 +230,7 @@ int flush_fd(int fd); int fopen_temporary(const char *path, FILE **_f, char **_temp_path); ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); char* dirname_malloc(const char *path); |