3 ms·
bmm6o's reply captures the approach; you WIPEONFORK a guard variable, and use the state of that variable to re-initialize. When we're writing a crypto library,
by colmmacc 9y ago
bmm6o's reply captures the approach; you WIPEONFORK a guard variable, and use the state of that variable to re-initialize.
When we're writing a crypto library, like s2n, or OpenSSL, we don't get a choice to avoid fork() ... the application can fork() any time it wants and we just have to be able to deal with it. There have been a few approaches:
* Always feed new entropy on every call (but this isn't always available)
* Use getpid() to detect a fork() ... but this can break because some versions of libc cache the value of getpid(). Another problem is the grand-child problem, where an application can fork(), have have the child start a new process group, then the parent exits, then the child fork()s again ... in that situation there's some chance that the grandchild ends up with the same PID as the original process that started everything (and may have used the RNG).
* To fix that, one clever approach that BoringSSL used for a while was to check both getpid() and getppid(), which signaficantly reduced the likelihood of occurrence but was still probabilistic.
* All sorts of weird clone() flags, that things like language runtimes and virtual machines use, can bypass pthread_atfork and PID changes.
- revelation 9y agoWhat's wrong with setting it DONTFORK and handling the page fault in the process? Someone can still prevent you from correctly handling the fault in the new process, but at least that keeps the RNG in an obvious broken state. Right now, the <4.14 fallback seems strictly worse. (Disregarding that this is mostly academic, and that whoever is calling fork() while using your library is unlikely to have spent the same attention to detail when it comes to stuff like ephemeral keys..)
- colmmacc 9y agoI couldn't make this work reliably ... the kinds of applications that call clone() directly and bypass the pthreads stuff are language runtimes and VMs that want to emulate their own lightweight processes. They also have their own page fault handling, and documentation says that behavior is undefined when these things start interacting recursively. It's very difficult for a library to exert control. At a same time these environments often use native crypto that's implemented in C, for performance, and so it all comes together. Of course the other mitigations present still work, and we're talking about a very very obscure and unlikely set of circumstances, but why leave even a tiny door open.
- tedunangst 9y agoHow does a library handle a page fault? What if two libraries set the same signal handler?
- daurnimator 9y agoWhy don't people use https://daurnimator.com/post/120415954844/linux-fork-detection-using-thread-specific https://daurnimator.com/post/120415954844/linux-fork-detecti... Related discussion: https://news.ycombinator.com/item?id=9636861 https://news.ycombinator.com/item?id=9636861
- colmmacc 9y agoWow, that's a cool trick - personally, I didn't know this is possible. Does it mean a system call and context switch for every check though? One thing I like about the MINHERIT_ZERO/MADV_WIPEONFORK approach is that it's basically just a low-cost cache-friendly memory lookup at run-time, the only expense is at fork time.