summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2014-10-31 11:58:25 -0400
committerAnthony G. Basile <blueness@gentoo.org>2014-10-31 11:58:25 -0400
commitea79c9cdf08072304aa6e464629cdd4b96d183a6 (patch)
treecd6fa54f52b44bfce67645440c210e422bc5fa8b
parentfb45281a7a8147e05616a65333094ea744029230 (diff)
util: make use of the new getrandom() syscall if it is available when needing entropy
Doesn't require an fd, and could be a bit faster, so let's make use of it, if it is available. Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
-rw-r--r--configure.ac12
-rw-r--r--src/shared/missing.h15
-rw-r--r--src/shared/util.c25
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)