[cfe-dev] Zero'ing Registers on Function Return

Szabolcs Nagy nsz at port70.net
Fri Sep 12 01:11:41 PDT 2014


* Russell Harmon <eatnumber1 at google.com> [2014-09-12 02:30:39 +0000]:
> I've been thinking about the issues with securely zero'ing buffers that
> Colin Percival discusses in his blog article
> <http://www.daemonology.net/blog/2014-09-06-zeroing-buffers-is-insufficient.html>,
> and I think I'd like to take a stab at fixing it in clang. Here's my
> proposal:
> 
> Add a function attribute, say __attribute__((clear_regs_on_return)) which
> when a thus annotated function returns will zero all callee owned registers
> and spill slots. Then, all unused caller owned registers will be
> immediately cleared by the caller after return.

while true that the abstract machine of c cannot make sure that there are
no lower level leaks (the lower layers are always allowed to hold on to
state at the wrong time and copy it somewhere that the abstract machine
cannot observe) there is a way to avoid information leaks in practice

instead of trying to figure out what are the possible leaks and using
workarounds for them (like volatile function pointer memset) just reexecute
the same code path the secret computation has taken, this is also useful for
verifying that the cryptographic computation was not miscompiled (which
happens and can have catastrophic consequences), this is the "self test trick"
the author seems to be unaware of although it is used in practice:

http://git.musl-libc.org/cgit/musl/tree/src/crypt/crypt_blowfish.c#n760

eg. this is the crypt code in musl libc contributed by Solar Designer

there are ways in which this can still break in theory but it works well
when the language is compiled ahead of time and there is no heavy runtime
(so the exact same code path is taken and the exact same state is clobbered
one just has to make sure that the "test" cannot be optimized away by the
compiler or not inlined with different choice for temporaries).

> As for why, I'm concerned with the case where a memory disclosure
> vulnerability exposes all or a portion of sensitive data via either spilled
> registers or infrequently used registers (xmm). If an attacker is able to
> analyze a binary for situations wherein sensitive data will be spilled,
> leveraging a memory disclosure vulnerability it's likely one could craft an
> exploit that reveals sensitive data.

in general a 'no info leak' attribute is hard to do (the proposed
semantics in the article are grossly underspecified)

the compiler cannot give strong guarantees: the state it is aware of
might not be everything (eg on a high level backend target where state
is handled dynamically, or timing related leaks) and it is hard to apply
recursively: if a function with such attr calls other functions which
also spill registers, then even the proposed "zero all used registers"
is problematic

what is probably doable is a non-recursive version (which still can be a
help to crypto code, but harder to use correctly). however i suspect even
that's non-trivial to specify in terms of the abstract machine of c

for recursive things i think the type system has to be invoked: eg a
sensitive type qualifier that marks state which the compiler has to
cleanup after.

however this whole issue is hard because it only matters if code already
invoked ub (otherwise the state left around is not observable by the
attacker), so probably this kind of hardening is entirely the wrong
approach and anything that deals with sensitive data should just be
completely isolated (priv sep, different process etc)



More information about the cfe-dev mailing list