Live data from Hacker News

How to zero a buffer

daemonology.net

131–140 of 216 posts

Re: How to zero a buffer

#131

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

Move the func into a dynamically linked library.

Thanks to the performance requirements of dynamic linking it's going to be a really long time until we have dynamic linker peeking into .so files and checking what a func does.

Re: How to zero a buffer

#132

This all seems kind of silly. Why doesn't C have a type qualifier like called "secure" to inform the compiler that it should avoid security-compromising optimisations and maybe even automatically zero the memory when it falls out of scope?

That sounds a lot like automatic memory management!

To a C dev, that's the same as communism to a US Republican.

Re: How to zero a buffer

#133

You should have test cases to verify the zeroing behavior in the object code. Even if the standard says a compiler must do something does not mean that it does.

The difficult thing is that any way to verify the zeroing behavior would change the compiler's decision about whether it could elide the call to memset. So it's possible (well, almost guaranteed) that the test would succeed even though the memory wouldn't actually be zeroed in production.

If you set up your tests up correctly they should test the exact binary or shared library that is deployed to production and not some test-specific build.

Re: How to zero a buffer

#134
post #85

Earlier quoted context omitted.

>In the absence of a stunningly advanced global optimization that peeks into other previously compiled units You'll be surprised, but this stuff exists since late last century, known as Link-Time Code Generation (LTCG): http://msdn.microsoft.com/en-us/magazine/cc301698.aspx

I've just been digging through the C99 standard (official) and the N1570 (final C11 draft) and have come to the conclusion that these optimizations break the language. This is probably not something you should be compiling your OpenSSL shared library or SSH with. A C program consists of translation units which may be preserved in translation form. That happens in translation phases 1 through 7. Multiple translation u…

> Though it is just an example, and not normative, it is very clear from the wording that the locus of valid optimizations is the translation unit.

I don't think that's clear at all. As you said, it's just an example.

> Phase 8 only consists of resolving references; the last semantic analysis takes place in phase 7.

Why do you think that the only place you can optimize is during the "semantic analysis" phase?

To me the phrase "All such translator output is collected into a program image" (from step 8) is vague enough to not rule out optimization during "collection".

Re: How to zero a buffer

#135
post #94

Earlier quoted context omitted.

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.

If you have multiple threads accessing a shared (mutable) variable in your program, even a shared volatile variable, then you need to guard every access to that variable (which, in this case, includes every function call through memset_ptr) with proper thread synchronisation primitives. Marking a variable "volatile" is not enough to prevent data races in a multi-threaded environment.

If you've put a semaphore, or mutex lock, or whatever around your calls through memset_ptr(), the transformations will all take place inside the lock, and data races should not be an issue.

Re: How to zero a buffer

#136
Is the proposed solution really the best approach? It seems complicated to me and relies on obscure parts of the language. Maybe the problem (compiler optimizes away function call because the result is no longer needed) could be solved like this:

  memset(key, 0, sizeof(key)); 
  if (key[0])  // we are using key, so you can't skip memset()
    dropDead();
Unless the compilers "understand" memset and still optimize away the last two lines? I would hope not... Does anyone know how aggressive the C optimizers are these days?

Re: How to zero a buffer

#137
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.

C/C++ are like Formula 1 racing cars: indispensable if you need to go really, really fast; wildly impractical in all other situations.

Re: How to zero a buffer

#138
post #121

I had no idea that such things are possible in C. The things about I've read recently (the "friendly" C suggestion) and this seem like violations of the spirit of the language. And for what, really? The language looses its signature predictability, which to me seemed like a great feature of C. If you write crappy code and expect the compiler to fix it for you, you should maybe consider another language. I can only im…

> If you write crappy code and expect the compiler to fix it for you, you should maybe consider another language.

This seems rather to be a case of writing good code and having the compiler break it for you.

Re: How to zero a buffer

#139
Just put it in a shared library and don't worry about it. Why all these compiler-specific brittle solutions when simply putting a function in a .so will ensure it's being called and will prevent any link-time optimisations.

Re: How to zero a buffer

#140
post #136

Is the proposed solution really the best approach? It seems complicated to me and relies on obscure parts of the language. Maybe the problem (compiler optimizes away function call because the result is no longer needed) could be solved like this: memset(key, 0, sizeof(key)); if (key[0]) // we are using key, so you can't skip memset() dropDead(); Unless the compilers "understand" memset and still optimize away the las…

The compiler understands memset, so that would probably not work.
Post reply on HN