| ... | @@ -206,7 +206,6 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -206,7 +206,6 @@ fn posixCallMainAndExit() noreturn { |
| 206 | // Do this as early as possible, the aux vector is needed | 206 | // Do this as early as possible, the aux vector is needed |
| 207 | if (builtin.position_independent_executable) { | 207 | if (builtin.position_independent_executable) { |
| 208 | @import("os/linux/start_pie.zig").apply_relocations(); | 208 | @import("os/linux/start_pie.zig").apply_relocations(); |
| 209 | @fence(.SeqCst); | | |
| 210 | } | 209 | } |
| 211 | | 210 | |
| 212 | // Initialize the TLS area. We do a runtime check here to make sure | 211 | // Initialize the TLS area. We do a runtime check here to make sure |
| ... | @@ -215,10 +214,9 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -215,10 +214,9 @@ fn posixCallMainAndExit() noreturn { |
| 215 | const is_dynamic = @import("dynamic_library.zig").get_DYNAMIC() != null; | 214 | const is_dynamic = @import("dynamic_library.zig").get_DYNAMIC() != null; |
| 216 | if (!is_dynamic) { | 215 | if (!is_dynamic) { |
| 217 | std.os.linux.tls.initStaticTLS(); | 216 | std.os.linux.tls.initStaticTLS(); |
| 218 | @fence(.SeqCst); | | |
| 219 | } | 217 | } |
| 220 | | 218 | |
| 221 | { | 219 | if (!@hasDecl(root, "use_AT_RANDOM_auxval") or root.use_AT_RANDOM_auxval) { |
| 222 | // Initialize the per-thread CSPRNG since Linux gave us the handy-dandy | 220 | // Initialize the per-thread CSPRNG since Linux gave us the handy-dandy |
| 223 | // AT_RANDOM. This depends on the TLS initialization above. | 221 | // AT_RANDOM. This depends on the TLS initialization above. |
| 224 | var i: usize = 0; | 222 | var i: usize = 0; |
| ... | @@ -226,19 +224,7 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -226,19 +224,7 @@ fn posixCallMainAndExit() noreturn { |
| 226 | switch (auxv[i].a_type) { | 224 | switch (auxv[i].a_type) { |
| 227 | std.elf.AT_RANDOM => { | 225 | std.elf.AT_RANDOM => { |
| 228 | // "The address of sixteen bytes containing a random value." | 226 | // "The address of sixteen bytes containing a random value." |
| 229 | const addr = auxv[i].a_un.a_val; | 227 | initCryptoSeedFromAuxVal(auxv[i].a_un.a_val); |
| 230 | if (addr == 0) break; | | |
| 231 | const ptr = @intToPtr(*[16]u8, addr); | | |
| 232 | var seed: [32]u8 = undefined; | | |
| 233 | seed[0..16].* = ptr.*; | | |
| 234 | seed[16..].* = ptr.*; | | |
| 235 | tlcsprng.init(seed); | | |
| 236 | // Overwrite AT_RANDOM after we use it, otherwise our secure | | |
| 237 | // seed is sitting in memory ready for some other code in the | | |
| 238 | // program to reuse, and hence break our security. | | |
| 239 | // We play nice by refreshing it with fresh random bytes | | |
| 240 | // rather than clearing it. | | |
| 241 | std.crypto.random.bytes(ptr); | | |
| 242 | break; | 228 | break; |
| 243 | }, | 229 | }, |
| 244 | else => continue, | 230 | else => continue, |
| ... | @@ -281,15 +267,31 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { | ... | @@ -281,15 +267,31 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { |
| 281 | } | 267 | } |
| 282 | | 268 | |
| 283 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { | 269 | fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { |
| 284 | // We do not attempt to initialize tlcsprng from AT_RANDOM here because | 270 | // By default, we do not attempt to initialize tlcsprng from AT_RANDOM here because |
| 285 | // libc owns the start code, not us, and therefore libc ows the random bytes | 271 | // libc owns the start code, not us, and therefore libc owns the random bytes |
| 286 | // from AT_RANDOM. | 272 | // from AT_RANDOM. |
| | 273 | if (builtin.os.tag == .linux and |
| | 274 | @hasDecl(root, "use_AT_RANDOM_auxval") and |
| | 275 | root.use_AT_RANDOM_auxval) |
| | 276 | { |
| | 277 | initCryptoSeedFromAuxVal(std.c.getauxval(std.elf.AT_RANDOM)); |
| | 278 | } |
| 287 | var env_count: usize = 0; | 279 | var env_count: usize = 0; |
| 288 | while (c_envp[env_count] != null) : (env_count += 1) {} | 280 | while (c_envp[env_count] != null) : (env_count += 1) {} |
| 289 | const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; | 281 | const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; |
| 290 | return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); | 282 | return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); |
| 291 | } | 283 | } |
| 292 | | 284 | |
| | 285 | fn initCryptoSeedFromAuxVal(addr: usize) void { |
| | 286 | if (addr == 0) return; |
| | 287 | const ptr = @intToPtr(*[16]u8, addr); |
| | 288 | tlcsprng.init(ptr.*); |
| | 289 | // Clear AT_RANDOM after we use it, otherwise our secure |
| | 290 | // seed is sitting in memory ready for some other code in the |
| | 291 | // program to reuse, and hence break our security. |
| | 292 | std.crypto.utils.secureZero(u8, ptr); |
| | 293 | } |
| | 294 | |
| 293 | // General error message for a malformed return type | 295 | // General error message for a malformed return type |
| 294 | const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'"; | 296 | const bad_main_ret = "expected return type of main to be 'void', '!void', 'noreturn', 'u8', or '!u8'"; |
| 295 | | 297 | |