4 ms·
From colmmacc's link: The option can be used to robustly reset a guard variable, and hence re-initialize an RNG, DRBG, PRF, or other generator where duplicate
by kevan 9y ago
From colmmacc's link:
The option can be used to robustly reset a guard variable, and hence
re-initialize an RNG, DRBG, PRF, or other generator where duplicate state
across processes would be a security issue.
- cperciva 9y agoIsn't there a race condition here? What if the fork happens between when you check the flag and when you access the rng state?
- infogulch 9y agoI had this exact same question. I guess you can make sure the code that checks and reads from the rng state can't fork in the middle of it (or call out to user code). But that only helps in the single-threaded case, what happens if you have another thread that is accessing it at the same time as the fork? Even if you check before and after, the initialized bool could be set again by the time you check after even though you just read a bunch of zeros. A rng-per-thread combined with initialization check before and after might cover all the cases I think...
- revelation 9y agoFrom what I can tell in their s2n code, the canary was/is already TLS.
- deleted 9y ago[deleted]
- colmmacc 9y agoI'm still experimenting with the best approach. On Linux fork() clones a single thread's context, and since we know there's no call to fork() between the line of code checking the guard and the lines of code generating data, we don't need to worry about that so much (the RNGs are thread local). But re-entrancy might be a problem ... e.g. if some crazy application writer has called fork() from a signal handler, and that happened right between those lines. For a case like this, I think moving the guard to post-generation (but pre-use) and using an atomic CAS option to have the guard effect the return value of the generator, can do the trick at the cost of having to very occasionally throw generated data away. But I haven't tried it on all platforms.
- jwilk 9y agoCrazy is the correct word here. glibc's fork() implementation is not async-signal-safe (even though POSIX currently says it should be), so you're going to have a bad time if you fork from a signal handler. https://sourceware.org/bugzilla/show_bug.cgi?id=4737 https://sourceware.org/bugzilla/show_bug.cgi?id=4737
- cperciva 9y agoSorry, I missed this comment when I brought the issue up below. (I was on my phone, which is sort of an excuse...) With a thread-local RNG (and a thread-local page which gets zeroed on fork) it sounds like you're probably best off extracting data from the RNG and then checking the flag to see if you need to go back and try again. The only cost of doing it this way is a very marginal extra cost whenever you need to regenerate entropy -- but you can think of that as just being a slight increase in the cost of the fork. The only other question which comes to mind is whether you need to worry about breakage on systems which have weaker-than-x86 cache coherency. I'm 99% certain that you're fine, but I'd prefer to be 100% certain. I assume you'd like to see this functionality added to other platforms as well?
- deleted 9y ago[deleted]
- tedunangst 9y agoHow can that happen? The racing thread doesn't exist in the child.
- cperciva 9y agoHow about if the fork happens from a signal handler?
- colmmacc 9y agoSee my reply here ... https://news.ycombinator.com/item?id=15761490 https://news.ycombinator.com/item?id=15761490
- tedunangst 9y agoWhy does that matter? The parent will eventually return from the signal handler and resume execution. What does fork have to do with anything? arc4random (or whatever you want to call it) isn't marked signal safe.
- cperciva 9y agoThe child will also eventually return from the signal handler and resume execution. In the middle of the PRNG, thus returning the same random numbers in both processes. I'm not sure what you mean by "arc4random isn't marked signal safe" -- you mean it can't be used in any process which receives signals?