diff mbox series

[RFC,v2,18/27] arm64: mte: Reserve tag block for the zero page

Message ID 20231119165721.9849-19-alexandru.elisei@arm.com (mailing list archive)
State Handled Elsewhere
Headers show
Series [RFC,v2,01/27] arm64: mte: Rework naming for tag manipulation functions | expand

Commit Message

Alexandru Elisei Nov. 19, 2023, 4:57 p.m. UTC
On arm64, the zero page receives special treatment by having the tagged
flag set on MTE initialization, not when the page is mapped in a process
address space. Reserve the corresponding tag block when tag storage
management is being activated.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---
 arch/arm64/kernel/mte_tag_storage.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

David Hildenbrand Nov. 28, 2023, 5:06 p.m. UTC | #1
On 19.11.23 17:57, Alexandru Elisei wrote:
> On arm64, the zero page receives special treatment by having the tagged
> flag set on MTE initialization, not when the page is mapped in a process
> address space. Reserve the corresponding tag block when tag storage
> management is being activated.

Out of curiosity: why does the shared zeropage require tagged storage? 
What about the huge zeropage?
Alexandru Elisei Nov. 29, 2023, 11:30 a.m. UTC | #2
On Tue, Nov 28, 2023 at 06:06:54PM +0100, David Hildenbrand wrote:
> On 19.11.23 17:57, Alexandru Elisei wrote:
> > On arm64, the zero page receives special treatment by having the tagged
> > flag set on MTE initialization, not when the page is mapped in a process
> > address space. Reserve the corresponding tag block when tag storage
> > management is being activated.
> 
> Out of curiosity: why does the shared zeropage require tagged storage? What
> about the huge zeropage?

There are two different tags that are used for tag checking: the logical
tag, the tag embedded in bits 59:56 of an address, and the physical tag
corresponding to the address. This tag is stored in a separate memory
location, called tag storage. When an access is performed, hardware
compares the logical tag (from the address) with the physical tag (from the
tag storage). If they match, the access is permitted.

The physical tag is set with special instructions.

Userspace pointers have bits 59:56 zero. If the pointer is in a VMA with
MTE enabled, then for userspace to be able to access this address, the
physical tag must also be 0b0000.

To make it easier on userspace, when a page is first mapped as tagged, its
tags are cleared by the kernel; this way, userspace can access the address
immediately, without clearing the physical tags beforehand. Another reason
for clearing the physical tags when a page is mapped as tagged would be to
avoid leaking uninitialized tags to userspace.

The zero page is special, because the physical tags are not zeroed every
time the page is mapped in a process; instead, the zero page is marked as
tagged (by setting a page flag) and the physical tags are zeroed only once,
when MTE is enabled at boot.

All of this means that when tag storage is enabled, which happens after MTE
is enabled, the tag storage corresponding to the zero page is already in
use and must be rezerved, and it can never be used for data allocations.

I hope all of the above makes sense. I can also put it in the commit
message :)

As for the zero huge page, the MTE code in the kernel treats it like a
regular page, and it zeroes the tags when it is mapped as tagged in a
process. I agree that this might not be the best solution from a
performance perspective, but it has worked so far.

With tag storage management enabled, set_pte_at()->mte_sync_tags() will
discover that the huge zero page doesn't have tag storage reserved, the
table entry will be mapped as invalid to use the page fault-on-access
mechanism that I introduce later in the series [1] to reserve tag storage,
and after that set_pte_at() will zero the physical tags.

[1] https://lore.kernel.org/all/20231119165721.9849-20-alexandru.elisei@arm.com/

Thanks,
Alex

> 
> -- 
> Cheers,
> 
> David / dhildenb
>
David Hildenbrand Nov. 29, 2023, 1:13 p.m. UTC | #3
On 29.11.23 12:30, Alexandru Elisei wrote:
> On Tue, Nov 28, 2023 at 06:06:54PM +0100, David Hildenbrand wrote:
>> On 19.11.23 17:57, Alexandru Elisei wrote:
>>> On arm64, the zero page receives special treatment by having the tagged
>>> flag set on MTE initialization, not when the page is mapped in a process
>>> address space. Reserve the corresponding tag block when tag storage
>>> management is being activated.
>>
>> Out of curiosity: why does the shared zeropage require tagged storage? What
>> about the huge zeropage?
> 
> There are two different tags that are used for tag checking: the logical
> tag, the tag embedded in bits 59:56 of an address, and the physical tag
> corresponding to the address. This tag is stored in a separate memory
> location, called tag storage. When an access is performed, hardware
> compares the logical tag (from the address) with the physical tag (from the
> tag storage). If they match, the access is permitted.

Ack, matches my understanding.

> 
> The physical tag is set with special instructions.
> 
> Userspace pointers have bits 59:56 zero. If the pointer is in a VMA with
> MTE enabled, then for userspace to be able to access this address, the
> physical tag must also be 0b0000.
> 
> To make it easier on userspace, when a page is first mapped as tagged, its
> tags are cleared by the kernel; this way, userspace can access the address
> immediately, without clearing the physical tags beforehand. Another reason
> for clearing the physical tags when a page is mapped as tagged would be to
> avoid leaking uninitialized tags to userspace.

Make sense. Zero it just like we zero page content.

