From bdf297518db7213e821daca24369f4dd3a810683 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 25 Aug 2026 04:27:41 +0800 Subject: [PATCH 1/3] feat: openkal.random on getrandom(2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⭐ **内核自己的调用,而不是 `/dev/urandom`。** 那个设备要一个描述符, 描述符要一条路径,而能力型文件系统刻意不发绝对路径 —— 那是模型在工作。 并且一个还没有文件系统的程序仍然有这个调用。 两张系统调用表各加一条:x86_64 = 318,aarch64 = 278。 ⚠️ **不设 `GRND_NONBLOCK`,而这正是 `BLOCKING` 那一位所报的。** 不设它, 调用会等到熵池播种完成 —— 在一台刚启动几秒的机器上是真的等待。设它则把 等待变成短读,而本接口没有「部分成功」这个状态,所以等待被保留并在能力字里 被命名。 ⚠️ 失败时缓冲区不恢复,而契约就是这么说的:失败的填充留下未指定内容而非 原内容。恢复它会迫使本函数保留一份入参副本 —— 每次成功的调用都为那一次 失败付这个代价。 短返回是内核的(`getrandom` 单次上限 32 MiB),循环是把它变成本接口承诺的 「全有或全无」。 `props = BLOCKING`,不含 `HARDWARE`:读的是内核的池,而池是否由硬件源播种 不是这个后端能观察的。 实测:两次 fill 返回不同字节,props = 1。 --- src/random.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/sys.h | 2 ++ 2 files changed, 57 insertions(+) create mode 100644 src/random.cpp diff --git a/src/random.cpp b/src/random.cpp new file mode 100644 index 0000000..70fc828 --- /dev/null +++ b/src/random.cpp @@ -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 + +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(out); + kal_uintptr filled = 0; + while (filled < len) { + const okl_long r = okl::sys(okl::nr_getrandom, + reinterpret_cast(p + filled), + static_cast(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(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; diff --git a/src/sys.h b/src/sys.h index 6352116..82975e3 100644 --- a/src/sys.h +++ b/src/sys.h @@ -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__) @@ -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 From 5dfab29cead66471c39e7d1ab825cdc0bb70c0f6 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 25 Aug 2026 04:48:57 +0800 Subject: [PATCH 2/3] deps: follow openkal 0.7.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 规范新增 `openkal.random`,版本升到 0.7.0。CI 的版本同步门要求实现与规范 同步声明 —— 它的诊断说得很准:「Nothing is wrong with either; they are not in step.」 --- mcpp.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpp.toml b/mcpp.toml index 927690d..c94a11b 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -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 From c701ea93fe8e8d6d869a465e0a5db3d09f910dd7 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Tue, 25 Aug 2026 05:21:26 +0800 Subject: [PATCH 3/3] release: 0.5.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The branch carried 0.5.3, which is the version on `main` and the version already in the index. Following openkal 0.7.0 changes what this package declares, and on two of these repositories it also adds an interface, so the content behind that number is no longer the content published under it. openkal takes a minor bump for a new interface and an implementation following it takes a patch bump --- the shape of 0.5.2 → 0.6.0 with 0.5.2 → 0.5.3 beneath it. --- mcpp.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcpp.toml b/mcpp.toml index c94a11b..f4583c7 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -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"