Live data from Hacker News

Memory Tagging and how it improves C/C++ memory safety

arxiv.org

21–30 of 41 posts

Re: Memory Tagging and how it improves C/C++ memory safety

#21

Earlier quoted context omitted.

> After skimming the paper, I think it's actually closer to segmentation. They just split the address space into X number of segments. The allocator then ensures every allocation lies completely within one of these segments and attaches that segment's ID to the returned pointer. It's sort of the other way around. Replacing "tags" with "colors" since somehow it seems a bit more intuitive, the allocator itself just "co…

Reading it again, I guess I missed the "shadow memory" concept they talked about, but they only mention it 5 times and none of those mentions are in the actually explanation of how they do the memory tagging. They do mention it one more time in the AArch64 implementation though, so it does look like you're correct on this. I don't understand why they didn't really make this detail much more clear though, since like y…

I dont understand the implication of why the kernel needs to be aware of the checking. the tag bits are architecturally ignored.

you can remove the restriction on the number of the colors by using valid upper virtual memory bits to denote type (bibop), as long as you know that the kernel hasnt put anything else there. maybe thats the kernel interaction you were thinking of?

Re: Memory Tagging and how it improves C/C++ memory safety

#22
post #9

A long time ago I found some memory problems in a C++ codebase we had inherited and that crashes from time. In Windows you can protect memory blocks with a function call so I overloaded new and malloc and added some protected blocks before and after the actual memory. Then we ran the code for a lot and it would fault right at the point of the memory overwrite instead of some place later. It made the code very slow bu…

We did the same thing for some device driver code and also use a tool called "Boundschecker", back in the 90s. I just checked and it still exists!

Re: Memory Tagging and how it improves C/C++ memory safety

#23

Earlier quoted context omitted.

> After skimming the paper, I think it's actually closer to segmentation. They just split the address space into X number of segments. The allocator then ensures every allocation lies completely within one of these segments and attaches that segment's ID to the returned pointer. It's sort of the other way around. Replacing "tags" with "colors" since somehow it seems a bit more intuitive, the allocator itself just "co…

Reading it again, I guess I missed the "shadow memory" concept they talked about, but they only mention it 5 times and none of those mentions are in the actually explanation of how they do the memory tagging. They do mention it one more time in the AArch64 implementation though, so it does look like you're correct on this. I don't understand why they didn't really make this detail much more clear though, since like y…

Yes, the memory->tag mapping has to be stored somewhere, but that's true even for a segmented system, right? You need some place to store the segment offset and length: either some dedicated registers if you only allow a few of them, or some in-memory tables for more general schemes, right?

Yeah they don't really get into how the shadow memory is managed. If you only had limited or no hardware support, it seems like it would be tricky, especially when you are arbitrarily mapping various chunks of the address space. The ideal for performance is that there is some straightforward relationship between a pointed-to region and the associated tag bits, e.g., just shift the pointer down by lg(TG) bits and then index into a single contiguous region which stores the tag bits, pointed to by some global.

That avoids the need to have any kind of page-table like structure, but it would waste a lot of virtual address space if the range of the pointers was very large or very sparse.

If you had hardware support though, maybe this problem goes away: the hardware could store the bits in "holes" right alongside the actual memory, as how ECC works (they suggest SPARC is doing this), or they could include the information in the TLB alongside the regular mappings (I guess this would need kernel support too).

I didn't see much about kernel-side checks in the paper? Maybe I missed it. The kernel already checks that user pointers are valid in the context of the process that provided them, but of course that is a very coarse check (can the user process as a whole read/write here?), and could still violate semantic memory safety of the process depending on what was passed.

Re: Memory Tagging and how it improves C/C++ memory safety

#24

Earlier quoted context omitted.

Reading it again, I guess I missed the "shadow memory" concept they talked about, but they only mention it 5 times and none of those mentions are in the actually explanation of how they do the memory tagging. They do mention it one more time in the AArch64 implementation though, so it does look like you're correct on this. I don't understand why they didn't really make this detail much more clear though, since like y…

