Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions mcpp.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
namespace = "mcpplibs"
name = "openkal-linux"
version = "0.5.3"
version = "0.5.4"
description = "The reference implementation of openkal for Linux, written on the kernel's own system-call interface so that it can be placed beneath a C library as well as above one."
license = "Apache-2.0"

Expand All @@ -18,7 +18,7 @@ authors = ["mcpplibs"]
repo = "https://github.com/mcpplibs/openkal-linux"

[dependencies]
openkal = "0.6.0"
openkal = "0.7.0"

# The package contributes definitions and no modules. The interface it
# implements is declared by the specification package, which this package
Expand Down
55 changes: 55 additions & 0 deletions src/random.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// openkal.random on Linux --- getrandom(2).
//
// ⭐ THE KERNEL'S OWN CALL AND NOT `/dev/urandom`. The device would need a
// descriptor, which needs a path, which a capability-oriented filesystem
// deliberately does not hand out; and a program early enough in its life not to
// have a filesystem yet still has this call. `getrandom` is the interface the
// kernel offers for exactly this question.
#include "sys.h"
#include <openkal/random.h>

namespace {

// ⚠️ `GRND_NONBLOCK` IS NOT SET, AND THAT IS WHAT `BLOCKING` REPORTS.
//
// Without it the call waits until the pool has been initialised, which on a
// machine seconds into its first boot can be a real wait. Setting it instead
// would turn that wait into a short read — a partial success this interface
// does not have — so the wait is kept and named in the capability word.
constexpr okl_long flags_blocking = 0;

} // namespace

extern "C" int kal_random_fill(void* out, kal_uintptr len) {
if (len == 0) return kal_ok;
if (out == nullptr) return kal_err_invalid;

auto* p = static_cast<unsigned char*>(out);
kal_uintptr filled = 0;
while (filled < len) {
const okl_long r = okl::sys(okl::nr_getrandom,
reinterpret_cast<okl_long>(p + filled),
static_cast<okl_long>(len - filled),
flags_blocking);
if (r < 0) {
// ⚠️ THE BUFFER IS NOT RESTORED, AND THE CONTRACT SAYS IT NEED NOT
// BE: a failed fill leaves the buffer unspecified rather than
// unchanged. Restoring it would oblige this function to keep a copy
// of what it was handed, which is a cost every successful call
// would pay for the benefit of the failing one.
if (r == -4 /* EINTR */) continue;
if (r == -11 /* EAGAIN */) return kal_err_again;
return kal_err_io;
}
// A short return is the kernel's, not this interface's: `getrandom`
// caps a single call at 32 MiB. Looping is what turns it into the
// all-or-nothing this interface promises.
filled += static_cast<kal_uintptr>(r);
}
return kal_ok;
}

// Blocking, because GRND_NONBLOCK is not set above. Not hardware: the kernel's
// pool is what this reads, and whether the pool was seeded from a hardware
// source is not something this backend can observe.
extern "C" const kal_uintptr kal_random_props = KAL_RANDOM_PROP_BLOCKING;
2 changes: 2 additions & 0 deletions src/sys.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ enum : okl_long {
nr_openat = 257, nr_mkdirat = 258, nr_newfstatat = 262, nr_unlinkat = 263,
nr_renameat = 264, nr_readlinkat = 267, nr_dup3 = 292, nr_execveat = 322,
nr_dup2 = 33, nr_utimensat = 280,
nr_getrandom = 318,
};

#elif defined(__aarch64__)
Expand Down Expand Up @@ -170,6 +171,7 @@ enum : okl_long {
nr_clone = 220, nr_execve = 221, nr_wait4 = 260, nr_renameat = 38,
nr_dup3 = 24, nr_execveat = 281, nr_dup2 = -1,
nr_arch_prctl = -1, nr_utimensat = 88,
nr_getrandom = 278,
};

#else
Expand Down
Loading