Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

So what is someone working with embedded devices for IoT supposed to do? Much of that work is based on ARM C/C++ Compilers.


Use a compiler that has extensions that _do_ guarantee that memory gets erased. That's what the gcc function attributes are for.

Alternatively, use a library that the C compiler doesn't know so much about that it will attempt to remove calling functions in them.

If you copy your standard library's memset in a separate DLL that is not the standard C library, the compiler will not even see the code during compilation, so it has to compile a function call.

The linker (or a JIT in your C runtime) is allowed to remove calls to the function, if it can prove that it doesn't have side effects. However, to prove that, it has to look at the assembly of the function; it cannot use the way simpler heuristic "it came from <memory.h> and is called memset"


If you copy your standard library's memset in a separate DLL that is not the standard C library, the compiler will not even see the code during compilation, so it has to compile a function call.

Although I'd like things to behave this way, I don't think this is true. The C standard library was incorporated into the language spec for C89. The behaviors of the named functions within it are specified, and the compiler is allowed to inline it's own version (ignoring your custom code) and then optimize out the inlined portion.

So while it's possible that the external linkage approach still works with certain compilers, it's not portable. I believe you are OK with the external approach if you use a non-standard name (my_secure_memset_pretty_please()), but that just shifts the problem to forcing the compiler to generate your external function without making the same dangerous optimizations.

In the end, I fear you are left with three options: blind faith, non-standard language extensions, or switching to a more secure language (likely assembly). If there are other options, I love to hear about them.


In practice, of course, memset actually works, because it's a function and the compiler's usage tracing is nowhere near able to spot that you don't reference those zeros that you write.

(IoT security is doom for other reasons though, mostly UI, updatability and cloud services)


Really? In my experience most compilers treat it pretty much like an intrinsic and generate specialized set of instructions if they can.


For now.

And then that code you wrote now silently becomes deadly a few years down the line.


I would be very interested to see the compiler that can optimise away memset across a shared library boundary.


LLVM can and will do it. It will assume it knows what a function named "memcpy" (for example) does and optimizes accordingly. (Look at TargetLibraryInfo.cpp and grep for LibFunc::memset in, for example, SimplifyLibCalls.cpp.)

(That said, I think TheLoneWolfling is being too strong with his/her claims. You can get modern compilers to avoid dangerous optimizations; it's just not for the faint of heart.)


I never said you couldn't get a particular compiler to. Or indeed, all current compilers.

I am saying that it's impossible to do so and remain in the realm of portable C / C++.

There is a distinction.


Also: isn't that a bug? Is there something in a C / C++ standard that states that a function named "memcpy" (for example) is necessarily the normal function?


Compilers have been doing this for a long time. The optimizations that this enables are essential for performance. They shouldn't stop; if the spec prohibits it, the spec should change (and if it doesn't, the compilers should ignore the spec).


Good to know about the first and last part.

And as for the second part... Meh. I don't see any optimizations that hard-coding calling something named "memcpy" (or whatever) does that cannot be enabled by looking at the actual code that gets linked. Albeit with more difficulty.


A JITter would be able to do that. And the JVM can (and will) do the equivalent for Java code.

Remember: there is nothing that specifies that C / C++ needs to be compiled.

Also: you could have said the same twenty years ago about many of the optimizations that currently compilers do.


1. Compile without optimization (maybe just the crypto parts, if that's possible). 2. Write all crypto stuff in assembly, link in as static binary.


Neither of those work in general.

W.r.t. 1, the compiler's definition of no optimization today is not the same thing as it was last version, or will be next version. For instance, on IA-64 there are things the compiler has to do that are typically considered optimizations.

W.r.t. 2, you have to make sure there is no link-time optimization happening.


Lto does not work on assembly, it only works if some IR is stored in the .o files (like gimple for gcc) iirc.


Currently.

However, that is not an inherent restriction - that is only a restriction on current compilers. It is entirely possible for a compiler to read the assembly of things being linked and optimize based on that.


You could also dynamically link.


That does not solve the problem. That only hides it and means it will be deadly later.

For instance, when someone runs it in an emulator for backwards compatibility purposes. Or when someone runs it in a JITter. Or even just if the compiler decides to special-case for the existing link target.


Either:

* Use a specific compiler and verify.

* Don't use C / C++.

* Panic.


C11 actually adds the memset_s function, which is guaranteed by the language spec not to be optimized away:

> memset may be optimized away (under the as-if rules) if the object modified by this function is not accessed again for the rest of its lifetime. For that reason, this function cannot be used to scrub memory (e.g. to fill an array that stored a password with zeroes). This optimization is prohibited for memset_s: it is guaranteed to perform the memory write.

http://en.cppreference.com/w/c/string/byte/memset


Except, of course, that memset_s is still not enough.

The compiler can and will copy things around, and it is not required to memset_s said cop(y)/(ies) away.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: