diff options
-rw-r--r-- | configure.ac | 12 | ||||
-rw-r--r-- | src/shared/missing.h | 15 | ||||
-rw-r--r-- | src/shared/util.c | 25 |
3 files changed, 45 insertions, 7 deletions
diff --git a/configure.ac b/configure.ac index 37472c3d2e..5d95ade543 100644 --- a/configure.ac +++ b/configure.ac @@ -60,20 +60,20 @@ AC_C_INLINE AC_TYPE_MODE_T AC_TYPE_PID_T AC_CHECK_MEMBERS([struct stat.st_rdev]) -AC_CHECK_DECLS([gettid, name_to_handle_at, accept4, mkostemp], [], [], [[#include <sys/types.h> +AC_CHECK_DECLS([getrandom, gettid, name_to_handle_at, accept4, mkostemp], [], [], [[#include <sys/types.h> #include <unistd.h> #include <sys/mount.h> #include <fcntl.h> -#include <sys/socket.h>]]) +#include <sys/socket.h> +#include <linux/random.h>]]) AC_CHECK_SIZEOF(pid_t) AC_CHECK_SIZEOF(uid_t) AC_CHECK_SIZEOF(gid_t) AC_CHECK_SIZEOF(time_t) -AC_CHECK_SIZEOF(rlim_t,,[ - #include <sys/time.h> - #include <sys/resource.h> -]) +AC_CHECK_SIZEOF(rlim_t,,[[ +#include <sys/time.h> +#include <sys/resource.h>]]) # Checks for library functions. AC_FUNC_CHOWN diff --git a/src/shared/missing.h b/src/shared/missing.h index 572e17117a..50f0d56c4a 100644 --- a/src/shared/missing.h +++ b/src/shared/missing.h @@ -42,6 +42,21 @@ /* If RLIMIT_RTTIME is not defined, then we cannot use RLIMIT_NLIMITS as is */ #define _RLIMIT_MAX (RLIMIT_RTTIME+1 > RLIMIT_NLIMITS ? RLIMIT_RTTIME+1 : RLIMIT_NLIMITS) +#ifndef __NR_getrandom +# if defined __x86_64__ +# define __NR_getrandom 278 +# else +# warning "__NR_getrandom unknown for your architecture" +# define __NR_getrandom 0xffffffff +# endif +#endif + +#if !HAVE_DECL_GETRANDOM +static inline int getrandom(void *buffer, size_t count, unsigned flags) { + return syscall(__NR_getrandom, buffer, count, flags); +} +#endif + #ifndef BTRFS_IOCTL_MAGIC #define BTRFS_IOCTL_MAGIC 0x94 #endif diff --git a/src/shared/util.c b/src/shared/util.c index e953363483..2080d77e05 100644 --- a/src/shared/util.c +++ b/src/shared/util.c @@ -685,14 +685,37 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { } int dev_urandom(void *p, size_t n) { - _cleanup_close_ int fd; + static int have_syscall = -1; + int r, fd; ssize_t k; + /* Use the 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, 0); + 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 + 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) |