1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00
putty-source/utils/smemclr.c
Simon Tatham 395c228bee Adopt a new universal implementation of smemclr().
This new implementation uses the same optimisation-barrier technique
that I used in various places in testsc: have a no-op function, and a
volatile function pointer pointing at it, and then call through the
function pointer, so that nothing actually happens (apart from the
physical call and return) but the compiler has to assume that
_anything_ might have happened.

Doing this just after a memset enforces that the compiler can't have
thrown away the memset, because the called function might (for
example) check that all the memory really is zero and abort if not.

I've been turning this over in my mind ever since coming up with the
technique for testsc. I think it's far more robust than the previous
smemclr technique: so much so that I'm switching to using it
_everywhere_, and no longer using platform alternatives like Windows's
SecureZeroMemory().
2021-04-18 08:30:44 +01:00

53 lines
1.6 KiB
C

/*
* Securely wipe memory.
*
* The actual wiping is no different from what memset would do: the
* point of 'securely' is to try to be sure over-clever compilers
* won't optimise away memsets on variables that are about to be freed
* or go out of scope. See
* https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html
*/
#include "defs.h"
#include "misc.h"
/*
* Trivial function that is given a pointer to some memory and ignores
* it.
*/
static void no_op(void *ptr, size_t size) {}
/*
* Function pointer that is given a pointer to some memory, and from
* the compiler's point of view, _might_ read it, or otherwise depend
* on its contents.
*
* In fact, this function pointer always points to no_op() above. But
* because the pointer itself is volatile-qualified, the compiler
* isn't allowed to optimise based on the assumption that that will
* always be the case. So it has to call through the function pointer
* anyway, on the basis that it _might_ have magically changed at run
* time into a pointer to some completely arbitrary function. And
* therefore it must also avoid optimising away any observable effect
* beforehand that a completely arbitrary function might depend on -
* such as the zeroing of our memory re3gion.
*/
static void (*const volatile maybe_read)(void *ptr, size_t size) = no_op;
void smemclr(void *b, size_t n)
{
if (b && n > 0) {
/*
* Zero out the memory.
*/
memset(b, 0, n);
/*
* Call the above function pointer, which (for all the
* compiler knows) might check that we've really zeroed the
* memory.
*/
maybe_read(b, n);
}
}