6 ms·
Or C doesn't provide the necessary semantic. For example, trying to zero a page before freeing it (because is contains sensitive information) is surprisingly h
by zimbatm 7y ago
Or C doesn't provide the necessary semantic.
For example, trying to zero a page before freeing it (because is contains sensitive information) is surprisingly hard. Optimizing compilers will consider that since the memory is not going to be accessed it doesn't need to write the zeroes to it. Look at all the contortions libsodium goes to do coerce all the compilers to do the right thing :) https://github.com/jedisct1/libsodium/blob/a26467874a512de304f6e7e25d98af549963de9f/src/libsodium/sodium/utils.c#L97-L142 https://github.com/jedisct1/libsodium/blob/a26467874a512de30...
- chrisseaton 7y agoWhy don't people write things like that in assembly and call that from C?
- beefhash 7y agoI could imagine that perhaps they want the program to work on architectures other than the ones they can provide and test assembly code for.
- chrisseaton 7y agoIf they don't have a way to test and look at machine code on these architectures... then how can they know their workarounds for compiler optimisations are working?
- megous 7y agoThese are not workarounds. The code looks complicated only because it tries to be portable and fast. Otherwise just the last #else block would be enough. Also they know, because it's what those functions they call are for. man explicit_bzero for example. It says: "The explicit_bzero() function performs the same task as bzero(). It differs from bzero() in that it guarantees that compiler optimizations will not remove the erase operation if the compiler deduces that the operation is "unnecessary"."
- chrisseaton 7y ago> These are not workarounds. What is the purpose of this line? Why do you think it's there if the C code using volatile is enough on its own? https://github.com/jedisct1/libsodium/blob/a26467874a512de304f6e7e25d98af549963de9f/src/libsodium/sodium/utils.c#L131 https://github.com/jedisct1/libsodium/blob/a26467874a512de30... It's a workaround to prevent optimisations because that happens to be how some compilers are implemented today. Will it be implemented like that tomorrow or in a different compiler? Who knows. https://github.com/jedisct1/libsodium/commit/27872ca13c713c90cd5576722a3f672a73d4c9f6 https://github.com/jedisct1/libsodium/commit/27872ca13c713c9...
- megous 7y agoThat line is not present at all if volatile using variant of the function is used.
- nsajko 7y agoBoringssl used to use assembly until they figured out this trick of scaring the compiler away by justing putting an assembly directive in the function: https://boringssl.googlesource.com/boringssl/+/refs/heads/master/crypto/mem.c#156 https://boringssl.googlesource.com/boringssl/+/refs/heads/ma... https://boringssl.googlesource.com/boringssl/+/ad1907fe73334d6c696c8539646c21b11178f20f%5E!/#F0 https://boringssl.googlesource.com/boringssl/+/ad1907fe73334...
- pjmlp 7y agoWhich is the kind of clever thing that it works until it doesn't, common in many C codebases.
- nsajko 7y agoI am pretty sure the code is entirely correct when meant for GCC or Clang. Standards-noncompliance (because of inline assembly) is another issue, of course; but one could argue that GCC and Clang are the de facto standard.
- jdsully 7y agoThe problem would be someone working on the GCC optimizer deciding, “Wouldn’t it be great if we could do all our fancy optimizations on functions with inline assembly?”
- nsajko 7y agoSearch for "volatile" in http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Extended-Asm.html http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Extended-Asm.htm...
- deleted 7y ago[deleted]
- jdsully 7y agoVolatile only says that the clobbered memory is not listed. Nothing would stop the compiler from statically analyzing the assembly to make smarter decisions if it chose to do so. This would be trivial with an empty asm block. However because inline assembly is non-standard even that is not truly guaranteed. Your relying on the good graces of the optimizers that have broken all the other code paths with their legalistic approach.
- missblit 7y agoI'm not familiar with writing code to wipe memory, but couldn't you just use volatile keyword? Volatile writes are not supposed to be optimized away, and pointers to non-volatile types can be cast to pointers to volatile types. Edit: Actually looking at your link closer (too many #defines makes my eyes glaze over), it looks like the final else branch appears to use volatile like I mentioned. I assume all the branches above it are optimizations for different systems?
- holy_city 7y agoVolatile is a hacky way to avoid optimizations and plays hell with normal language semantics. For example, you can't memcpy or memset volatile pointers or pointers to volatiles. Imo if you don't want the compiler to optimize something, tell it not to. For example in GCC: __attribute__((optimize("-O0"), noinline)) void zero_memory(void* memory, size_t sz) { memset(memory, 0, sz); } If you wanted to make that portable, there are equivalents in clang and msvc so you'd want to use some #defines here and there. Of course disabling optimizations/inlining in functions has a performance hit, but I think if you're so concerned with code being ignored the tradeoff is appropriate.
- cpeterso 7y agoWindows even provides a SecureZeroMemory API because solving this problem reliably at the language level is hard. I see the sodium_memzero function you linked to calls Windows' SecureZeroMemory. :) https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa366877(v=vs.85) https://docs.microsoft.com/en-us/previous-versions/windows/d...
- andreyv 7y agoC now has a memset_s() function to do this.