> 
> The zero page is special, because the physical tags are not zeroed every
> time the page is mapped in a process; instead, the zero page is marked as
> tagged (by setting a page flag) and the physical tags are zeroed only once,
> when MTE is enabled at boot.

Makes sense.

> 
> All of this means that when tag storage is enabled, which happens after MTE
> is enabled, the tag storage corresponding to the zero page is already in
> use and must be rezerved, and it can never be used for data allocations.
> 
> I hope all of the above makes sense. I can also put it in the commit
> message :)

Yes, makes sense!

> 
> As for the zero huge page, the MTE code in the kernel treats it like a
> regular page, and it zeroes the tags when it is mapped as tagged in a
> process. I agree that this might not be the best solution from a
> performance perspective, but it has worked so far.

What if user space were to change the tag of that shared resource?

Having a tag != 0 doesn't make sense for such a shared resource, so I 
suspect modifying the tag is like a write event: trigger write-fault -> COW.

> 
> With tag storage management enabled, set_pte_at()->mte_sync_tags() will
> discover that the huge zero page doesn't have tag storage reserved, the
> table entry will be mapped as invalid to use the page fault-on-access
> mechanism that I introduce later in the series [1] to reserve tag storage,

I assume (without looking at the code) that you took proper care of 
possible races.

Thanks for goind into detail!
Alexandru Elisei Nov. 29, 2023, 1:41 p.m. UTC | #4
Hi,

On Wed, Nov 29, 2023 at 02:13:50PM +0100, David Hildenbrand wrote:
> On 29.11.23 12:30, Alexandru Elisei wrote:
> > On Tue, Nov 28, 2023 at 06:06:54PM +0100, David Hildenbrand wrote:
> > > On 19.11.23 17:57, Alexandru Elisei wrote:
> > > > On arm64, the zero page receives special treatment by having the tagged
> > > > flag set on MTE initialization, not when the page is mapped in a process
> > > > address space. Reserve the corresponding tag block when tag storage
> > > > management is being activated.
> > > 
> > > Out of curiosity: why does the shared zeropage require tagged storage? What
> > > about the huge zeropage?
> > 
> > There are two different tags that are used for tag checking: the logical
> > tag, the tag embedded in bits 59:56 of an address, and the physical tag
> > corresponding to the address. This tag is stored in a separate memory
> > location, called tag storage. When an access is performed, hardware
> > compares the logical tag (from the address) with the physical tag (from the
> > tag storage). If they match, the access is permitted.
> 
> Ack, matches my understanding.
> 
> > 
> > The physical tag is set with special instructions.
> > 
> > Userspace pointers have bits 59:56 zero. If the pointer is in a VMA with
> > MTE enabled, then for userspace to be able to access this address, the
> > physical tag must also be 0b0000.
> > 
> > To make it easier on userspace, when a page is first mapped as tagged, its
> > tags are cleared by the kernel; this way, userspace can access the address
> > immediately, without clearing the physical tags beforehand. Another reason
> > for clearing the physical tags when a page is mapped as tagged would be to
> > avoid leaking uninitialized tags to userspace.
> 
> Make sense. Zero it just like we zero page content.
> 
> > 
> > The zero page is special, because the physical tags are not zeroed every
> > time the page is mapped in a process; instead, the zero page is marked as
> > tagged (by setting a page flag) and the physical tags are zeroed only once,
> > when MTE is enabled at boot.
> 
> Makes sense.
> 
> > 
> > All of this means that when tag storage is enabled, which happens after MTE
> > is enabled, the tag storage corresponding to the zero page is already in
> > use and must be rezerved, and it can never be used for data allocations.
> > 
> > I hope all of the above makes sense. I can also put it in the commit
> > message :)
> 
> Yes, makes sense!
> 
> > 
> > As for the zero huge page, the MTE code in the kernel treats it like a
> > regular page, and it zeroes the tags when it is mapped as tagged in a
> > process. I agree that this might not be the best solution from a
> > performance perspective, but it has worked so far.
> 
> What if user space were to change the tag of that shared resource?
> 
> Having a tag != 0 doesn't make sense for such a shared resource, so I
> suspect modifying the tag is like a write event: trigger write-fault -> COW.

Yes, modifying the tag is a write event.

> 
> > 
> > With tag storage management enabled, set_pte_at()->mte_sync_tags() will
> > discover that the huge zero page doesn't have tag storage reserved, the
> > table entry will be mapped as invalid to use the page fault-on-access
> > mechanism that I introduce later in the series [1] to reserve tag storage,
> 
> I assume (without looking at the code) that you took proper care of possible
> races.
> 
> Thanks for goind into detail!

No problem.

Alex

> 
> 
> -- 
> Cheers,
> 
> David / dhildenb
>
diff mbox series

Patch

diff --git a/arch/arm64/kernel/mte_tag_storage.c b/arch/arm64/kernel/mte_tag_storage.c
index 833480048170..a1cc239f7211 100644
--- a/arch/arm64/kernel/mte_tag_storage.c
+++ b/arch/arm64/kernel/mte_tag_storage.c
@@ -393,6 +393,8 @@  static int __init mte_tag_storage_activate_regions(void)
 		totalcma_pages += range_len(tag_range);
 	}
 
+	reserve_tag_storage(ZERO_PAGE(0), 0, GFP_HIGHUSER_MOVABLE);
+
 	return 0;
 
 out_disabled: