On 7/10/24 18:26, Andrey Semashev wrote:
On 7/10/24 14:59, Peter Dimov via Boost wrote:
Ruben Perez wrote:
There is OPENSSL_Cleanse, which does a similar job. I found it surprisingly simple - I wonder if this is just enough or there are any corner cases where this doesn't work: https://github.com/openssl/openssl/blob/b544047c99c4a7413f793afe82ab1c165f85...
That's an interesting approach. I can't offhand think of a reason why it wouldn't work.
The compiler might convert OPENSSL_cleanse to something like this:
void OPENSSL_cleanse(void *ptr, size_t len) { memset_t func = memset_func; if (func != memset) func(ptr, 0, len); else memset(ptr, 0, len); }
The purpose here is that, if memset_func is actually memset most of the time, it can further optimize the call to memset, including to completely remove it, depending on the call context. The (well-predictable) branch is typically cheaper than an indirect call. I think I've seen compilers do something along those lines as a result of call devirtualization, especially with IPO and LTCG.
I'm not saying that's what actually happens in OpenSSL, just that something like this is possible. I think, a dummy asm statement is more reliable and more efficient.
void secure_cleanse(void *ptr, size_t len) { memset(ptr, 0, len); // a normal memset, optimizations are welcome __asm__ __volatile__ ("" : : "r" (ptr), "r" (len) : "memory"); }
You can even make that function inline and it'll work, and in an optimal way, too.
And for compilers that don't support __asm__, I think you could replace it with: std::atomic_signal_fence(std::memory_order::acq_rel);