-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
arch/arm64: Armv8 MTE - Memory Tagging Extensions #458
Conversation
@marcrittinghaus, @skuenzer I would like your comments on this one, especially in the topics below. The changes in the allocator: These somewhat relate to the discussion in #191 on whether we should add a wrapper around alloc for these things. My understanding is that this would help with any allocators provided by Unikraft, but not with allocators in external implementations of libc (newlib / musl). The other option is to instrument the allocator's implementation. This has the drawback that some work needs to be duplicated for every allocator, but also benefits in performance, as you can optimize The implementation of asynchronous TCF reporting: My implementation comes with a penalty of one register check per IRQ. IIRC linux checks the TFSR on task switch, thread switch, and when swicthing between EL0 and EL1. We don't have most of these choices on Unikraft, so IRQ is one of our few choices. If people find this an issue, and would rather check in other places (say in the scheduler), we can make checks in IRQ optional and provide alternatives via KConfig. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @michpappas,
I did an initial pass over this PR and it looks pretty ok, I left some comments.
One thing that bothers me a bit is the the overall spam of ifdef/endif
guards.
Unfortunately I'm not sure if there is a better way to this, as the protected code is pretty small and non-repetitive so I'm not sure if it can be abstracted.
Other than this, the PR looks okay! I'll try it out after the RNG PR is in.
I'll let @skuenzer now give his input on this.
Cezar
I'll go ahead and test it again, just to make sure Edit: Still works like a charm 🥇 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michpappas Thanks for putting the extra effort into this!
- Now we arch/arm64/include/uk/asm/memtag.h includes
errno.h
forukarch_memtag_ini()
to return-ENOTSUP
as you requested on your previous comment.
Ok, no problem. We discuss the introduction of an uk/errno.h
also for the code conventions and can adapt later if needed.
- I left handling of asynchronous reporting out of
ukarch_memtag
, and only conditional to MTE.
Yes, makes sense 👍🏻
- In theory ukalloc could be changed to have all memory tagging operations unconditional, and have
ukarch_memtag
stub them out if memory tagging is not supported, or not enabled. Not sure if that's what you had in mind. Saying that, all this is subject to change anyway, as we need a common memory tagging library that will use KASAN if a hardware implementation is not available (in linux MTE is also part of the KASAN subsystem as "hardware KASAN"). Also see that the changes inalloc.c
for KASAN are very close to MTE. All this was dicussed during the security workshop in Sinaia, yet I would rather get this PR merged first and work with @vladandrew towards thelibmemtag
as KASAN gets on the way to be merged on 0.12, rather going over endless iterations of reworks here. CC: @hlef
Yes, when I wrote the comment, I had in mind to avoid #ifdefs
where possible to reduce code clutter. I wasn't aware of the planned integration with KASAN to be honest as I am not reviewing that PR and not really wrapped my head around it that much 🙈, but it totally makes sense 👍🏻 Nevertheless, I think it is cleaner now. Just like with the random API you can now use a common ukarch
API in KASAN to use HW features if available. So at least it will make KASAN cleaner in the end 😃 Thanks for making the changes 🙏🏻
@craciunoiuc Thanks for checking it out!
03f6180
to
059fbcf
Compare
Yes exactly, the moving to ukarch is not wasted, it should had been done anyway, the only part subject to changes is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go ahead and add the review tag, as we are nearing the release.
Reviewed-by: Cezar Craciunoiu cezar.craciunoiu@unikraft.io
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michpappas: Just saw that you have to remove the commits from #434 (I think they are not the newest, too). We can then merge #434 first and then merge this one.
This commit introduces a minimal subsystem for memory tagging. Memory tagging provides protection against memory safety violations, by restricting pointer access to predefined memory regions. Implementations tag memory regions and pointers to these regions, and check for tag match upon access. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
Move system and io register helpers from plat/common/include to arch/arm/arm64 to make them accessible to ukarch functions. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
This commit implements the ukarch_memtag API for arm64-based platforms using the Memory Tagging Extensions (FEAT_MTE) of Armv8. It introduces: * A new configuration option to enable MTE (CONFIG_ARM64_FEAT_MTE). * A new memory type for tagged memory. This is set as the default type of Normal Memory when MTE is enabled. * A new header under arch/arm/arm64/ with primitives for generating, storing and loading tags. Currently only loads / stores of allocations to granule is supported (LDG / SDG). Additional functionality such as store allocation tag with zeroing (SDGZ), store allocation tag for blocks (SDGM), etc is not implemented. * A new configuration option to enable memory tagging, and additional options to control tag check fault reporting (CONFIG_ARM64_FEAT_MTE_TCF_[SYNC,ASYNC,ASYMMETRIC]). * A check in the IRQ vector to check for accumulated errors when tag check fault reporting is set to Async or Asymmetric. FEAT_MTE is introduced as an OPTIONAL feature in Armv8.5. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
This commit updates ukalloc with basic support for memory tagging. Specifically it adds a new `size` field to ifpages metadata in order to track the requested allocation size. uk_malloc_ifpages(), and uk_realloc_freepages() are instrumented to tag the requested region and return a tagged pointer. Tagging is applied to the size requested by the caller (aligned to the tag granule) excluding metadata and additionally allocated memory to page size. uk_free_ifpages() is updated to tag the freed region with a new tag, to prevent use-after-free. The implementation is simple, as it does not implement optimizations based on MTE features such as store allocation with zeroing, store allocation tags for blocks, etc. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
Enable memory tagging on boot and mark the heap as tagged memory. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm>
059fbcf
to
7d5e203
Compare
Rebased from |
Beep boop! I ran Unikraft's
Truncated logs starting from first warning e5d07fb:
View complete logs | Learn more about Unikraft's coding style and contribution guidelines. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @michpappas!
Approved-by: Marc Rittinghaus marc.rittinghaus@unikraft.io
Move system and io register helpers from plat/common/include to arch/arm/arm64 to make them accessible to ukarch functions. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: #458
This commit implements the ukarch_memtag API for arm64-based platforms using the Memory Tagging Extensions (FEAT_MTE) of Armv8. It introduces: * A new configuration option to enable MTE (CONFIG_ARM64_FEAT_MTE). * A new memory type for tagged memory. This is set as the default type of Normal Memory when MTE is enabled. * A new header under arch/arm/arm64/ with primitives for generating, storing and loading tags. Currently only loads / stores of allocations to granule is supported (LDG / SDG). Additional functionality such as store allocation tag with zeroing (SDGZ), store allocation tag for blocks (SDGM), etc is not implemented. * A new configuration option to enable memory tagging, and additional options to control tag check fault reporting (CONFIG_ARM64_FEAT_MTE_TCF_[SYNC,ASYNC,ASYMMETRIC]). * A check in the IRQ vector to check for accumulated errors when tag check fault reporting is set to Async or Asymmetric. FEAT_MTE is introduced as an OPTIONAL feature in Armv8.5. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: #458
This commit updates ukalloc with basic support for memory tagging. Specifically it adds a new `size` field to ifpages metadata in order to track the requested allocation size. uk_malloc_ifpages(), and uk_realloc_freepages() are instrumented to tag the requested region and return a tagged pointer. Tagging is applied to the size requested by the caller (aligned to the tag granule) excluding metadata and additionally allocated memory to page size. uk_free_ifpages() is updated to tag the freed region with a new tag, to prevent use-after-free. The implementation is simple, as it does not implement optimizations based on MTE features such as store allocation with zeroing, store allocation tags for blocks, etc. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: #458
Enable memory tagging on boot and mark the heap as tagged memory. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: #458
This commit introduces a minimal subsystem for memory tagging. Memory tagging provides protection against memory safety violations, by restricting pointer access to predefined memory regions. Implementations tag memory regions and pointers to these regions, and check for tag match upon access. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: unikraft#458
Move system and io register helpers from plat/common/include to arch/arm/arm64 to make them accessible to ukarch functions. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: unikraft#458
This commit implements the ukarch_memtag API for arm64-based platforms using the Memory Tagging Extensions (FEAT_MTE) of Armv8. It introduces: * A new configuration option to enable MTE (CONFIG_ARM64_FEAT_MTE). * A new memory type for tagged memory. This is set as the default type of Normal Memory when MTE is enabled. * A new header under arch/arm/arm64/ with primitives for generating, storing and loading tags. Currently only loads / stores of allocations to granule is supported (LDG / SDG). Additional functionality such as store allocation tag with zeroing (SDGZ), store allocation tag for blocks (SDGM), etc is not implemented. * A new configuration option to enable memory tagging, and additional options to control tag check fault reporting (CONFIG_ARM64_FEAT_MTE_TCF_[SYNC,ASYNC,ASYMMETRIC]). * A check in the IRQ vector to check for accumulated errors when tag check fault reporting is set to Async or Asymmetric. FEAT_MTE is introduced as an OPTIONAL feature in Armv8.5. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: unikraft#458
This commit updates ukalloc with basic support for memory tagging. Specifically it adds a new `size` field to ifpages metadata in order to track the requested allocation size. uk_malloc_ifpages(), and uk_realloc_freepages() are instrumented to tag the requested region and return a tagged pointer. Tagging is applied to the size requested by the caller (aligned to the tag granule) excluding metadata and additionally allocated memory to page size. uk_free_ifpages() is updated to tag the freed region with a new tag, to prevent use-after-free. The implementation is simple, as it does not implement optimizations based on MTE features such as store allocation with zeroing, store allocation tags for blocks, etc. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: unikraft#458
Enable memory tagging on boot and mark the heap as tagged memory. Signed-off-by: Michalis Pappas <mpappas@fastmail.fm> Reviewed-by: Cezar Craciunoiu <cezar.craciunoiu@unikraft.io> Approved-by: Marc Rittinghaus <marc.rittinghaus@unikraft.io> Tested-by: Unikraft CI <monkey@unikraft.io> GitHub-Closes: unikraft#458
Prerequisite checklist
checkpatch.pl
on your commit series before opening this PR;Base target
Additional configuration
Description of changes
Memory tagging is a hardware protection against memory safety violations in the scope of both spatial (eg buffer overflows) and temporal (eg use-after-free) safety.
The idea behind MTE is to restrict pointer access to predefined blocks of memory. This is done by tagging memory regions and pointers, and check for match upon access. A mismatch generates a Tag Check Fault (TCF). Specifically, the architecture introduces the concepts of:
DEFINED memory space that is logically different from the Data PA Space.
Combined together, these ensure that only memory within a given block is accessed. For instance, in the case of a buffer overflow, memory access outside the allocated bufer will cause a tag mismatch. Similarly, assuming that freeing memory re-tags the freed region, a use-after-free attempt will also cause a tag mismatch. Other accesses like prefetches, cache maintenance, translation table walks, accesses to the tag PA space, etc are always tag unchecked.
MTE requires support from the operating system. For example, addresses returned by malloc() must be tagged. Notice that the tags are only 4-bits wide, ie tags can have 16 possible values. Consequently, the same tag may be used on different regions on a given time, or that a region may have different tag values during time.
Architecture support
Armv8.5 introduces Memory Tagging as an OPTIONAL feature, through:
Armv8.7 makes FEAT_MTE3 a mandatory when FEAT_MTE2 is implemented.
Compiler support
GCC-9
Introduces initial MTE support with march=armv8.5-a+memtag. According to the GCC docs,
"This option is only to enable the extension at the assembler level and does not affect code generation".
GCC-10
Introduces MTE heap tagging support. The 'memtag' option enables memory tagging intrinsics.
At the time of writing, MTE stack tagging is not yet supported.
Hardware Support
None. At the time of writing MTE is only known to be implemented in QEMU, and in Arm FVP.Lately vendor support for MTE has started to appear on the news. Notable examples include the DSU-110 DynamIQ cluster from Arm for Armv9, and Samsung's Exynos 2200.
Changes introduced in this series
This PR implements basic MTE support for arm64-based platforms, with the following changes:
ldg
/sdg
). Additional functionality such as store allocation tag with zeroing (sdgz
), store allocation tag for blocks (sdgm
), etc is not implemented.CONFIG_ARM64_FEAT_MTE_TCF_[SYNC,ASYNC,ASYMMETRIC]
).An additional commit demonstrates how an allocator can be modified to support MTE, by introducing instrumentation to
ukalloc
. This is a fairly simple implementation that tags memory onuk_malloc_ifpages()
,uk_free_ifpages()
, anduk_posix_memalign_ifpages()
. The region tagged is equal to the size requested by the user aligned to the MTE granule, ie 16 bytes. Any attempt to access memory outside that region, including allocation metadata, will cause a fault.Resources