Live data from Hacker News

How to zero a buffer

daemonology.net

91–100 of 216 posts

Re: How to zero a buffer

#91
post #83

Earlier quoted context omitted.

I'm not aware of any language that would be better. Most languages don't even let you touch memory to try to zero it.

Zeroing out an array or struct field is not a C-specific feature.

Dead store elision is not a C specific optimization.

Re: How to zero a buffer

#94

Earlier quoted context omitted.

The first comment there (by Anonymous) claims that the final technique can also be optimized: (memset_ptr)(p, 0, len); > can be replaced by: if (memset_ptr == memset) { memset(p, 0, len); } else { memset_ptr(p, 0, len); } > Which in turn can be optimized using the other tricks noticed above into: if (memset_ptr != memset) { memset_ptr(p, 0, len); } I'm no expert, but this seems like a believable defeat of the techniq…

That's not quite right since it's now reading memset_ptr twice, but the concept does seem to be right -- the volatile pointer must be read but the standard doesn't require that the function is invoked.

What about a data race? Theoretically, the function that memset_ptr points to could be changed between when it is checked and when it would be run.

Re: How to zero a buffer

#97

The article the completely obvious: /* implemented in another translation unit */ void zero_for_sure(void *data, size_t size); void func(void) { char securedata[42]; /* ... */ zero_for_sure(securedata, sizeof securedata); } The key here is that our zero_for_sure is an external function in a separately translated file. In the absence of a stunningly advanced global optimization that peeks into other previously compile…

From the article, "Some people will try this with secure_memzero in a separate C file. This will trick yet more compilers, but no guarantees — with link-time optimization the compiler may still discover your treachery." https://gcc.gnu.org/wiki/LinkTimeOptimization http://llvm.org/docs/LinkTimeOptimization.html

1. It is the compiler that is committing treachery here. This stuff stretches, if not outright breaks, the translation model given in the C standard, where it is clear that a program is separated into translation units, and that linkage resolves external names.

2. You bring this on yourself; it's not enabled by default by ordinary optimization options like -O2 or -O3. You have to ask for it, and so you must know what you're doing.

3. Under gcc, it looks like only those object files compiled with -flto are prepared for this optimization. You can arrange through your makefile or whatever not to apply -flto to sensitive modules that cannot be inlined or optimized away into other translation units. Those object files won't then contain the GIMPLE bytecode and whatnot needed to be able to peer into their internals at link time.

4. I don't think the dynamic linker in libc (ld.so) does this optimization, so putting code into shared libs may be another good way to hide it.

So, basically, the external function approach is still a very good tool for defeating unwanted inlining and dead code elimination, provided you don't stupidly use some advanced features that bend the standard translation model of the C language. In security-critical code, to boot. External functions are expressed using the standard language; the approach will work under pretty much any compiler.

Re: How to zero a buffer

#98

Earlier quoted context omitted.

I'm gonna go ahead and say it: Perhaps in retrospect C is an inappropriate choice of language for these kinds of applications. This "Performance at all costs, including safety and predictability" thing may be appropriate in video games, but for security-critical applications that philosophy is downright negligent.

I'm not aware of any language that would be better. Most languages don't even let you touch memory to try to zero it.

This is what Mozilla is trying to create with Rust

http://www.rust-lang.org/

Re: How to zero a buffer

#99
post #55

Earlier quoted context omitted.

Perhaps in retrospect this was an inappropriate choice of definition, at least for cryptographic operations.

I'm gonna go ahead and say it: Perhaps in retrospect C is an inappropriate choice of language for these kinds of applications. This "Performance at all costs, including safety and predictability" thing may be appropriate in video games, but for security-critical applications that philosophy is downright negligent.

Dead store elimination is a really important optimization, and it comes out of bog-standard compiler optimizations like SROA on SSA form IR. You really want your compiler to perform it for acceptable performance.

Re: How to zero a buffer

#100
post #63

Earlier quoted context omitted.

It's because memset is a standard function and has a defined standard way of acting, with the most important part being that it doesn't produce any side-effects. It's also worth noting that accessing memory that's no longer in the current scope is undefined-behavior, so the compiler can assume it doesn't happen. Thus the memset has absolutely zero effect on the actual program and isn't necessary. In general this isn'…

What if one made some trivial use of the block of memory after having performed the memset, say something like this: void dosomethingsensitive(void) { uint8_t key[32]; ... /* Zero sensitive information. */ memset((volatile void *)key, 0, sizeof(key)); key[0] = key[1] + 1; } Would that thwart the optimizer, or would it also see through that usage and eliminate it as well?

You should keep in mind that the memset call is almost guarenteed to be inlined. So your code actually looks like this:

    void
    dosomethingsensitive(void)
    {
        uint8_t key[32];
        /* ... */
        int i;
        for (i = 0; i 
Assuming the optimizer is sufficiently smart, then it'll remove that 'for' and it'll remove the addition after it in the same fashion.
Post reply on HN