I dont understand the implication of why the kernel needs to be aware of the checking. the tag bits are architecturally ignored. you can remove the restriction on the number of the colors by using valid upper virtual memory bits to denote type (bibop), as long as you know that the kernel hasnt put anything else there. maybe thats the kernel interaction you were thinking of?

I suppose that's what I get for skimming, this paper is a bit weird. I thought they were going to have the kernel check the tags of userspace pointers that are passed to it, because it includes this line in regards to ASAN:

    Does not currently detect when the kernel accesses invalid user-space memory
But after reading the paper again it looks like they never bring this up again so ¯\_(ツ)_/¯

Re: Memory Tagging and how it improves C/C++ memory safety

#25

Earlier quoted context omitted.

I dont understand the implication of why the kernel needs to be aware of the checking. the tag bits are architecturally ignored. you can remove the restriction on the number of the colors by using valid upper virtual memory bits to denote type (bibop), as long as you know that the kernel hasnt put anything else there. maybe thats the kernel interaction you were thinking of?

I suppose that's what I get for skimming, this paper is a bit weird. I thought they were going to have the kernel check the tags of userspace pointers that are passed to it, because it includes this line in regards to ASAN: Does not currently detect when the kernel accesses invalid user-space memory But after reading the paper again it looks like they never bring this up again so ¯\_(ツ)_/¯

Yeah they aren't clear about it, but I guess the idea is in a hardware supported model with memory tagging you'd presumably get kernel (and more generally "cross process") checking kind of for free since the checks would be pervasive and hardware enforced.

