diff --git a/.github/workflows/numbers.yml b/.github/workflows/numbers.yml index 6464670..829296c 100644 --- a/.github/workflows/numbers.yml +++ b/.github/workflows/numbers.yml @@ -42,6 +42,7 @@ jobs: ftruncate truncate mmap lseek __getcwd getcwd \ stat stat64 fstat fstat64 lstat lstat64 \ fstatat fstatat64 getdirentries getdirentries64 \ + getentropy \ bsdthread_terminate thread_selfid \ open openat openat_nocancel renameat faccessat unlinkat \ readlinkat mkdirat rmdir unlink mkdir rename access \ diff --git a/mcpp.toml b/mcpp.toml index d917c82..2d02cb4 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal-macos" -version = "0.3.3" +version = "0.3.4" description = "An implementation of openkal for macOS, written on the kernel's own calls. Its purpose is as much to test the specification as to be used." license = "Apache-2.0" @@ -18,7 +18,7 @@ authors = ["mcpplibs"] repo = "https://github.com/mcpplibs/openkal-macos" [dependencies] -openkal = "0.6.0" +openkal = "0.7.0" [build] # The flags are attached to this package's own sources rather than to the whole diff --git a/src/random.cpp b/src/random.cpp new file mode 100644 index 0000000..2532d74 --- /dev/null +++ b/src/random.cpp @@ -0,0 +1,45 @@ +// openkal.random on this system --- getentropy(2). +// +// ⭐ THE NUMBER CAME FROM THE MACHINE, NOT FROM MEMORY. `.github/workflows/ +// numbers.yml` reads every number this implementation uses out of the SDK's own +// `sys/syscall.h`, on both runners this repository targets, and both answered +// `SYS_getentropy 500`. That workflow exists because a number recalled rather +// than read is a number that is right until the day it is not. +// +// ⚠️ AND NOT `arc4random_buf`, WHICH IS WHAT libc++ WOULD REACH FOR HERE. +// That name is in libSystem, and reaching into libSystem is what this backend +// exists to avoid: it issues this kernel's calls directly, as the note in +// `sys.h` records. `getentropy` is the call underneath. +// +// ⚠️ THE KERNEL CAPS A CALL AT 256 BYTES. That is this system's limit and not +// this interface's, so the loop below turns it into the all-or-nothing +// `kal_random_fill` promises. +#include "sys.h" +#include + +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 kal_uintptr chunk = (len - filled) > 256 ? 256 : (len - filled); + const okm_long r = okm::sys(okm::nr_getentropy, + reinterpret_cast(p + filled), + static_cast(chunk), 0, 0); + if (r < 0) { + // ⚠️ The buffer is not restored, and the contract says it need not + // be: a failed fill leaves it unspecified rather than unchanged. + if (r == -4 /* EINTR */) continue; + return kal_err_io; + } + filled += chunk; + } + return kal_ok; +} + +// Neither blocking nor hardware. This kernel's generator is seeded before a +// process runs, so there is no wait to report; and whether the seed came from a +// hardware source is not something this backend can observe. +extern "C" const kal_uintptr kal_random_props = 0; diff --git a/src/sys.h b/src/sys.h index 4cf565a..da94894 100644 --- a/src/sys.h +++ b/src/sys.h @@ -134,6 +134,7 @@ enum : okm_long { nr_dup2 = 90, nr_fsync = 95, nr_gettimeofday = 116, nr_readv = 120, nr_writev = 121, nr_ftruncate = 201, nr_utimes = 138, nr_futimes = 139, + nr_getentropy = 500, // This kernel has no call that reports the working directory --- the // measurement is in .github/workflows/numbers.yml, where SYS___getcwd is // absent from the system's own table. What it has instead is an enquiry