From 59cfb5a84fd94fe72c4a19531bf014564a8b31f2 Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Fri, 10 Aug 2018 09:42:35 -0400 Subject: Cleanup code, add TEST_WRAPPER support. --- Makefile.in | 6 ++-- random-seed.c | 109 ++++++++++++++++++++++++++++++++-------------------------- util.c | 30 +++++++++++++++- util.h | 11 ++---- 4 files changed, 95 insertions(+), 61 deletions(-) diff --git a/Makefile.in b/Makefile.in index d3e3430..f52121e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -49,8 +49,8 @@ endif test: $(TEST_FILE) $(TEST_FILE): random-seed - ./random-seed save $(TEST_FILE) - ./random-seed load $(TEST_FILE) || [ $$? = 15 ] + $(TEST_WRAPPER) ./random-seed save $(TEST_FILE) + $(TEST_WRAPPER) ./random-seed load $(TEST_FILE) || [ $$? = 15 ] clean: $(RM) random-seed $(OBJ) $(DEP) $(TEST_FILE) @@ -58,5 +58,5 @@ clean: distclean: clean $(RM) -r aclocal.m4 autom4te.cache config.h config.h.in 'config.h.in~' config.log config.status configure Makefile -.PHONY: all install test clean +.PHONY: all install test clean random-seed.test .INTERMEDIATE: $(TEST_FILE) diff --git a/random-seed.c b/random-seed.c index 6ed971b..53ad8e3 100644 --- a/random-seed.c +++ b/random-seed.c @@ -213,7 +213,7 @@ static bool load(FILE *seed_file) { } } - char *nul = memchr(line, '\0', line_length); + char *nul = memchr(line, '\0', (size_t)line_length); if (nul) { fprintf(stderr, "error parsing seed file: encountered NUL byte in commands line %zu char %zu\n", linenum, nul - line + 1); credit_entropy = false; @@ -272,10 +272,11 @@ static bool load(FILE *seed_file) { } static bool get_rand_pool(unsigned char *buf) { - size_t rand_bits_gotten = 0; - while (rand_bits_gotten < RAND_POOL_SIZE) { - long this_rand_bits_gotten = random_get(buf + rand_bits_gotten, RAND_POOL_SIZE - rand_bits_gotten, 0); - if (this_rand_bits_gotten < 0) { + size_t rand_bytes_gotten = 0; + + do { + long this_rand_bytes_gotten = random_get(buf + rand_bytes_gotten, RAND_POOL_SIZE - rand_bytes_gotten, 0); + if (this_rand_bytes_gotten == -1) { switch (errno) { case EAGAIN: continue; case EINTR: return false; @@ -284,9 +285,10 @@ static bool get_rand_pool(unsigned char *buf) { exit(1); } } else { - rand_bits_gotten += (size_t)this_rand_bits_gotten; + rand_bytes_gotten += (size_t)this_rand_bytes_gotten; } - } + } while (rand_bytes_gotten < RAND_POOL_SIZE); + return true; } @@ -301,61 +303,64 @@ static bool save(const char *seed_path, unsigned char *random_buf) { assert(seed_path); bool rv = false; - char *seed_path_tmp = NULL; - char *seed_name_new = NULL; - unsigned char my_random_buf[RAND_POOL_SIZE]; - if (!random_buf) { - if (!get_rand_pool(my_random_buf)) + unsigned char *random_ptr; + if (random_buf) { + random_ptr = random_buf; + } else { + random_ptr = alloca(RAND_POOL_SIZE); + if (!get_rand_pool(random_ptr)) return false; - random_buf = my_random_buf; } unsigned char machine_id_digest[HASH_LEN]; - if (!get_machine_id_hash(random_buf, machine_id_digest)) { + if (!get_machine_id_hash(random_ptr, machine_id_digest)) { fputs("cannot obtain machine id, aborting save\n", stderr); return false; } - char machine_id_hash[HASH_LEN*2+1]; - memset(machine_id_hash, 0, HASH_LEN*2); - mem2hex(machine_id_hash, machine_id_digest, HASH_LEN); - machine_id_hash[sizeof(machine_id_hash)-1] = '\0'; + char machine_id_hash[HASH_STR_LEN]; + mem2hex(machine_id_hash, machine_id_digest, HASH_STR_LEN); + machine_id_hash[HASH_STR_LEN-1] = '\0'; int seed_dir_fd = -1; int seed_fd = -1; FILE *seed_file = NULL; - seed_path_tmp = strdup(seed_path); + char *seed_path_tmp = strdup(seed_path); + const char *seed_dir, *seed_name; + char *seed_path_last_slash = strrchr(seed_path_tmp, '/'); + if (seed_path_last_slash) { + *seed_path_last_slash = '\0'; + seed_dir = seed_path_tmp; + seed_name = seed_path_last_slash + 1; + } else { + free(seed_path_tmp); + seed_path_tmp = NULL; + seed_dir = "."; + seed_name = seed_path; + } + char *seed_name_new = NULL; + + if (asprintf(&seed_name_new, ".%s.new", seed_name) == -1) { + fputs("out of memory\n", stderr); + goto out; + } - seed_dir_fd = open(mydirname(seed_path_tmp), O_RDONLY | O_DIRECTORY); + seed_dir_fd = open(seed_dir, O_RDONLY | O_DIRECTORY); if (seed_dir_fd == -1) { perror("error opening seed directory"); goto out; } unsigned char fs_id_digest[HASH_LEN]; - if (!get_fs_id_hash(random_buf, fs_id_digest, seed_dir_fd)) { + if (!get_fs_id_hash(random_ptr, fs_id_digest, seed_dir_fd)) { fputs("cannot obtain machine id, aborting save\n", stderr); - free(seed_path_tmp); - return false; + goto out; } char fs_id_hash[HASH_LEN*2+1]; mem2hex(fs_id_hash, fs_id_digest, HASH_LEN); fs_id_hash[sizeof(fs_id_hash)-1] = '\0'; - strcpy(seed_path_tmp, seed_path); - char *seed_name = mybasename(seed_path_tmp); - size_t seed_name_new_len = strlen(seed_name) + 6; - seed_name_new = malloc(seed_name_new_len); - if (!seed_name_new) { - fputs("out of memory\n", stderr); - free(seed_path_tmp); - return false; - } - assert(seed_name_new_len < INT_MAX); - if ((size_t)snprintf(seed_name_new, seed_name_new_len, ".%s.new", seed_name) >= seed_name_new_len) - abort(); - seed_fd = openat(seed_dir_fd, seed_name_new, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (seed_fd == -1) { perror("error opening new seed file"); @@ -367,7 +372,7 @@ static bool save(const char *seed_path, unsigned char *random_buf) { goto err; } - if (fwrite(random_buf, 1, RAND_POOL_SIZE, seed_file) != RAND_POOL_SIZE + if (fwrite(random_ptr, 1, RAND_POOL_SIZE, seed_file) != RAND_POOL_SIZE || fputs(MAGIC, seed_file) == EOF || fputs("machine-id ", seed_file) == EOF || fputs(machine_id_hash, seed_file) == EOF @@ -468,17 +473,22 @@ noreturn static void run(const char *mode, const char *seed_path) { if (refresh_seed) { unsigned char random_buf[RAND_POOL_SIZE]; unsigned char *random_ptr = random_buf; - if (random_get(random_buf, sizeof(random_buf), GRND_NONBLOCK) == -1) { - if (errno != EAGAIN) { - perror("getrandom"); - exit(1); - } - daemon(0, 1); - close(0); - close(1); - random_ptr = NULL; + switch (random_get(random_buf, RAND_POOL_SIZE, GRND_NONBLOCK)) { + case RAND_POOL_SIZE: + goto save; + case -1: + if (errno != EAGAIN) { + perror("getrandom"); + exit(1); + } } - if (!save(seed_path, random_ptr)) + if (daemon(0, 1) == -1) { + perror("error daemonizing, continuing without"); + } + close(0); + close(1); + random_ptr = NULL; +save: if (!save(seed_path, random_ptr)) exit_status = 1; } exit(exit_status); @@ -505,7 +515,10 @@ noreturn static void run(const char *mode, const char *seed_path) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - daemon(seed_path[0] != '/', 1); + if (daemon(seed_path[0] != '/', 1) == -1) { + perror("error daemonizing"); + exit(1); + } close(0); close(1); // don't close stderr because we log there diff --git a/util.c b/util.c index f0d1fda..a5eb220 100644 --- a/util.c +++ b/util.c @@ -68,7 +68,7 @@ void hash(const unsigned char salt[static SALT_LEN], unsigned char *out, const v sha256_final(&ctx, out); } -void print_hash(const unsigned char digest[static HASH_LEN]) { +static void print_hash(const unsigned char digest[static HASH_LEN]) { #ifdef DEBUG char hash[HASH_LEN*2+1]; mem2hex(hash, digest, HASH_LEN); @@ -93,3 +93,31 @@ bool hash_match(const unsigned char digest[static HASH_LEN], const char *arg) { #endif return !memcmp(digest, theirdigest, HASH_LEN); } + +ssize_t random_get(void *buf, size_t buflen, unsigned int flags) { + memset(buf, 0, buflen); + + long rv = syscall(SYS_getrandom, buf, buflen, flags); + if (rv == -1) { + if (errno == ENOSYS) { + fputs("getrandom returned ENOSYS. random-seed requires Linux 3.17\n", stderr); + exit(1); + } + } else { + bool all_zero = true; + if (buflen > 32) { + for (size_t i = 0; i < buflen; i++) { + if (((unsigned char *)buf)[i] != 0) { + all_zero = false; + break; + } + } + } + if (all_zero) { + fputs("getrandom returned all zeros, probably broken\n", stderr); + exit(1); + } + } + + return rv; +} diff --git a/util.h b/util.h index 5c4a604..9cd2bd4 100644 --- a/util.h +++ b/util.h @@ -17,6 +17,7 @@ #define RAND_POOL_SIZE 512 /* SHA-256 */ #define HASH_LEN 32 +#define HASH_STR_LEN 65 /* The salt is the random data */ #define SALT_LEN RAND_POOL_SIZE @@ -24,15 +25,7 @@ static inline bool streq(const char *s1, const char *s2) { return !strcmp(s1, s2); } -static inline ssize_t random_get(void *buf, size_t buflen, unsigned int flags) { - long rv = syscall(SYS_getrandom, buf, buflen, flags); - if (rv == -1 && errno == ENOSYS) { - fputs("getrandom returned ENOSYS. random-seed requires Linux 3.17", stderr); - exit(1); - } - return rv; -} - +ssize_t random_get(void *buf, size_t buflen, unsigned int flags); size_t hex2mem(unsigned char *dest, size_t size, const char *src); void mem2hex(char *dest, const void *src, size_t size); void hash(const unsigned char salt[static SALT_LEN], unsigned char *out, const void *in, size_t size); -- cgit v1.2.3-70-g09d2