<span style="line-height:18px">I'm somewhat of a fan of Paul's solution - disallowing calls to non annotated functions.</span><div style="line-height:18px"><br></div><div style="line-height:18px">Would clearing the stack implicitly help all that much if the programmer has already properly cleared the sensitive via a call to memset_s?</div><div style="line-height:18px"><br></div><div style="line-height:18px">I was wrong in saying to clear the caller owned registers, although we should also clear all the argument registers on return.</div><div style="line-height:18px"><br></div><div style="line-height:18px">CIL</div><br><div class="gmail_quote">On Fri Sep 12 2014 at 1:11:42 AM Szabolcs Nagy <<a href="mailto:nsz@port70.net">nsz@port70.net</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">* Russell Harmon <<a href="mailto:eatnumber1@google.com" target="_blank">eatnumber1@google.com</a>> [2014-09-12 02:30:39 +0000]:<br>
> I've been thinking about the issues with securely zero'ing buffers that<br>
> Colin Percival discusses in his blog article<br>
> <<a href="http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html" target="_blank">http://www.daemonology.net/<u></u>blog/2014-09-06-zeroing-<u></u>buffers-is-insufficient.html</a>>,<br>
> and I think I'd like to take a stab at fixing it in clang. Here's my<br>
> proposal:<br>
><br>
> Add a function attribute, say __attribute__((clear_regs_on_<u></u>return)) which<br>
> when a thus annotated function returns will zero all callee owned registers<br>
> and spill slots. Then, all unused caller owned registers will be<br>
> immediately cleared by the caller after return.<br>
<br>
while true that the abstract machine of c cannot make sure that there are<br>
no lower level leaks (the lower layers are always allowed to hold on to<br>
state at the wrong time and copy it somewhere that the abstract machine<br>
cannot observe) there is a way to avoid information leaks in practice<br>
<br>
instead of trying to figure out what are the possible leaks and using<br>
workarounds for them (like volatile function pointer memset) just reexecute<br>
the same code path the secret computation has taken, this is also useful for<br>
verifying that the cryptographic computation was not miscompiled (which<br>
happens and can have catastrophic consequences), this is the "self test trick"<br>
the author seems to be unaware of although it is used in practice:<br>
<br>
<a href="http://git.musl-libc.org/cgit/musl/tree/src/crypt/crypt_blowfish.c#n760" target="_blank">http://git.musl-libc.org/cgit/<u></u>musl/tree/src/crypt/crypt_<u></u>blowfish.c#n760</a><br>
<br>
eg. this is the crypt code in musl libc contributed by Solar Designer<br></blockquote><div><br></div><div>I also wasn't aware of this technique, although it's making quite a few assumptions about the behavior of the compiler. Although an interesting technique, I'd prefer some better guarantees around clearing of hidden state.</div><div><br></div><div>Trying to avoid a philosophical debate, I understand this is a difficult problem, but I don't think that means it's not worthwhile to attempt.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">there are ways in which this can still break in theory but it works well<br>
when the language is compiled ahead of time and there is no heavy runtime<br>
(so the exact same code path is taken and the exact same state is clobbered<br>
one just has to make sure that the "test" cannot be optimized away by the<br>
compiler or not inlined with different choice for temporaries).<br>
<br>
> As for why, I'm concerned with the case where a memory disclosure<br>
> vulnerability exposes all or a portion of sensitive data via either spilled<br>
> registers or infrequently used registers (xmm). If an attacker is able to<br>
> analyze a binary for situations wherein sensitive data will be spilled,<br>
> leveraging a memory disclosure vulnerability it's likely one could craft an<br>
> exploit that reveals sensitive data.<br>
<br>
in general a 'no info leak' attribute is hard to do (the proposed<br>
semantics in the article are grossly underspecified)<br>
<br>
the compiler cannot give strong guarantees: the state it is aware of<br>
might not be everything (eg on a high level backend target where state<br>
is handled dynamically, or timing related leaks) and it is hard to apply<br>
recursively: if a function with such attr calls other functions which<br>
also spill registers, then even the proposed "zero all used registers"<br>
is problematic<br></blockquote><div><br></div><div>I'm not trying to deal with every case. I'm specifically trying to deal with hardening in case of memory disclosure bugs. An attacker e.x. reading from the swap device directly is outside of the scope of this protection, as you require more than just a memory disclosure to exploit.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
what is probably doable is a non-recursive version (which still can be a<br>
help to crypto code, but harder to use correctly). however i suspect even<br>
that's non-trivial to specify in terms of the abstract machine of c<br>
<br>
for recursive things i think the type system has to be invoked: eg a<br>
sensitive type qualifier that marks state which the compiler has to<br>
cleanup after.<br></blockquote><div><br></div><div>I'm not clear on why disallowing calls to non-annotated functions from within an annotated function won't handle these issues.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
however this whole issue is hard because it only matters if code already<br>
invoked ub (otherwise the state left around is not observable by the<br>
attacker), so probably this kind of hardening is entirely the wrong<br>
approach and anything that deals with sensitive data should just be<br>
completely isolated (priv sep, different process etc)<br></blockquote><div><br></div><div>Agreed, priv sep is another important feature to have when dealing with secure data, but I see this as a component of a defense-in-depth approach, and in my opinion saying that a program shouldn't perform ub isn't really a sound argument to begin with.</div></div>