2 * Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <lttng/constant.h>
10 #include <common/error.h>
11 #include <common/hashtable/utils.h>
12 #include <common/random.h>
13 #include <common/readwrite.h>
14 #include <common/time.h>
20 #ifdef HAVE_SYS_SYSCALL_H
21 #include <sys/syscall.h>
24 /* getrandom is available in Linux >= 3.17. */
25 #if defined(__linux__) && defined(SYS_getrandom) && defined(HAVE_SYS_RANDOM_H)
27 #include <sys/random.h>
29 /* A glibc wrapper is provided only for glibc >= 2.25. */
30 #if defined(HAVE_GETRANDOM)
31 /* Simply use the existing wrapper, passing the non-block flag. */
32 static ssize_t
_call_getrandom_nonblock(char *out_data
, size_t size
)
34 return getrandom(out_data
, size
, GRND_NONBLOCK
);
37 static ssize_t
_call_getrandom_nonblock(char *out_data
, size_t size
)
39 const int grnd_nonblock_flag
= 0x1;
40 long ret
= syscall(SYS_getrandom
, out_data
, size
, grnd_nonblock_flag
);
49 #endif /* defined(HAVE_GETRANDOM) */
51 /* Returns either with a full read or throws. */
52 static int getrandom_nonblock(char *out_data
, size_t size
)
55 * Since GRND_RANDOM is _not_ used, a partial read can only be caused
56 * by a signal interruption. In this case, retry.
62 random_ret
= _call_getrandom_nonblock(out_data
, size
);
63 } while ((random_ret
> 0 && random_ret
!= size
) || (random_ret
== -1 && errno
== EINTR
));
66 PERROR("Failed to get true random data using getrandom(): size=%zu", size
);
72 #else /* defined(__linux__) && defined(SYS_getrandom) && defined(HAVE_SYS_RANDOM_H) */
73 static int getrandom_nonblock(char *out_data
, size_t size
)
75 WARN("getrandom() is not supported by this platform");
78 #endif /* defined(__linux__) && defined(SYS_getrandom) && defined(HAVE_SYS_RANDOM_H) */
80 static int produce_pseudo_random_seed(seed_t
*out_seed
)
83 struct timespec real_time
= {};
84 struct timespec monotonic_time
= {};
85 unsigned long hash_seed
;
86 char hostname
[LTTNG_HOST_NAME_MAX
] = {};
90 ret
= clock_gettime(CLOCK_REALTIME
, &real_time
);
92 PERROR("Failed to read real time while generating pseudo-random seed");
96 ret
= clock_gettime(CLOCK_MONOTONIC
, &monotonic_time
);
98 PERROR("Failed to read monotonic time while generating pseudo-random seed");
102 ret
= gethostname(hostname
, sizeof(hostname
));
104 PERROR("Failed to get host name while generating pseudo-random seed");
108 hash_seed
= (unsigned long) real_time
.tv_nsec
^ (unsigned long) real_time
.tv_sec
^
109 (unsigned long) monotonic_time
.tv_nsec
^
110 (unsigned long) monotonic_time
.tv_sec
;
111 seed
= hash_key_ulong((void *) real_time
.tv_sec
, hash_seed
);
112 seed
^= hash_key_ulong((void *) real_time
.tv_nsec
, hash_seed
);
113 seed
^= hash_key_ulong((void *) monotonic_time
.tv_sec
, hash_seed
);
114 seed
^= hash_key_ulong((void *) monotonic_time
.tv_nsec
, hash_seed
);
117 seed
^= hash_key_ulong((void *) pid
, hash_seed
);
118 seed
^= hash_key_str(hostname
, hash_seed
);
121 *out_seed
= (seed_t
) seed
;
126 static int produce_random_seed_from_urandom(seed_t
*out_seed
)
128 int ret
= 0, read_ret
;
129 const int urandom_raw_fd
= open("/dev/urandom", O_RDONLY
| O_CLOEXEC
);
131 if (urandom_raw_fd
< 0) {
132 PERROR("Failed to open `/dev/urandom`");
137 read_ret
= lttng_read(urandom_raw_fd
, out_seed
, sizeof(*out_seed
));
138 if (read_ret
!= sizeof(*out_seed
)) {
139 PERROR("Failed to read from `/dev/urandom`: size=%zu",
146 if (urandom_raw_fd
>= 0) {
147 if (close(urandom_raw_fd
)) {
148 PERROR("Failed to close `/dev/urandom` file descriptor");
154 int lttng_produce_true_random_seed(seed_t
*out_seed
)
156 return getrandom_nonblock((char *) out_seed
, sizeof(*out_seed
));
159 int lttng_produce_best_effort_random_seed(seed_t
*out_seed
)
163 ret
= lttng_produce_true_random_seed(out_seed
);
167 WARN("Failed to produce a random seed using getrandom(), falling back to pseudo-random device seed generation which will block until its pool is initialized");
170 ret
= produce_random_seed_from_urandom(out_seed
);
174 WARN("Failed to produce a random seed from the urandom device");
177 /* Fallback to seed generation based on time and system configuration. */
178 ret
= produce_pseudo_random_seed(out_seed
);
This page took 0.032884 seconds and 4 git commands to generate.