From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2024-07-10 15:26:20


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/b544047c99c4a7413f793afe82ab1c165f85b5b6/crypto/mem_clr.c#L22
>
> 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.