Skip to content

Commit 54081a0

Browse files
committed
Harden security + simplify random
1 parent e460c55 commit 54081a0

18 files changed

+2078
-759
lines changed

fio-stl.h

Lines changed: 777 additions & 363 deletions
Large diffs are not rendered by default.

fio-stl.md

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3078,18 +3078,6 @@ void fio_rand_bytes(void *data_, size_t len)
30783078
Writes `len` random Bytes to the buffer pointed to by `data`. Probably **not**
30793079
cryptographically safe.
30803080

3081-
#### `fio_rand_feed2seed`
3082-
3083-
```c
3084-
static void fio_rand_feed2seed(void *buf_, size_t len);
3085-
```
3086-
3087-
An internal function (accessible from the translation unit) that allows a program to feed random data to the PRNG (`fio_rand64`).
3088-
3089-
The random data will effect the random seed on the next reseeding.
3090-
3091-
Limited to 1023 bytes of data per function call.
3092-
30933081
#### `fio_rand_reseed`
30943082

30953083
```c

fio-stl/000 core.h

Lines changed: 75 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,29 @@ Settings - Memory Function Selectors
12701270
/** Helper for simple `for` loops, where `i` is the variable name to use. */
12711271
#define FIO_FOR(i, count) for (size_t i = 0; i < (count); ++i)
12721272
#endif
1273+
1274+
/* *****************************************************************************
1275+
SIMD Vector Looping Helper
1276+
***************************************************************************** */
1277+
1278+
/* Internal - bytes per constant iterative loop for compiler optimization */
1279+
#define FIO___SIMD_BYTES ((size_t)256U)
1280+
/* Internal - looping macro that separates */
1281+
#define FIO_FOR_UNROLL(itterations, size_of_loop, i, action) \
1282+
do { \
1283+
size_t i = 0; \
1284+
/* handle odd length vectors, not multiples of FIO___LOG2V */ \
1285+
if ((itterations & ((FIO___SIMD_BYTES / size_of_loop) - 1))) \
1286+
for (; i < (itterations & ((FIO___SIMD_BYTES / size_of_loop) - 1)); ++i) \
1287+
action; \
1288+
if (itterations) \
1289+
for (; i < itterations;) \
1290+
for (size_t j__loop__ = 0; \
1291+
j__loop__ < (FIO___SIMD_BYTES / size_of_loop); \
1292+
++j__loop__, ++i) /* dear compiler, please vectorize */ \
1293+
action; \
1294+
} while (0)
1295+
12731296
/* *****************************************************************************
12741297
Memory Copying Primitives (the basis for unaligned memory access for numbers)
12751298
***************************************************************************** */
@@ -2126,6 +2149,12 @@ FIO_SFUNC _Bool fio_ct_is_eq(const void *a_, const void *b_, size_t bytes) {
21262149
return !flag;
21272150
}
21282151

2152+
/** A timing attack resistant memory comparison function. */
2153+
FIO_IFUNC void fio_secure_zero(const void *a_, size_t bytes) {
2154+
volatile uint8_t *buf = (volatile uint8_t *)(a_);
2155+
FIO_FOR_UNROLL(bytes, 1, i, buf[i] = 0);
2156+
}
2157+
21292158
/* *****************************************************************************
21302159
Bit rotation
21312160
***************************************************************************** */
@@ -3468,28 +3497,6 @@ FIO___VMATH_DEF_LARGE_MUL(4096, 2048)
34683497
#undef FIO___VMATH_DEF_LARGE_ADD_SUB
34693498
#undef FIO___VMATH_DEF_LARGE_MUL
34703499

3471-
/* *****************************************************************************
3472-
SIMD Vector Looping Helper
3473-
***************************************************************************** */
3474-
3475-
/* Internal - bytes per constant iterative loop for compiler optimization */
3476-
#define FIO___SIMD_BYTES ((size_t)256U)
3477-
/* Internal - looping macro that separates */
3478-
#define FIO_FOR_UNROLL(itterations, size_of_loop, i, action) \
3479-
do { \
3480-
size_t i = 0; \
3481-
/* handle odd length vectors, not multiples of FIO___LOG2V */ \
3482-
if ((itterations & ((FIO___SIMD_BYTES / size_of_loop) - 1))) \
3483-
for (; i < (itterations & ((FIO___SIMD_BYTES / size_of_loop) - 1)); ++i) \
3484-
action; \
3485-
if (itterations) \
3486-
for (; i < itterations;) \
3487-
for (size_t j__loop__ = 0; \
3488-
j__loop__ < (FIO___SIMD_BYTES / size_of_loop); \
3489-
++j__loop__, ++i) /* dear compiler, please vectorize */ \
3490-
action; \
3491-
} while (0)
3492-
34933500
/* *****************************************************************************
34943501
SIMD Vector Operations
34953502
***************************************************************************** */
@@ -3539,6 +3546,24 @@ SIMD Vector Operations
35393546
Defining a Pseudo-Random Number Generator Function (deterministic / not)
35403547
**************************************************************************** */
35413548

3549+
#if defined(__x86_64__) || defined(__i386__)
3550+
FIO_IFUNC uint64_t fio_cycle_counter(void) {
3551+
uint64_t r = 0;
3552+
uint32_t lo, hi;
3553+
__asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi));
3554+
r = ((uint64_t)hi << 32) | lo;
3555+
return r;
3556+
}
3557+
#elif defined(__aarch64__)
3558+
FIO_IFUNC uint64_t fio_cycle_counter(void) {
3559+
uint64_t r;
3560+
__asm__ volatile("mrs %0, cntvct_el0" : "=r"(r));
3561+
return r;
3562+
}
3563+
#else
3564+
FIO_IFUNC uint64_t fio_cycle_counter(void) { return (uint64_t)0; }
3565+
#endif
3566+
35423567
/**
35433568
* Defines a semi-deterministic Pseudo-Random 128 bit Number Generator function.
35443569
*
@@ -3570,47 +3595,59 @@ Defining a Pseudo-Random Number Generator Function (deterministic / not)
35703595
name##___state[3] = 0x95561f0927ad7ecdULL; \
35713596
name##___state[4] = 0; \
35723597
} \
3573-
FIO_SFUNC void name##___state_reseed(uint64_t *state) { \
3574-
const size_t jitter_samples = 8 | (state[0] & 15); \
3598+
extern void name##_reseed(void) { \
3599+
const size_t jitter_samples = 16 | (name##___state[0] & 15); \
35753600
for (size_t i = 0; i < jitter_samples; ++i) { \
35763601
struct timespec t; \
35773602
clock_gettime(CLOCK_MONOTONIC, &t); \
3578-
uint64_t clk[2]; \
3579-
clk[0] = (uint64_t)((t.tv_sec << 30) + (int64_t)t.tv_nsec); \
3603+
uint64_t clk[2] = {(uint64_t)(uintptr_t)&clk + (uint64_t)(uintptr_t) & \
3604+
(name##_reseed), \
3605+
0}; \
3606+
clk[0] += (uint64_t)((t.tv_sec << 30) + (int64_t)t.tv_nsec); \
35803607
clk[0] = fio_math_mulc64(clk[0], FIO_U64_HASH_PRIME0, clk + 1); \
35813608
clk[1] += FIO_U64_HASH_PRIME0; \
35823609
clk[0] += fio_lrot64(clk[0], 27); \
35833610
clk[0] += fio_lrot64(clk[0], 49); \
35843611
clk[1] += fio_lrot64(clk[1], 27); \
35853612
clk[1] += fio_lrot64(clk[1], 49); \
3586-
state[0] += clk[0]; \
3587-
state[1] += clk[1]; \
3588-
state[2] += clk[0]; \
3589-
state[3] += clk[1]; \
3613+
name##___state[0] += clk[0] + fio_cycle_counter(); \
3614+
name##___state[1] += clk[1] + fio_cycle_counter(); \
3615+
name##___state[2] += clk[0] + fio_cycle_counter(); \
3616+
name##___state[3] += clk[1] + fio_cycle_counter(); \
35903617
} \
35913618
} \
35923619
/** Re-seeds the PNGR so forked processes don't match. */ \
35933620
extern __attribute__((unused)) void name##_on_fork(void *is_null) { \
35943621
(void)is_null; \
3595-
name##___state_reseed(name##___state); \
3622+
name##_reseed(); \
35963623
} \
35973624
/** Returns a 128 bit pseudo-random number. */ \
35983625
extern __attribute__((unused)) fio_u128 name##128(void) { \
35993626
fio_u256 r; \
3600-
if (!((name##___state[4]++) & ((1ULL << reseed_log) - 1)) && \
3627+
if (!(fio_atomic_add(name##___state + 4, 1) & \
3628+
((1ULL << reseed_log) - 1)) && \
36013629
((size_t)(reseed_log - 1) < 63)) \
3602-
name##___state_reseed(name##___state); \
3630+
name##_reseed(); \
36033631
uint64_t s1[4]; \
36043632
{ /* load state to registers and roll, mul, add */ \
3605-
const uint64_t s0[] = {name##___state[0], \
3606-
name##___state[1], \
3607-
name##___state[2], \
3608-
name##___state[3]}; \
3633+
const uint64_t cycles = \
3634+
reseed_log ? fio_cycle_counter() + (uint64_t)(uintptr_t)&cycles \
3635+
: 0xB5ULL; \
3636+
const uint64_t variation = \
3637+
0x4E55788DULL + \
3638+
(reseed_log ? (uint64_t)(uintptr_t)&name##_reseed : 0); \
3639+
const uint64_t s0[] = {(name##___state[0] + cycles), \
3640+
(name##___state[1] + cycles), \
3641+
(name##___state[2] + cycles), \
3642+
(name##___state[3] + cycles)}; \
36093643
const uint64_t mulp[] = {0x37701261ED6C16C7ULL, \
36103644
0x764DBBB75F3B3E0DULL, \
36113645
~(0x37701261ED6C16C7ULL), \
36123646
~(0x764DBBB75F3B3E0DULL)}; \
3613-
const uint64_t addc[] = {name##___state[4], 0, name##___state[4], 0}; \
3647+
const uint64_t addc[] = {name##___state[4], \
3648+
seed_offset + 0x59DD1C23ULL, \
3649+
name##___state[4] + cycles, \
3650+
variation}; \
36143651
for (size_t i = 0; i < 4; ++i) { \
36153652
s1[i] = fio_lrot64(s0[i], 33); \
36163653
s1[i] += addc[i]; \

fio-stl/002 random.h

Lines changed: 56 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,21 @@ Random - API
2626
/** Returns 64 psedo-random bits. Probably not cryptographically safe. */
2727
SFUNC uint64_t fio_rand64(void);
2828

29+
/** Returns 64 psedo-random bits. Probably not cryptographically safe. */
30+
SFUNC fio_u128 fio_rand128(void);
31+
2932
/** Writes `len` bytes of psedo-random bits to the target buffer. */
3033
SFUNC void fio_rand_bytes(void *target, size_t len);
3134

32-
/** Feeds up to 1023 bytes of entropy to the random state. */
33-
IFUNC void fio_rand_feed2seed(void *buf_, size_t len);
35+
/**
36+
* Writes `len` bytes of cryptographically secure random data to `target`.
37+
*
38+
* Uses system CSPRNG: getrandom() on Linux, arc4random_buf() on BSD/macOS,
39+
* or /dev/urandom as fallback. Returns 0 on success, -1 on failure.
40+
*
41+
* IMPORTANT: Use this for security-sensitive operations like key generation.
42+
*/
43+
SFUNC int fio_rand_bytes_secure(void *target, size_t len);
3444

3545
/** Reseeds the random engine using system state (rusage / jitter). */
3646
SFUNC void fio_rand_reseed(void);
@@ -94,6 +104,10 @@ Possibly `extern` Implementation
94104
***************************************************************************** */
95105
#if defined(FIO_EXTERN_COMPLETE) || !defined(FIO_EXTERN)
96106

107+
/* *****************************************************************************
108+
Risky Hash
109+
***************************************************************************** */
110+
97111
/* Computes a facil.io Risky Hash. */
98112
SFUNC uint64_t fio_risky_hash(const void *data_, size_t len, uint64_t seed) {
99113
#if FIO_USE_STABLE_HASH_WHEN_CALLING_RISKY_HASH
@@ -257,125 +271,53 @@ SFUNC void fio_stable_hash128(void *restrict dest,
257271
Random - Implementation
258272
***************************************************************************** */
259273

260-
#if FIO_OS_POSIX || \
261-
(__has_include("sys/resource.h") && __has_include("sys/time.h"))
274+
#if FIO_OS_POSIX || (__has_include("sys/resource.h") && \
275+
__has_include("sys/time.h") && __has_include("fcntl.h"))
276+
#include <fcntl.h>
262277
#include <sys/resource.h>
263278
#include <sys/time.h>
264279
#endif
265280

266-
static volatile uint64_t fio___rand_state[4] = {0}; /* random state */
267-
static volatile size_t fio___rand_counter = 0; /* seed counter */
268-
/* feeds random data to the algorithm through this 256 bit feed. */
269-
static volatile uint64_t fio___rand_buffer[4] = {0x9c65875be1fce7b9ULL,
270-
0x7cc568e838f6a40d,
271-
0x4bb8d885a0fe47d5,
272-
0x95561f0927ad7ecd};
273-
274-
IFUNC void fio_rand_feed2seed(void *buf_, size_t len) {
275-
len &= 1023;
276-
uint8_t *buf = (uint8_t *)buf_;
277-
uint8_t offset = (fio___rand_counter & 3);
278-
uint64_t tmp = 0;
279-
for (size_t i = 0; i < (len >> 3); ++i) {
280-
tmp = fio_buf2u64u(buf);
281-
fio___rand_buffer[(offset++ & 3)] ^= tmp;
282-
buf += 8;
283-
}
284-
if ((len & 7)) {
285-
tmp = 0;
286-
fio_memcpy7x(&tmp, buf, len);
287-
fio___rand_buffer[(offset++ & 3)] ^= tmp;
288-
}
289-
}
290-
291-
SFUNC void fio_rand_reseed(void) {
292-
const size_t jitter_samples = 16 | (fio___rand_state[0] & 15);
293-
#if defined(RUSAGE_SELF)
294-
{
295-
struct rusage rusage;
296-
getrusage(RUSAGE_SELF, &rusage);
297-
fio___rand_state[0] ^=
298-
fio_risky_hash(&rusage, sizeof(rusage), fio___rand_state[0]);
299-
}
300-
#endif
301-
for (size_t i = 0; i < jitter_samples; ++i) {
302-
struct timespec t;
303-
clock_gettime(CLOCK_MONOTONIC, &t);
304-
uint64_t clk =
305-
(uint64_t)((t.tv_sec << 30) + (int64_t)t.tv_nsec) + fio___rand_counter;
306-
fio___rand_state[0] ^= fio_risky_num(clk, fio___rand_state[0] + i);
307-
fio___rand_state[1] ^= fio_risky_num(clk, fio___rand_state[1] + i);
308-
}
309-
{
310-
uint64_t tmp[2];
311-
tmp[0] = fio_risky_num(fio___rand_buffer[0], fio___rand_state[0]) +
312-
fio_risky_num(fio___rand_buffer[1], fio___rand_state[1]);
313-
tmp[1] = fio_risky_num(fio___rand_buffer[2], fio___rand_state[0]) +
314-
fio_risky_num(fio___rand_buffer[3], fio___rand_state[1]);
315-
fio___rand_state[2] ^= tmp[0];
316-
fio___rand_state[3] ^= tmp[1];
317-
}
318-
fio___rand_buffer[0] = fio_lrot64(fio___rand_buffer[0], 31);
319-
fio___rand_buffer[1] = fio_lrot64(fio___rand_buffer[1], 29);
320-
fio___rand_buffer[2] ^= fio___rand_buffer[0];
321-
fio___rand_buffer[3] ^= fio___rand_buffer[1];
322-
fio___rand_counter += jitter_samples;
323-
}
324-
325-
/* tested for randomness using code from: http://xoshiro.di.unimi.it/hwd.php */
326-
SFUNC uint64_t fio_rand64(void) {
327-
/* modeled after xoroshiro128+, by David Blackman and Sebastiano Vigna */
328-
uint64_t r = 0;
329-
if (!((fio___rand_counter++) & (((size_t)1 << 12) - 1))) {
330-
/* re-seed state every 4095 requests / 2^12-1 attempts */
331-
fio_rand_reseed();
332-
}
333-
/* load to registers */
334-
const uint64_t s0[] = {fio___rand_state[0],
335-
fio___rand_state[1],
336-
fio___rand_state[2],
337-
fio___rand_state[3]};
338-
uint64_t s1[4] = {0};
339-
{
340-
const uint64_t mulp[] = {0x37701261ED6C16C7ULL,
341-
0x764DBBB75F3B3E0DULL,
342-
~(0x37701261ED6C16C7ULL),
343-
~(0x764DBBB75F3B3E0DULL)}; /* load to registers */
344-
const uint64_t addc[] = {fio___rand_counter, 0, fio___rand_counter, 0};
345-
for (size_t i = 0; i < 4; ++i) {
346-
s1[i] = fio_lrot64(s0[i], 33);
347-
s1[i] += addc[i];
348-
s1[i] *= mulp[i];
349-
s1[i] += s0[i];
281+
/* The fio_rand64 implementation. */
282+
FIO_DEFINE_RANDOM128_FN(SFUNC, fio_rand, 11, 0)
283+
284+
/**
285+
* Cryptographically secure random bytes using system CSPRNG.
286+
* Returns 0 on success, -1 on failure.
287+
*/
288+
SFUNC int fio_rand_bytes_secure(void *target, size_t len) {
289+
if (!target || !len)
290+
return 0;
291+
292+
#if (defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
293+
defined(__NetBSD__) || defined(__DragonFly__))
294+
/* BSD/macOS: use arc4random_buf (always succeeds, CSPRNG) */
295+
arc4random_buf(target, len);
296+
return 0;
297+
#else
298+
/* Generic POSIX fallback: read from /dev/urandom */
299+
uint8_t *buf = (uint8_t *)target;
300+
int fd = open("/dev/urandom", O_RDONLY);
301+
if (fd < 0)
302+
return -1;
303+
while (len > 0) {
304+
ssize_t got = read(fd, buf, len);
305+
if (got < 0) {
306+
if (errno == EINTR)
307+
continue;
308+
close(fd);
309+
return -1;
350310
}
351-
}
352-
for (size_t i = 0; i < 4; ++i) { /* store to memory */
353-
fio___rand_state[i] = s1[i];
354-
}
355-
{
356-
uint8_t rotc[] = {31, 29, 27, 30};
357-
for (size_t i = 0; i < 4; ++i) {
358-
s1[i] = fio_lrot64(s1[i], rotc[i]);
359-
r += s1[i];
311+
if (got == 0) {
312+
close(fd);
313+
return -1; /* unexpected EOF */
360314
}
315+
buf += got;
316+
len -= (size_t)got;
361317
}
362-
return r;
363-
}
364-
365-
/* copies 64 bits of randomness (8 bytes) repeatedly. */
366-
SFUNC void fio_rand_bytes(void *data_, size_t len) {
367-
if (!data_ || !len)
368-
return;
369-
uint8_t *data = (uint8_t *)data_;
370-
for (unsigned i = 31; i < len; i += 32) {
371-
uint64_t rv[4] = {fio_rand64(), fio_rand64(), fio_rand64(), fio_rand64()};
372-
fio_memcpy32(data, rv);
373-
data += 32;
374-
}
375-
if (len & 31) {
376-
uint64_t rv[4] = {fio_rand64(), fio_rand64(), fio_rand64(), fio_rand64()};
377-
fio_memcpy31x(data, rv, len);
378-
}
318+
close(fd);
319+
return 0;
320+
#endif
379321
}
380322
/* *****************************************************************************
381323
Random - Cleanup

0 commit comments

Comments
 (0)