authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-20 15:26:17+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-05-20 15:26:17+02:00
logabfe7f96dd45e22d43c3e14ed64e1fbb8e94b419
treee4283d3203940eb4588d8c87f12964ad6902dfb7
parent992c02ab95e8297a1558bcf011f15a5cf1cd8e1b

std: Call pthread_atfork only once

Some libc implementations (glib) deduplicate identical hooks, others (musl, macos) do not and blindly append them to an internal list. Ensure there's only a single call to pthread_atfork to prevent unbounded memory use when lots of threads/forks are used.

1 files changed, 12 insertions(+), 8 deletions(-)

lib/std/crypto/tlcsprng.zig+12-8
...@@ -48,6 +48,16 @@ const Context = struct {...@@ -48,6 +48,16 @@ const Context = struct {
48 gimli: std.crypto.core.Gimli,48 gimli: std.crypto.core.Gimli,
49};49};
5050
51var install_atfork_handler = std.once(struct {
52 // Install the global handler only once.
53 // The same handler is shared among threads and is inherinted by fork()-ed
54 // processes.
55 fn do() void {
56 const r = std.c.pthread_atfork(null, null, childAtForkHandler);
57 std.debug.assert(r == 0);
58 }
59}.do);
60
51threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};61threadlocal var wipe_mem: []align(mem.page_size) u8 = &[_]u8{};
5262
53fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {63fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {
...@@ -135,14 +145,8 @@ fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {...@@ -135,14 +145,8 @@ fn tlsCsprngFill(_: *const std.rand.Random, buffer: []u8) void {
135}145}
136146
137fn setupPthreadAtforkAndFill(buffer: []u8) void {147fn setupPthreadAtforkAndFill(buffer: []u8) void {
138 const failed = std.c.pthread_atfork(null, null, childAtForkHandler) != 0;148 install_atfork_handler.call();
139 if (failed) {149 return initAndFill(buffer);
140 const ctx = @ptrCast(*Context, wipe_mem.ptr);
141 ctx.init_state = .failed;
142 return fillWithOsEntropy(buffer);
143 } else {
144 return initAndFill(buffer);
145 }
146}150}
147151
148fn childAtForkHandler() callconv(.C) void {152fn childAtForkHandler() callconv(.C) void {