C++ Logo


Advanced search

Re: Memory Safety and Page Protected Memory

From: Robin Rowe <robin.rowe_at_[hidden]>
Date: Fri, 1 Mar 2024 14:23:06 -0800
On 3/1/2024 12:32 PM, Arthur O'Dwyer wrote:
> `memset_explicit` is in C23 for real
> <https://en.cppreference.com/w/c/string/byte/memset>.

Using memset_explicit() in C++, or explicit_bzero() in C, is a different
topic. Zeroing sensitive memory later is not like a safe_memory_alloc()
function returning a pointer to a protected page of memory.

> Your proposed feature is shaped more like "protection from reads from
> within the same process," which I don't even understand what that
> would mean...

Safe memory is special OS memory that is somewhere else, not the app's
stack, not in the heap, not in static memory, at an address far away
from all of the other pointers in the app. It is almost impossible that
incrementing some other pointer in the app can overrun into a safe
memory data buffer.

Not only that, a second requirement is that a pointer to a safe memory
data buffer is impossible to overrun. A buffer overrun by a safe memory
pointer is not undefined behaviour. Increment the safe memory pointer,
then access off the end of its buffer, and the app will segfault or
raise a signal every time, immediately. No guard bands, it just works
that way at the OS level.

Robin Rowe
Beverly Hills, California
*Chairman ISO WG21 SG14 C++ Banking and Financial Systems Subcommittee

On 3/1/2024 12:32 PM, Arthur O'Dwyer wrote:
> Robin,
> Your idea, especially in the focus on "security," sounds an awful lot
> like P1315 "secure_clear"
> <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1315r7.html>,
> which was rejected by C++ but according to the GitHub tracker
> <https://github.com/cplusplus/papers/issues/67> was actually adopted by
> WG14 for C23.
> The problem with "secure_clear" — which was supposed to behave like
> memset(buf, '\0', sizeof(buf)) except "do what I mean" in the case that
> `buf` was dead after the write — is that it doesn't actually help any
> production use-case as far as we could tell.
> Con: "If you're using this thing to zero out a password, or something,
> you're definitely doing it wrong, because you failed to pin the buffer's
> page in RAM. It will get swapped to disk, your magic memset won't zero
> out the /swapfile/, and you're just as pwned as if you had used ordinary
> memset in the first place. Or, your magic memset will zero out the L1
> /cache/ but fail to zero out the L2/L3 cache or main memory. Or, your
> magic memset will zero out the buffer you pointed it at, but it won't
> zero out the other copies of that same data that the optimizer caused to
> be made (trivially, thus undetectably) all over the stack, under the
> As-If Rule. Or, the attacker will just read that memory /before/ the
> memset, instead of after."
> Pro: "Belt-and-suspenders! Swiss cheese security model! We certainly
> need more work on things like an API for pinning memory pages, but
> secure_memset can't possibly /hurt!/"
> Con: "Look, there are only two cases to consider here. Case 1 is you're
> writing an important program that /will be attacked/ in these horrible
> ways, such that you can't even leave secrets lying around in your own
> process's address space, and then secure_memset won't help because it
> doesn't stop all these other channels; your only sensible approach is to
> work very carefully with extremely low-level code. Case 2 is you're
> /not/ writing that kind of program, and then secure_memset won't help
> because you haven't got that problem to begin with. Either way, it
> doesn't help you, so there's no point in standardizing it."
> But I guess WG14 wasn't swayed by the Con arguments, because
> `memset_explicit` is in C23 for real
> <https://en.cppreference.com/w/c/string/byte/memset>. The entire formal
> wording is as follows:
> The memset_explicit function copies the value of c (converted to an
> unsigned char) into each of the first n characters of the object
> pointed to by s. The purpose of this function is to make sensitive
> information stored in the object inaccessible. [Footnote: The
> intention is that the memory store is always performed (i.e. never
> elided), regardless of optimizations. This is in contrast to calls
> to the memset function. —end footnote]
> Your proposed feature is shaped more like "protection from reads from
> within the same process," which I don't even understand what that would
> mean, really; but you should definitely at least read and
> study-the-history-of the `secure_clear` proposal. The discussions
> (including on the SG14 list) will hit a lot of the same points as they
> would for your proposal.
> HTH,
> Arthur

Received on 2024-03-01 22:23:08