|
|
Subscribe / Log in / New account

Support for Intel's Linear Address Masking

By Jonathan Corbet
July 25, 2022
A 64-bit pointer can address a lot of memory — far more than just about any application could ever need. As a result, there are bits within that pointer that are not really needed to address memory, and which might be put to other needs. Storing a few bits of metadata within a pointer is a common enough use case that multiple architectures are adding support for it at the hardware level. Intel is no exception; support for its "Linear Address Masking" (LAM) feature has been slowly making its way toward the mainline kernel.

CPUs can support this metadata by simply masking off the relevant bits before dereferencing a pointer. Naturally, every CPU vendor has managed to support this feature differently. Arm's top-byte ignore feature allows the most-significant byte of the address to be used for non-pointing purposes; it has been supported by the Linux kernel since 5.4 came out in 2019. AMD's "upper address ignore" feature, instead, only allows the seven topmost bits to be used in this way; support for this feature was proposed earlier this year but has not yet been accepted.

One of the roadblocks in the AMD case is that this feature would allow the creation of valid user-space pointers that have the most-significant bit set. In current kernels, only kernel-space addresses have that bit set, and an unknown amount of low-level code depends on that distinction. The consequences of confusing user-space and kernel-space addresses could be severe and contribute to the ongoing CVE-number shortage, so developers are nervous about any feature that could cause such confusion to happen. Quite a bit of code would likely have to be audited to create any level of confidence that allowing user-space addresses with that bit set would not open up a whole set of security holes.

Intel's LAM feature offers two modes, both of which are different from anybody else's:

  • LAM_U57 allows six bits of metadata in bits 62 to 57.
  • LAM_U48 allows 15 bits of metadata in bits 62 to 48.

It's worth noting that neither of these modes allows bit 63 (the most-significant bit) to be used for this purpose, so LAM avoids the pitfall that has created trouble for AMD.

Support for LAM is added by this patch set from Kirill Shutemov. Since LAM must be enabled in the CPU by privileged code, the patch set introduces a new API in the form of two new arch_prctl() commands that are designed to be able to support any CPU's pointer-metadata mechanism. The first, ARCH_ENABLE_TAGGED_ADDR, enables the use of LAM for the current process; it takes an integer argument indicating how many bits of data the process wishes to store in pointers and selects the mode (from the above set) that holds at least that many.

Programs trying to use this feature need to know where they can store their metadata within a pointer; this needs to happen in a general way if such programs are to be portable across architectures. The second arch_prctl() operation, ARCH_GET_UNTAG_MASK, returns a 64-bit value with bits set to indicate the available space. The patch set also adds a line to each process's arch_status file in /proc indicating the effective mask.

The LAM patches are, for the most part, uncontroversial; the LAM feature is seen as being better designed than AMD's equivalent. That said, there are some ongoing concerns about the LAM_U48 mode in particular that may prevent it from being supported in Linux anytime soon.

Linux has supported five-level page tables on x86 systems since the 4.11 release in 2017. On a system with five-level page tables enabled, 57 bits of address space are available to running processes. The kernel will not normally map memory into the upper nine bits of that address space, which is the part added by the fifth page-table level, out of fear of breaking applications; among other things, some programs may be storing metadata in those bits even without hardware support. More care must be taken when applying this trick since the metadata bits must always be masked out before dereferencing a pointer, but it is possible. Programs that do this would obviously break, though, if those bits became necessary to address memory within their address space.

To avoid this kind of problem, the kernel will only map memory into the upper part of the address space if the application explicitly asks for it in an mmap() call. It's a rare application that will need to do that, and should be a relatively easy thing to add in cases where it's necessary.

The LAM_U48 mode, which uses 15 pointer bits and only leaves 48 significant bits for the actual address, is clearly inconsistent with any attempt to use a 57-bit address space. One might argue that any programmer who tries to use both together deserves the resulting explosions, but it is better to simply not provide useless footguns whenever possible. Since the kernel already plays a role in the use of both modes, it is well placed to ensure that they are not used together.

In Shutemov's patch set, the enabling of LAM_U48 is relegated to a set of optional patches at the end; if they are left out, the kernel will only support the LAM_U57 mode, which is certainly one way to solve the problem. If the patches are included, instead, then user space must choose which of the two features it will use (if either); the mode that is selected first wins. If LAM_U48 is enabled, the ability to map memory in the upper nine bits of the address space will be permanently removed from that process. But if the process has already mapped memory there when it tries to enable LAM_U48, the attempt will fail.

It seems like a reasonable solution that would make all of the functionality available and let processes choose which they will actually use, but developers remain concerned about the LAM_U48 mode. Alexander Potapenko suggested that distributors would want to remove this mode if it makes it into the mainline, but that it would become harder to do so over time as other changes land on top of it. Dave Hansen, one of the x86 maintainers, said that he would not merge LAM_U48 immediately, but would consider doing so in the future.

So, while there does not seem to be much to impede the adoption of LAM in general, it is not clear that all of the LAM patches will be merged anytime soon. If there are people with use cases for LAM_U48 out there, this might be a good time to make those use cases known; otherwise they may find that the feature is unavailable to them.