With the software only solution, it's essentially just a variation on ASAN: with the trick that you use some pointer bits to additionally detect some cases that ASAN can't (because ASAN doesn't care about the origin/formation of the pointer: only whether the access is allowed).

Re: Memory Tagging and how it improves C/C++ memory safety

#26
It seems pretty weird for me that a paper submitted in 2018 doesn't mention Intel's MPX (https://en.wikipedia.org/wiki/Intel_MPX), which is pretty much tackling exactly the same problem, in hardware (and requiring software cooperation).

I'm not taking (yet) a position on the relative merits of the bounds-register based MPX approach versus the tagged pointer one presented here, but the comparison should at least be made if at least only to explain why MT would be successful in contrast (MPX has hardly taken the world by storm).

Also, since they appear to be positioning this as something that could be fast enough to run in production (with hardware assist), they should at least take a shot at analyzing the attack surface presented by the probabilistic protection: a figure like 99.6% chance of catching a rogue access makes sense for testing scenarios, but if the adversary is an attacker, can they manipulate those odds to their advantage? The exact tag allocation mechanism becomes pretty important in this case.

Re: Memory Tagging and how it improves C/C++ memory safety

#27

Earlier quoted context omitted.

Reading it again, I guess I missed the "shadow memory" concept they talked about, but they only mention it 5 times and none of those mentions are in the actually explanation of how they do the memory tagging. They do mention it one more time in the AArch64 implementation though, so it does look like you're correct on this. I don't understand why they didn't really make this detail much more clear though, since like y…

Yes, the memory->tag mapping has to be stored somewhere, but that's true even for a segmented system, right? You need some place to store the segment offset and length: either some dedicated registers if you only allow a few of them, or some in-memory tables for more general schemes, right? Yeah they don't really get into how the shadow memory is managed. If you only had limited or no hardware support, it seems like…

> Yes, the memory->tag mapping has to be stored somewhere, but that's true even for a segmented system, right? You need some place to store the segment offset and length: either some dedicated registers if you only allow a few of them, or some in-memory tables for more general schemes, right?

Not if your segments/tags are static and defined beforehand, which is what I thought that were going for (Since that doesn't require any extra memory). But obviously that approach is pretty limited, which was my thinking.

> Yeah they don't really get into how the shadow memory is managed. If you only had limited or no hardware support, it seems like it would be tricky, especially when you are arbitrarily mapping various chunks of the address space. The ideal for performance is that there is some straightforward relationship between a pointed-to region and the associated tag bits, e.g., just shift the pointer down by lg(TG) bits and then index into a single contiguous region which stores the tag bits, pointed to by some global.

This is exactly what I'm thinking as well. If the platform has paging support, in theory this is cheaper then it seems because (besides using up tons of virtual memory) the array can be sparsely allocated, with only the regions actually in used taking up physical memory. But 64bytes is still really coarse, it might be necessary to use a multi-level approach to make the size a bit saner. But since it is just virtual memory, depending on the architecture it may not matter.

Storing it in the page table mappings themselves is an interesting idea. Of course, some architectures have more 'free' space in there then others. And at that point you're talking about likely 4K granularity, not 64 bytes. Still better then nothing of course, but it would definitely decrease the effectiveness for smaller objects.

> I didn't see much about kernel-side checks in the paper? Maybe I missed it. The kernel already checks that user pointers are valid in the context of the process that provided them, but of course that is a very coarse check (can the user process as a whole read/write here?), and could still violate semantic memory safety of the process depending on what was passed.

Someone else asked about this as well, it seems I was led astray. The paper has this line about ASAN:

    Does not currently detect when the kernel accesses invalid user-space memory
From reading that, I thought they were then going to use their memory tagging system to do such checking (And in theory you could do it as long as the kernel knew about the mappings). But they never actually bring this up again in the paper.

Re: Memory Tagging and how it improves C/C++ memory safety

#28
post #9

A long time ago I found some memory problems in a C++ codebase we had inherited and that crashes from time. In Windows you can protect memory blocks with a function call so I overloaded new and malloc and added some protected blocks before and after the actual memory. Then we ran the code for a lot and it would fault right at the point of the memory overwrite instead of some place later. It made the code very slow bu…

These days the gcc and clang memory/address sanitizers can do this quite nicely, and they tend to have low overhead as well (in my limited experience so far).

When running a test suite at work with ASan + UBsan turned on, the test goes from taking ~30 seconds to ~20 minutes. So there's certainly some pathological cases.

Re: Memory Tagging and how it improves C/C++ memory safety

#29
post #28

Earlier quoted context omitted.

These days the gcc and clang memory/address sanitizers can do this quite nicely, and they tend to have low overhead as well (in my limited experience so far).

When running a test suite at work with ASan + UBsan turned on, the test goes from taking ~30 seconds to ~20 minutes. So there's certainly some pathological cases.

Try it with just ASan. Some of the UBsan checks can be quite expensive.

Also, check how much free ram your computer has when running with ASan. It may be running out of RAM, and e.g. spending a lot of time looking for other memory to free, or even swapping.

Re: Memory Tagging and how it improves C/C++ memory safety

#30

Earlier quoted context omitted.

Yes, the memory->tag mapping has to be stored somewhere, but that's true even for a segmented system, right? You need some place to store the segment offset and length: either some dedicated registers if you only allow a few of them, or some in-memory tables for more general schemes, right? Yeah they don't really get into how the shadow memory is managed. If you only had limited or no hardware support, it seems like…

> Yes, the memory->tag mapping has to be stored somewhere, but that's true even for a segmented system, right? You need some place to store the segment offset and length: either some dedicated registers if you only allow a few of them, or some in-memory tables for more general schemes, right? Not if your segments/tags are static and defined beforehand, which is what I thought that were going for (Since that doesn't r…

> This is exactly what I'm thinking as well. If the platform has paging support, in theory this is cheaper then it seems because (besides using up tons of virtual memory) the array can be sparsely allocated, with only the regions actually in used taking up physical memory.

Yes exactly. The worse case still seems like a doubling of (actual) memory use though: imagine a very sparsely accessed region of memory: even today each access would bring in a whole 4K page (on x86, for example), but now you'd bring in a whole 4K shadow page as well (yes, the access has to be really sparse to get this 1:1 ratio).

> And at that point you're talking about likely 4K granularity, not 64 bytes. Still better then nothing of course, but it would definitely decrease the effectiveness for smaller objects.

I think a 4K granularity is next to useless - you already get that from the hardware/OS paging support. If you want to detect problems on a 4K level, you only need to change your allocator to mmap in a page at a time, which you can even already do on some with tunable ones.

Post reply on HN