Skip to content

Commit e328ba1

Browse files
authored
feat: openkal.random on getrandom(2) (#6)
* feat: openkal.random on getrandom(2) ⭐ **内核自己的调用,而不是 `/dev/urandom`。** 那个设备要一个描述符, 描述符要一条路径,而能力型文件系统刻意不发绝对路径 —— 那是模型在工作。 并且一个还没有文件系统的程序仍然有这个调用。 两张系统调用表各加一条:x86_64 = 318,aarch64 = 278。 ⚠️ **不设 `GRND_NONBLOCK`,而这正是 `BLOCKING` 那一位所报的。** 不设它, 调用会等到熵池播种完成 —— 在一台刚启动几秒的机器上是真的等待。设它则把 等待变成短读,而本接口没有「部分成功」这个状态,所以等待被保留并在能力字里 被命名。 ⚠️ 失败时缓冲区不恢复,而契约就是这么说的:失败的填充留下未指定内容而非 原内容。恢复它会迫使本函数保留一份入参副本 —— 每次成功的调用都为那一次 失败付这个代价。 短返回是内核的(`getrandom` 单次上限 32 MiB),循环是把它变成本接口承诺的 「全有或全无」。 `props = BLOCKING`,不含 `HARDWARE`:读的是内核的池,而池是否由硬件源播种 不是这个后端能观察的。 实测:两次 fill 返回不同字节,props = 1。 * deps: follow openkal 0.7.0 规范新增 `openkal.random`,版本升到 0.7.0。CI 的版本同步门要求实现与规范 同步声明 —— 它的诊断说得很准:「Nothing is wrong with either; they are not in step.」 * release: 0.5.4 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.
1 parent a0a92ea commit e328ba1

3 files changed

Lines changed: 59 additions & 2 deletions

File tree

mcpp.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
namespace = "mcpplibs"
33
name = "openkal-linux"
4-
version = "0.5.3"
4+
version = "0.5.4"
55
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."
66
license = "Apache-2.0"
77

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

2020
[dependencies]
21-
openkal = "0.6.0"
21+
openkal = "0.7.0"
2222

2323
# The package contributes definitions and no modules. The interface it
2424
# implements is declared by the specification package, which this package

src/random.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// openkal.random on Linux --- getrandom(2).
2+
//
3+
// ⭐ THE KERNEL'S OWN CALL AND NOT `/dev/urandom`. The device would need a
4+
// descriptor, which needs a path, which a capability-oriented filesystem
5+
// deliberately does not hand out; and a program early enough in its life not to
6+
// have a filesystem yet still has this call. `getrandom` is the interface the
7+
// kernel offers for exactly this question.
8+
#include "sys.h"
9+
#include <openkal/random.h>
10+
11+
namespace {
12+
13+
// ⚠️ `GRND_NONBLOCK` IS NOT SET, AND THAT IS WHAT `BLOCKING` REPORTS.
14+
//
15+
// Without it the call waits until the pool has been initialised, which on a
16+
// machine seconds into its first boot can be a real wait. Setting it instead
17+
// would turn that wait into a short read — a partial success this interface
18+
// does not have — so the wait is kept and named in the capability word.
19+
constexpr okl_long flags_blocking = 0;
20+
21+
} // namespace
22+
23+
extern "C" int kal_random_fill(void* out, kal_uintptr len) {
24+
if (len == 0) return kal_ok;
25+
if (out == nullptr) return kal_err_invalid;
26+
27+
auto* p = static_cast<unsigned char*>(out);
28+
kal_uintptr filled = 0;
29+
while (filled < len) {
30+
const okl_long r = okl::sys(okl::nr_getrandom,
31+
reinterpret_cast<okl_long>(p + filled),
32+
static_cast<okl_long>(len - filled),
33+
flags_blocking);
34+
if (r < 0) {
35+
// ⚠️ THE BUFFER IS NOT RESTORED, AND THE CONTRACT SAYS IT NEED NOT
36+
// BE: a failed fill leaves the buffer unspecified rather than
37+
// unchanged. Restoring it would oblige this function to keep a copy
38+
// of what it was handed, which is a cost every successful call
39+
// would pay for the benefit of the failing one.
40+
if (r == -4 /* EINTR */) continue;
41+
if (r == -11 /* EAGAIN */) return kal_err_again;
42+
return kal_err_io;
43+
}
44+
// A short return is the kernel's, not this interface's: `getrandom`
45+
// caps a single call at 32 MiB. Looping is what turns it into the
46+
// all-or-nothing this interface promises.
47+
filled += static_cast<kal_uintptr>(r);
48+
}
49+
return kal_ok;
50+
}
51+
52+
// Blocking, because GRND_NONBLOCK is not set above. Not hardware: the kernel's
53+
// pool is what this reads, and whether the pool was seeded from a hardware
54+
// source is not something this backend can observe.
55+
extern "C" const kal_uintptr kal_random_props = KAL_RANDOM_PROP_BLOCKING;

src/sys.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ enum : okl_long {
9797
nr_openat = 257, nr_mkdirat = 258, nr_newfstatat = 262, nr_unlinkat = 263,
9898
nr_renameat = 264, nr_readlinkat = 267, nr_dup3 = 292, nr_execveat = 322,
9999
nr_dup2 = 33, nr_utimensat = 280,
100+
nr_getrandom = 318,
100101
};
101102

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

175177
#else

0 commit comments

Comments
 (0)