Index entries for this article
KernelArchitectures/x86


to post comments

Support for Intel's Linear Address Masking

Posted Jul 26, 2022 0:13 UTC (Tue) by unixbhaskar (guest, #44758) [Link] (3 responses)

Well, a simple question, might sound useless to you, but still ..... are those LAM_U48 and LAM_U57 mutually exclusive?? That means whether the chosen option blocks others to assign in the same space, or does it cancel the precedence?

IOW, if the devs assign U48 in a space, they are not allowed to assign U57. Kinda hard restriction.

Reading the article and what I gather, which is not. Not sure I am getting the right vibes.

PS: If it does not make sense, it is my fault.

Support for Intel's Linear Address Masking

Posted Jul 26, 2022 9:27 UTC (Tue) by dottedmag (subscriber, #18590) [Link]

The problematic sequence is mmap(address in upper memory, ... MAP_FIXED) and then enable LAM_U48.

Support for Intel's Linear Address Masking

Posted Jul 26, 2022 10:36 UTC (Tue) by danielthompson (subscriber, #97243) [Link] (1 responses)

That are technically mutually exclusive or, more accurately, setting LAM_U57 causes the hardware ignore the LAM_U48 bit. Thus setting both bits will cause the processor to adopt LAM_U57.

LAM_U57 = 0 LAM_U48 = 0 -> No LAM
LAM_U57 = 0 LAM_U48 = 1 -> LAM_U48
LAM_U57 = 1 LAM_U48 = 0 -> LAM_U57
LAM_U57 = 1 LAM_U48 = 0 -> LAM_U57

However that rather overlooks the fact that LAM_U48 is a super-set of LAM_U57 meaning any LAM_U57 compatible pointer tagging could be used in either of the LAM modes.

Support for Intel's Linear Address Masking

Posted Jul 28, 2022 8:48 UTC (Thu) by epa (subscriber, #39769) [Link]

That seems like a misdesign by Intel. The combination (1, 1) ought to have been reserved for future use.

Support for Intel's Linear Address Masking

Posted Jul 27, 2022 4:45 UTC (Wed) by alison (subscriber, #63752) [Link] (1 responses)

Isn't the LAM_U57 vs. LAM_U48 conflict fully addressable with Kconfig? Kconfig is already full of conflicting options, so what is new here?

Support for Intel's Linear Address Masking

Posted Jul 27, 2022 8:32 UTC (Wed) by danielthompson (subscriber, #97243) [Link]

LAM_U57 isn't actually involved in the conflict at all. The conflict occurs when figuring out how to handle the existing 57-bit virtual addresses features alongside LAM_U48 (which only makes sense if you have 48-bit virtual addresses).

I'm not sure a Kconfig option would help much; it looks to me like the existing approach (of letting each process choose which feature they want) is significantly better than a config option since choosing per-process allows 57-bit VA and LAM_U48 processes to exist on the same kernel.

Support for Intel's Linear Address Masking

Posted Jul 30, 2022 18:46 UTC (Sat) by fratti (guest, #105722) [Link] (4 responses)

What are some of the uses for metadata in pointers? Hashes of the return address in indirect function calls or something like that?

Support for Intel's Linear Address Masking

Posted Jul 31, 2022 13:59 UTC (Sun) by NUXI (subscriber, #70138) [Link] (1 responses)

Support for Intel's Linear Address Masking

Posted Aug 7, 2022 22:24 UTC (Sun) by kiryl (subscriber, #41516) [Link]

Address space sanitizers wants the feature too.

Support for Intel's Linear Address Masking

Posted Aug 8, 2022 21:20 UTC (Mon) by rwmj (subscriber, #5474) [Link]

Tagged integers are fairly common in garbage collected languages. OCaml sets the least significant bit when storing (63 bit) integers, and leaves it clear for pointers. This has surprisingly small overhead when doing arithmetic because of various mathematical identities: https://rwmj.wordpress.com/2009/08/04/ocaml-internals/

I'm not actually sure if OCaml could use the Intel scheme however since it works in the "wrong" way.

Support for Intel's Linear Address Masking

Posted Jun 16, 2023 11:34 UTC (Fri) by tigerchen (guest, #165616) [Link]

> Hashes of the return address in indirect function calls or something like that?
We can't. The Intel PRM said "LAM doe not apply to addresses used for instruction fetches or to those that specify the targets of jump and call instructions."

what's the expected behavior is segmentation is enabled in 64bit mode?

Posted Sep 25, 2024 11:33 UTC (Wed) by stanpbk (guest, #173674) [Link]

Sorry to bother you guys, but i just cannot think this through:

since FS/GS could have a none-zero base, if a 64-bit pointer LinAddr = FS: EffAddr, how do we expect the masking behavior?
in certain case, LinAddr[63] could be affected by arithmetic operation of the metadata, which seems weird to me.
masking off the metadata before calculation is also improbable,since we cannot know the masking bits before figuring out LinAddr[63] first.

Does that means that when LAM enabled, or the segment base address must be zero? (in that case this feature should be just called as effective address masking)

other segment(-related) base address like IDTR/LDTR/GDTR may also suffer the same issue.


Copyright © 2022, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds