mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-25 13:29:03 +02:00
only use the getrandom syscall on linux, or arc4random. the /dev/urandom fallback is removed, and we use the syscall; failure is almost certainly unlikely, but if it fails, we abort. this provides therefore the same guarantee as bsd arc4random, since it will never return under fault conditions. it will only ever return success, or abort. nobody should be using /dev/urandom in 2026. Signed-off-by: Leah Rowe <leah@libreboot.org>
121 lines
2.4 KiB
C
121 lines
2.4 KiB
C
/* SPDX-License-Identifier: MIT
|
|
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
|
|
*
|
|
* Random number generation
|
|
*/
|
|
|
|
#ifndef RAND_H
|
|
#define RAND_H
|
|
|
|
#ifdef __OpenBSD__
|
|
#include <sys/param.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
#if !((defined(__OpenBSD__) && (OpenBSD) >= 201) || \
|
|
defined(__FreeBSD__) || \
|
|
defined(__NetBSD__) || defined(__APPLE__))
|
|
#include <fcntl.h> /* if not arc4random: /dev/urandom */
|
|
#endif
|
|
#include <limits.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "../include/common.h"
|
|
|
|
/* Random numbers
|
|
*/
|
|
|
|
/* when calling this: save errno
|
|
* first, then set errno to zero.
|
|
* on error, this function will
|
|
* set errno and possibly return
|
|
*
|
|
* rlong also preserves errno
|
|
* and leaves it unchanged on
|
|
* success, so if you do it
|
|
* right, you can detect error.
|
|
* this is because it uses
|
|
* /dev/urandom which can err.
|
|
* ditto getrandom (EINTR),
|
|
* theoretically.
|
|
*/
|
|
|
|
/* for the linux version: we use only the
|
|
* syscall, because we cannot trust /dev/urandom
|
|
* to be as robust, and some libc implementations
|
|
* may default to /dev/urandom under fault conditions.
|
|
*
|
|
* for general high reliability, we must abort on
|
|
* failure. in practise, it will likely never fail.
|
|
* the arc4random call on bsd never returns error.
|
|
*/
|
|
|
|
size_t
|
|
rlong(void)
|
|
{
|
|
size_t rval;
|
|
int saved_errno = errno;
|
|
|
|
#if (defined(__OpenBSD__) && (OpenBSD) >= 201) || \
|
|
defined(__FreeBSD__) || \
|
|
defined(__NetBSD__) || defined(__APPLE__)
|
|
|
|
arc4random_buf(&rval, sizeof(size_t));
|
|
goto out;
|
|
|
|
#elif defined(__linux__)
|
|
|
|
size_t off = 0;
|
|
size_t len = sizeof(rval);
|
|
|
|
ssize_t rc;
|
|
|
|
if (!len)
|
|
goto err;
|
|
|
|
while (off < len) {
|
|
|
|
rc = (ssize_t)syscall(SYS_getrandom,
|
|
(char *)&rval + off, len - off, 0);
|
|
|
|
if (rc < 0) {
|
|
if (errno == EINTR || errno == EAGAIN)
|
|
continue;
|
|
|
|
goto err; /* possibly unsupported by kernel */
|
|
}
|
|
|
|
if (rval == 0)
|
|
goto err;
|
|
|
|
off += (size_t)rc;
|
|
}
|
|
|
|
goto out;
|
|
|
|
return rval;
|
|
err:
|
|
/*
|
|
* getrandom can return with error, butt arc4random
|
|
* doesn't. generally, getrandom will be reliably,
|
|
* but we of course have to maintain parity with
|
|
* BSD. So a rand failure is to be interpreted as
|
|
* a major systems failure, and we act accordingly.
|
|
*/
|
|
err_no_cleanup(1, ECANCELED, "Randomisation failure");
|
|
exit(1);
|
|
|
|
#else
|
|
#error Unsupported operating system (possibly unsecure randomisation)
|
|
#endif
|
|
|
|
out:
|
|
errno = saved_errno;
|
|
return rval;
|
|
}
|
|
#endif
|