#include <sys/cdefs.h>
__RCSID("$NetBSD: t_getrandom.c,v 1.5 2023/08/03 03:18:12 rin Exp $");
#include <sys/param.h>
#include <sys/random.h>
#include <atf-c.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static uint8_t buf[65536];
static uint8_t zero24[24];
static void
alarm_handler(int signo)
{
fprintf(stderr, "timeout\n");
}
static void
install_alarm_handler(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof sa);
sa.sa_handler = alarm_handler;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
ATF_CHECK_MSG(sigaction(SIGALRM, &sa, NULL) != -1,
"sigaction(SIGALRM): %s", strerror(errno));
}
ATF_TC(getrandom_default);
ATF_TC_HEAD(getrandom_default, tc)
{
atf_tc_set_md_var(tc, "descr", "getrandom(..., 0)");
atf_tc_set_md_var(tc, "timeout", "2");
}
ATF_TC_BODY(getrandom_default, tc)
{
ssize_t n;
install_alarm_handler();
alarm(1);
memset(buf, 0, sizeof buf);
n = getrandom(buf, sizeof buf, 0);
if (n == -1) {
ATF_CHECK_EQ(errno, EINTR);
} else {
ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
ATF_CHECK((size_t)n <= sizeof buf);
ATF_CHECK(memcmp(buf, zero24, 24) != 0);
ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
}
alarm(0);
}
ATF_TC(getrandom_nonblock);
ATF_TC_HEAD(getrandom_nonblock, tc)
{
atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_NONBLOCK)");
}
ATF_TC_BODY(getrandom_nonblock, tc)
{
ssize_t n;
memset(buf, 0, sizeof buf);
n = getrandom(buf, sizeof buf, GRND_NONBLOCK);
if (n == -1) {
ATF_CHECK_EQ(errno, EAGAIN);
} else {
ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
ATF_CHECK((size_t)n <= sizeof buf);
ATF_CHECK(memcmp(buf, zero24, 24) != 0);
ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
}
}
ATF_TC(getrandom_insecure);
ATF_TC_HEAD(getrandom_insecure, tc)
{
atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_INSECURE)");
}
ATF_TC_BODY(getrandom_insecure, tc)
{
ssize_t n;
memset(buf, 0, sizeof buf);
n = getrandom(buf, sizeof buf, GRND_INSECURE);
ATF_CHECK(n != -1);
ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
ATF_CHECK((size_t)n <= sizeof buf);
ATF_CHECK(memcmp(buf, zero24, 24) != 0);
ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
}
ATF_TC(getrandom_insecure_nonblock);
ATF_TC_HEAD(getrandom_insecure_nonblock, tc)
{
atf_tc_set_md_var(tc, "descr",
"getrandom(..., GRND_INSECURE|GRND_NONBLOCK)");
}
ATF_TC_BODY(getrandom_insecure_nonblock, tc)
{
ssize_t n;
memset(buf, 0, sizeof buf);
n = getrandom(buf, sizeof buf, GRND_INSECURE|GRND_NONBLOCK);
ATF_CHECK(n != -1);
ATF_CHECK(n >= (ssize_t)MIN(256, sizeof buf));
ATF_CHECK((size_t)n <= sizeof buf);
ATF_CHECK(memcmp(buf, zero24, 24) != 0);
ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
}
ATF_TC(getrandom_random);
ATF_TC_HEAD(getrandom_random, tc)
{
atf_tc_set_md_var(tc, "descr", "getrandom(..., GRND_RANDOM)");
atf_tc_set_md_var(tc, "timeout", "2");
}
ATF_TC_BODY(getrandom_random, tc)
{
ssize_t n;
install_alarm_handler();
alarm(1);
memset(buf, 0, sizeof buf);
n = getrandom(buf, sizeof buf, GRND_RANDOM);
if (n == -1) {
ATF_CHECK_EQ(errno, EINTR);
} else {
ATF_CHECK(n != 0);
ATF_CHECK((size_t)n <= sizeof buf);
if ((size_t)n >= 24) {
ATF_CHECK(memcmp(buf, zero24, 24) != 0);
ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
}
}
alarm(0);
}
ATF_TC(getrandom_random_nonblock);
ATF_TC_HEAD(getrandom_random_nonblock, tc)
{
atf_tc_set_md_var(tc, "descr",
"getrandom(..., GRND_RANDOM|GRND_NONBLOCK)");
}
ATF_TC_BODY(getrandom_random_nonblock, tc)
{
ssize_t n;
memset(buf, 0, sizeof buf);
n = getrandom(buf, sizeof buf, GRND_RANDOM|GRND_NONBLOCK);
if (n == -1) {
ATF_CHECK_EQ(errno, EAGAIN);
} else {
ATF_CHECK(n != 0);
ATF_CHECK((size_t)n <= sizeof buf);
if ((size_t)n >= 24) {
ATF_CHECK(memcmp(buf, zero24, 24) != 0);
ATF_CHECK(memcmp(buf + n - 24, zero24, 24) != 0);
}
}
}
ATF_TC(getrandom_random_insecure);
ATF_TC_HEAD(getrandom_random_insecure, tc)
{
atf_tc_set_md_var(tc, "descr",
"getrandom(..., GRND_RANDOM|GRND_INSECURE)");
}
ATF_TC_BODY(getrandom_random_insecure, tc)
{
ssize_t n;
n = getrandom(buf, sizeof buf, GRND_RANDOM|GRND_INSECURE);
ATF_CHECK_EQ(n, -1);
ATF_CHECK_EQ(errno, EINVAL);
}
ATF_TC(getrandom_random_insecure_nonblock);
ATF_TC_HEAD(getrandom_random_insecure_nonblock, tc)
{
atf_tc_set_md_var(tc, "descr",
"getrandom(..., GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK)");
}
ATF_TC_BODY(getrandom_random_insecure_nonblock, tc)
{
ssize_t n;
n = getrandom(buf, sizeof buf,
GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK);
ATF_CHECK_EQ(n, -1);
ATF_CHECK_EQ(errno, EINVAL);
}
ATF_TC(getrandom_invalid);
ATF_TC_HEAD(getrandom_invalid, tc)
{
atf_tc_set_md_var(tc, "descr", "getrandom(..., <invalid>)");
}
ATF_TC_BODY(getrandom_invalid, tc)
{
ssize_t n;
__CTASSERT(~(GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK));
n = getrandom(buf, sizeof buf,
~(GRND_RANDOM|GRND_INSECURE|GRND_NONBLOCK));
ATF_CHECK_EQ(n, -1);
ATF_CHECK_EQ(errno, EINVAL);
}
ATF_TC(getrandom_fault);
ATF_TC_HEAD(getrandom_fault, tc)
{
atf_tc_set_md_var(tc, "descr", "getrandom(NULL, ...)");
}
ATF_TC_BODY(getrandom_fault, tc)
{
ssize_t n;
n = getrandom(NULL, sizeof buf, GRND_INSECURE|GRND_NONBLOCK);
ATF_CHECK_EQ(n, -1);
ATF_CHECK_EQ(errno, EFAULT);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getrandom_default);
ATF_TP_ADD_TC(tp, getrandom_nonblock);
ATF_TP_ADD_TC(tp, getrandom_insecure);
ATF_TP_ADD_TC(tp, getrandom_insecure_nonblock);
ATF_TP_ADD_TC(tp, getrandom_random);
ATF_TP_ADD_TC(tp, getrandom_random_nonblock);
ATF_TP_ADD_TC(tp, getrandom_random_insecure);
ATF_TP_ADD_TC(tp, getrandom_random_insecure_nonblock);
ATF_TP_ADD_TC(tp, getrandom_invalid);
ATF_TP_ADD_TC(tp, getrandom_fault);
return atf_no_error();
}