diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-12-17 20:03:41 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-12-18 12:22:46 -0700 |
| commit | 013efaf13987acfa6b41d40f07900c1ea77f5bda (patch) | |
| tree | 14325d114eb66312b3545f3a897142400dfb7c16 /lib/std/start.zig | |
| parent | ce65533985caa9e2da567948e36d7d4ba0185005 (diff) | |
| download | zig-013efaf13987acfa6b41d40f07900c1ea77f5bda.tar.gz zig-013efaf13987acfa6b41d40f07900c1ea77f5bda.zip | |
std: introduce a thread-local CSPRNG for general use
std.crypto.random
* cross platform, even freestanding
* can't fail. on initialization for some systems requires calling
os.getrandom(), in which case there are rare but theoretically
possible errors. The code panics in these cases, however the
application may choose to override the default seed function and then
handle the failure another way.
* thread-safe
* supports the full Random interface
* cryptographically secure
* no syscall required to initialize on Linux (AT_RANDOM)
* calls arc4random on systems that support it
`std.crypto.randomBytes` is removed in favor of `std.crypto.random.bytes`.
I moved some of the Random implementations into their own files in the
interest of organization.
stage2 no longer requires passing a RNG; instead it uses this API.
Closes #6704
Diffstat (limited to 'lib/std/start.zig')
| -rw-r--r-- | lib/std/start.zig | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/lib/std/start.zig b/lib/std/start.zig index 7d3a9c45c7..b6fb7e4dfd 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -10,6 +10,7 @@ const std = @import("std.zig"); const builtin = std.builtin; const assert = std.debug.assert; const uefi = std.os.uefi; +const tlcsprng = @import("crypto/tlcsprng.zig"); var argc_argv_ptr: [*]usize = undefined; @@ -215,6 +216,28 @@ fn posixCallMainAndExit() noreturn { std.os.linux.tls.initStaticTLS(); } + { + // Initialize the per-thread CSPRNG since Linux gave us the handy-dandy + // AT_RANDOM. This depends on the TLS initialization above. + var i: usize = 0; + while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { + switch (auxv[i].a_type) { + std.elf.AT_RANDOM => { + // "The address of sixteen bytes containing a random value." + const addr = auxv[i].a_un.a_val; + if (addr == 0) break; + const ptr = @intToPtr(*const [16]u8, addr); + var seed: [32]u8 = undefined; + seed[0..16].* = ptr.*; + seed[16..].* = ptr.*; + tlcsprng.init(seed); + break; + }, + else => continue, + } + } + } + // TODO This is disabled because what should we do when linking libc and this code // does not execute? And also it's causing a test failure in stack traces in release modes. @@ -250,6 +273,9 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { } fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { + // We do not attempt to initialize tlcsprng from AT_RANDOM here because + // libc owns the start code, not us, and therefore libc ows the random bytes + // from AT_RANDOM. var env_count: usize = 0; while (c_envp[env_count] != null) : (env_count += 1) {} const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; |
