<div dir="ltr"><div dir="ltr">On Wed, 29 Apr 2020 at 18:17, JF Bastien via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">cfe-dev@lists.llvm.org</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div style="color:rgb(0,0,0)">I’ve consulted with folks in security, compilers, and developers of security-sensitive codebases. A few points:</div><div style="color:rgb(0,0,0)"><br></div><div style="color:rgb(0,0,0)"><ul><li>They like that automatic variable initialization provides a security mitigation for a significant percentage of observed zero-day exploits, at extremely low cost, with little chance of regression.</li><li>They like that pattern initialization is a “smoking gun” when seen in a crash log. The size+performance costs have decreased in the last year, but they’d like to see it improve further.</li><li>They like the lower size+performance cost of zero initialization as well as the safety it offers for e.g. size variables (because a size of 0xAA…AA is “infinite” which is bad for bounds checking, whereas zero isn’t). They don’t like that zero is often a valid pointer sentinel value (i.e. initializing pointers to zero can be used in unexpected data flow). They don’t like the silly long compiler flag.</li><li>We’ve deployed automatic variable initialization in a significant amount of code. The vast majority of our deployment uses pattern initialization. A small number uses zero, of which you’ll note <a href="https://opensource.apple.com/source/xnu/xnu-6153.11.26/makedefs/MakeInc.def.auto.html" target="_blank">XNU</a>. We’ve only chosen zero in cases where size or performance were measured issues.</li><li>Automatic variable initialization which might sometimes trap (as Richard suggests) is a proposal we’d like to see implemented, but we’d like to see it under its own separate flag, something like UBSan does with developers choosing trapping or logging modes. The main reason is that pure trapping with zero-init will make deployment significantly harder (it’s no longer a low-risk mitigation), and it’ll make updating our compiler significantly harder (because it might change where it generates traps over time). We also think that trapping behavior would need good tooling, for example through opt remarks, to help find and fix parts of the code where the compiler added traps. A logging mode would ease some of this burden. As well, we’re not convinced on the size+performance cost of either tapping nor logging, complicating the adoption of the mitigation.</li></ul></div></div></div></blockquote><div>I threw together an implementation here: <a href="https://reviews.llvm.org/D79249">https://reviews.llvm.org/D79249</a><br></div><div><br></div><div>It's pretty quick and dirty but it seems to do the right thing on at least a small selection of test cases. I've not tried it on any nontrivial codebases yet. (I'm not sure in what ways it doesn't work, but at least the InstCombine approach seems likely to fight with other InstCombines.)</div><div><br></div><div>Just a few points of my own on the topic of trap-vs-init:</div><div><br></div><div> * Once we agree that we want to harden against uninitialized uses, we're out of the security space entirely. The question of whether we would prefer a crash or a program somehow keeping going after hitting undefined behavior (absent a security bug) is a software engineering question, not a security question, if we agree that they provide the same security mitigation, so if the only users you asked are security-focused ones, you have sampling bias.</div><div> * As I understand it, automatic initialization to zero or to pattern-with-high-bits-set were chosen, in part, because they are very likely to lead to clean crashes. Given that, it doesn't really make sense to me to be concerned about the "trap" risk of the mitigation introducing new crashes, since crashing on bad programs was already part of the goal.</div><div> * The performance of the trapping mode is certainly unproven, but if the trapping mode doesn't introduce new branches and the "potentially trap" markers are removed early enough to not get in the way of other optimizations, it's not obvious to me that there should be any systematic effect.</div><div> * The size of the trapping mode is likewise unproven, but if it only ever replaces a branch destination with a trap, it seems plausible to me that it could *reduce* code size compared to the zeroing mode.</div><div> * In the presence of a bug, "crash early, crash often" is, in (empirically and subjectively) most software domains, the right answer -- continuing after your program's invariants are not met is not sound software engineering practice. But whether we do continue in such cases is exactly the difference between "zero" and "zero-or-maybe-trap". Programs that really need to be robust against things going wrong, and recover in some way, typically install a SIGSEGV and SIGABRT handler anyway. It's probably better to jump to those handlers rather than continue with broken invariants and risk hitting more problems (maybe security problems) later on.</div><div> * Per <a href="http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html">http://blog.llvm.org/2011/05/what-every-c-programmer-should-know_21.html</a> warning or producing opt remarks when the optimizer inserts a trap is not likely to be all that useful. (I think opt remarks would be OK, but I also think it's going to be hard to expose them in a way that helps the user understand what happened well enough to know if they're false positives.) Places where traps are added don't necessarily need to be fixed; the case in question might be unreachable due to program invariants in a way the optimizer can't determine, and in those cases, the remarks will just be non-useful noise. Perhaps a project could keep track of newly-introduced remarks and ask the developer to take a look at them though?</div><div><br></div><div>If we want a separate flag to control whether / how much we use such a trapping mode, I think that could be reasonable, subject to having a good answer to the language dialect concern I expressed previously (eg, maybe there's never a guarantee that we won't insert a trap, even though with the flag on its lowest setting that is actually what happens).</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div style="color:rgb(0,0,0)"><ul><li>We don’t think the design space has been explored enough. We might want to differentiate initialization more than just “floating point is 0xFF…FF, everything else is 0xAA…AA”. For example:</li><ul><li>We could pattern-init pointers (maybe with compile-time random different patterns), and zero-init scalars. This has a good mix of performance and security upsides.</li><li>We could key off heuristics to choose how to initialize, such as variable names, function names, or some machine learning model (and for those who know me: I’m not joking).</li><li>We could use a variety of runtime pseudo-random sources to initialize values.</li><li>We could add a new IR “undef” type, or different late-stage treatment of “undef”, to apply initialization after optimizations have found interesting facts about the program.</li></ul></ul></div><div style="color:rgb(0,0,0)"><br></div><div style="color:rgb(0,0,0)">We’d like to see work continue on improving this mitigation, optimizations around it, and other similar mitigations.</div></div></div></blockquote><div><br></div><div>+1. =) </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div><div><blockquote type="cite"><div>On Apr 22, 2020, at 1:55 PM, Kees Cook via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:</div><br><div><div>On Wed, Apr 22, 2020 at 01:08:03PM -0700, Richard Smith wrote:<br><blockquote type="cite">On Wed, 22 Apr 2020 at 10:49, Joe Bialek <<a href="mailto:jobialek@microsoft.com" target="_blank">jobialek@microsoft.com</a>> wrote:<br><blockquote type="cite">Also not clear to me what the OS is expected to do with this trap. We have<br>a number of information leak vulnerabilities where force initialization<br>kills the bug silently.<br><br></blockquote><br>Do you really mean "kills the bug"? I would certainly believe you have a<br>number of information leak vulnerabilities where zero-init fixes the<br>*vulnerability* (and we should definitely provide tools to harden programs<br>against such vulnerabilities), but the program is still using an<br>uninitialized value and still has a bug. The idea that this compiler change<br>fixes or removes the bug is precisely the language dialect problem that I'm<br>concerned about. Developers must still think that reading an uninitialized<br>value is a bug (even if it's not a vulnerability any more) or they're<br>writing a program in a language dialect where doing that is not a bug.<br></blockquote><br>Yeah, this is another "different communities mean different things"<br>terminology glitch. For the security folks, "bug" tends to stand in for<br>"security bug" or "security flaw". But yes, as you say, the "bug"<br>(misuse of the C language) is present, but the "security flaw" gets<br>downgraded to "just a bug" in the zero-init case. :)<br><br>-- <br>Kees Cook<br>_______________________________________________<br>cfe-dev mailing list<br><a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br><a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br></div></div></blockquote></div><br></div></div>_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</blockquote></div></div>