Skip to contentSkip to conversation

arm64/mm: A fix and a documentation bit for change_memory_common()

PATCH Applied Dev Jain 5 participants 16 messages Nov 12, 2025 – Nov 28, 2025 arm64

lore
Share & tools
lore

Dev Jain

author
#0 lore raw

cover arm64/mm: A fix and a documentation bit for change_memory_common()

The first patch is a fix to prevent suppression of error encountered during linear map alias permission change. This is needed because the rodata=on security measure requires us to proceed only if we first do the linear map alias protection change.

The second patch documents why linear map split failure during the vfreeing path isn't problematic.

Dev Jain (2):
arm64/pageattr: Propagate return value from __change_memory_common arm64/mm: Document why linear map split failure upon vm_reset_perms is
not problematic

 arch/arm64/mm/pageattr.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
Signature · 1 line
2.30.2
author
#1 lore raw

PATCH 1/2 arm64/pageattr: Propagate return value from __change_memory_common

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

---
v1 of this patch: https://lore.kernel.org/all/[email protected]/
I have dropped stable since no real chance of failure was there.

 arch/arm64/mm/pageattr.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/arm64/mm/pageattr.c +4 -1
index 5135f2d66958..b4ea86cd3a71 100644
@@ -148,6 +148,7 @@ static int change_memory_common(unsigned long addr, int numpages,
 	unsigned long size = PAGE_SIZE * numpages;
 	unsigned long end = start + size;
 	struct vm_struct *area;
+	int ret;
 	int i;
 
 	if (!PAGE_ALIGNED(addr)) {
@@ -185,8 +186,10 @@ static int change_memory_common(unsigned long addr, int numpages,
 	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
 			    pgprot_val(clear_mask) == PTE_RDONLY)) {
 		for (i = 0; i < area->nr_pages; i++) {
-			__change_memory_common((u64)page_address(area->pages[i]),
+			ret = __change_memory_common((u64)page_address(area->pages[i]),
 					       PAGE_SIZE, set_mask, clear_mask);
+			if (ret)
+				return ret;
 		}
 	}
 
Signature · 1 line
2.30.2
#2 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 10 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

Thanks for fixing this. My old patches propagated the return value of splitting page table which was called outside __change_memory_common(). But it was missed in the final patches.

The fix looks good to me. Reviewed-by: Yang Shi <[email protected]>

Yang

Quoted 31 lines

---
v1 of this patch: https://lore.kernel.org/all/[email protected]/
I have dropped stable since no real chance of failure was there.

  arch/arm64/mm/pageattr.c | 5 ++++-
  1 file changed, 4 insertions(+), 1 deletion(-)
arch/arm64/mm/pageattr.c +4 -1
index 5135f2d66958..b4ea86cd3a71 100644
@@ -148,6 +148,7 @@ static int change_memory_common(unsigned long addr, int numpages,
  	unsigned long size = PAGE_SIZE * numpages;
  	unsigned long end = start + size;
  	struct vm_struct *area;
+	int ret;
  	int i;
 
  	if (!PAGE_ALIGNED(addr)) {
@@ -185,8 +186,10 @@ static int change_memory_common(unsigned long addr, int numpages,
  	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
  			    pgprot_val(clear_mask) == PTE_RDONLY)) {
  		for (i = 0; i < area->nr_pages; i++) {
-			__change_memory_common((u64)page_address(area->pages[i]),
+			ret = __change_memory_common((u64)page_address(area->pages[i]),
  					       PAGE_SIZE, set_mask, clear_mask);
+			if (ret)
+				return ret;
  		}
  	}
 
maintainer
#3 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 2 lines · Yang Shi

The fix looks good to me. Reviewed-by: Yang Shi
<[email protected]>

BTW, I think tools like b4 which I use to apply patches will ignored the reviewed-by tag as it's not on a separate line (I haven't checked the latest b4 version but I've seen it happening in the past).

Signature · 1 line
Catalin
#4 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 6 lines · Catalin Marinas
Quoted 2 lines · Yang Shi

The fix looks good to me. Reviewed-by: Yang Shi
<[email protected]>

BTW, I think tools like b4 which I use to apply patches will ignored the reviewed-by tag as it's not on a separate line (I haven't checked the latest b4 version but I've seen it happening in the past).

Thank you for reminding. I will put my tag in a separate line next time.

Yang

Quoted 1 line
Reviewed-by on v1 1/2
#5 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

In reply to Dev Jain
Quoted 10 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

It would be good to get this into v6.18 I guess?

Although I think this will conflict with a patch from Yang that makes this work with a partial vm area range - But I think that one will only go to v6.19.

Thanks,
Ryan

Quoted 31 lines

---
v1 of this patch: https://lore.kernel.org/all/[email protected]/
I have dropped stable since no real chance of failure was there.

 arch/arm64/mm/pageattr.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
arch/arm64/mm/pageattr.c +4 -1
index 5135f2d66958..b4ea86cd3a71 100644
@@ -148,6 +148,7 @@ static int change_memory_common(unsigned long addr, int numpages,
 	unsigned long size = PAGE_SIZE * numpages;
 	unsigned long end = start + size;
 	struct vm_struct *area;
+	int ret;
 	int i;
 
 	if (!PAGE_ALIGNED(addr)) {
@@ -185,8 +186,10 @@ static int change_memory_common(unsigned long addr, int numpages,
 	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
 			    pgprot_val(clear_mask) == PTE_RDONLY)) {
 		for (i = 0; i < area->nr_pages; i++) {
-			__change_memory_common((u64)page_address(area->pages[i]),
+			ret = __change_memory_common((u64)page_address(area->pages[i]),
 					       PAGE_SIZE, set_mask, clear_mask);
+			if (ret)
+				return ret;
 		}
 	}
 
#6 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 9 lines · Ryan Roberts
Quoted 8 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Quoted 5 lines
Quoted 2 lines
Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

It would be good to get this into v6.18 I guess?

Yeah, agreed.

Quoted 3 lines

Although I think this will conflict with a patch from Yang that makes this work with a partial vm area range - But I think that one will only go to v6.19.

Yes, it will conflict. But it is quite easy to solve. I will rebase my patch on top of it once it is picked.

Thanks,
Yang

Quoted 35 lines

Thanks,
Ryan

Quoted 31 lines

---
v1 of this patch: https://lore.kernel.org/all/[email protected]/
I have dropped stable since no real chance of failure was there.

  arch/arm64/mm/pageattr.c | 5 ++++-
  1 file changed, 4 insertions(+), 1 deletion(-)
arch/arm64/mm/pageattr.c +4 -1
index 5135f2d66958..b4ea86cd3a71 100644
@@ -148,6 +148,7 @@ static int change_memory_common(unsigned long addr, int numpages,
  	unsigned long size = PAGE_SIZE * numpages;
  	unsigned long end = start + size;
  	struct vm_struct *area;
+	int ret;
  	int i;
 
  	if (!PAGE_ALIGNED(addr)) {
@@ -185,8 +186,10 @@ static int change_memory_common(unsigned long addr, int numpages,
  	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
  			    pgprot_val(clear_mask) == PTE_RDONLY)) {
  		for (i = 0; i < area->nr_pages; i++) {
-			__change_memory_common((u64)page_address(area->pages[i]),
+			ret = __change_memory_common((u64)page_address(area->pages[i]),
  					       PAGE_SIZE, set_mask, clear_mask);
+			if (ret)
+				return ret;
  		}
  	}
 
maintainer
#7 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

In reply to Ryan Roberts
Quoted 9 lines · Ryan Roberts
Quoted 8 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Quoted 6 lines
Quoted 2 lines
Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

It would be good to get this into v6.18 I guess?

I'm not sure I see the urgency. When the commit message says:

"there is a real chance of such an error arising post commit a166563e7ec3"

afaict that's either due to -ENOMEM or some hideous issue with the page-tables (e.g. the -EINVALs in pageattr_pXd_entry() seem completely unnecessary to me).

Do you think failure is actually likely and recoverable?

Will

#8 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 15 lines · Will Deacon
Quoted 14 lines · Ryan Roberts
Quoted 10 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
Quoted 7 lines
Quoted 1 line

It would be good to get this into v6.18 I guess?

I'm not sure I see the urgency. When the commit message says:

"there is a real chance of such an error arising post commit a166563e7ec3"

afaict that's either due to -ENOMEM

Yes this is the main risk; failing to allocate an intermediate page table during split_kernel_leaf_mapping(). I have no idea how likely that is in production. The only data point I have is that for the theoretical memory hotplug -ENOMEM that Chaitanya and Linu fixed recently, we tried to provoke it by hotplugging a lot of memory on a system under high memory pressure; no matter what we did, we couldn't get that 4K pgtable allocation to fail. So on that basis, I think we are unlikely to see it.

Quoted 3 lines

or some hideous issue with the
page-tables (e.g. the -EINVALs in pageattr_pXd_entry() seem completely unnecessary to me).

I thought the -EINVALs were trying to catch the case where someone tries to set permissions on a sub-portion of a vmalloc_huge() area on a system that doesn't support BBML2_NOABORT. But looking again, we already refuse vmalloc_huge in change_memory_common.

Quoted 2 lines

Do you think failure is actually likely and recoverable?

As above, I think failure is unlikely, but not impossible. I guess the result would be memory that remains RW when it should have been set RO or RX. But I think it will all work itself out at vfree. I think.

We can defer this to next cycle if you prefer.

Thanks,
Ryan

Quoted 2 lines

Will

maintainer
#9 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 42 lines · Ryan Roberts
Quoted 15 lines · Will Deacon
Quoted 14 lines · Ryan Roberts
Quoted 10 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")
Quoted 7 lines
Quoted 1 line

It would be good to get this into v6.18 I guess?

I'm not sure I see the urgency. When the commit message says:

"there is a real chance of such an error arising post commit a166563e7ec3"

afaict that's either due to -ENOMEM

Yes this is the main risk; failing to allocate an intermediate page table during split_kernel_leaf_mapping(). I have no idea how likely that is in production. The only data point I have is that for the theoretical memory hotplug -ENOMEM that Chaitanya and Linu fixed recently, we tried to provoke it by hotplugging a lot of memory on a system under high memory pressure; no matter what we did, we couldn't get that 4K pgtable allocation to fail. So on that basis, I think we are unlikely to see it.

Quoted 3 lines

or some hideous issue with the
page-tables (e.g. the -EINVALs in pageattr_pXd_entry() seem completely unnecessary to me).

I thought the -EINVALs were trying to catch the case where someone tries to set permissions on a sub-portion of a vmalloc_huge() area on a system that doesn't support BBML2_NOABORT. But looking again, we already refuse vmalloc_huge in change_memory_common.

Quoted 1 line
Quoted 7 lines
Quoted 1 line

Do you think failure is actually likely and recoverable?

As above, I think failure is unlikely, but not impossible. I guess the result would be memory that remains RW when it should have been set RO or RX. But I think it will all work itself out at vfree. I think.

We can defer this to next cycle if you prefer.

Yeah, I think we have bigger problems if we can't find memory to allocate page tables tbh.

Will

maintainer
#10 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

In reply to Dev Jain
Quoted 8 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Quoted 5 lines
Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

---
v1 of this patch: https://lore.kernel.org/all/[email protected]/
I have dropped stable since no real chance of failure was there.

I couldn't figure out from the comments on v1 whether Will's concern was addressed:

https://lore.kernel.org/all/aQn4EwKar66UZ7rz@willie-the-truck/

IOW, is the patch necessary? What are the failure scenarios and what does the caller do? It's good to propagate an error to the caller but patch also changes the current behaviour by bailing out earlier.

Signature · 1 line
Catalin
author
#11 lore raw

Re: [PATCH 1/2] arm64/pageattr: Propagate return value from __change_memory_common

Quoted 14 lines · Catalin Marinas
Quoted 8 lines · Dev Jain

The rodata=on security measure requires that any code path which does vmalloc -> set_memory_ro/set_memory_rox must protect the linear map alias too. Therefore, if such a call fails, we must abort set_memory_* and caller must take appropriate action; currently we are suppressing the error, and there is a real chance of such an error arising post commit a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full"). Therefore, propagate any error to the caller.

Quoted 5 lines
Fixes a166563e7ec3 ("arm64: mm: support large block mapping when rodata=full")

---
v1 of this patch: https://lore.kernel.org/all/[email protected]/
I have dropped stable since no real chance of failure was there.

Quoted 6 lines

I couldn't figure out from the comments on v1 whether Will's concern was addressed:

https://lore.kernel.org/all/aQn4EwKar66UZ7rz@willie-the-truck/

IOW, is the patch necessary? What are the failure scenarios and what

The patch is necessary because rodata=on requires us to proceed with set_memory_* *only* if the linear map alias permission change was successful. If we still go ahead with the set_memory_*, you now have memory in RO state, whereas the linear map alias is in RW state, defeating the purpose of rodata = on.

Quoted 2 lines

does the caller do? It's good to propagate an error to the caller but patch also changes the current behaviour by bailing out earlier.

The caller will get to know that set_memory_* failed. Since we may have bailed out partially in between the linear map alias permission change, we must also ensure that we change that memory back to RW - vm_reset_perms() will ensure that, and that change back to RW is *guaranteed* to succeed in the calls to set_area_direct_map() in vm_reset_perms(): as explained in the next patch, since that memory is non-RW, it is guaranteed to be pte-mapped.

Now, it is the responsibility of the caller to pass VM_FLUSH_RESET_PERMS *before* it does set_memory_ro/set_memory_rox. If it doesn't, then the code is broken as is (Ryan noted earlier how this is a fragility in the vmalloc API and we should do something about it).

Quoted 1 line
author
#12 lore raw

PATCH 2/2 arm64/mm: Document why linear map split failure upon vm_reset_perms is not problematic

In reply to Dev Jain

Consider the following code path:

(1) vmalloc -> (2) set_vm_flush_reset_perms -> (3) set_memory_ro/set_memory_rox -> .... (4) use the mapping .... -> (5) vfree -> (6) vm_reset_perms -> (7) set_area_direct_map.
Or, it may happen that we encounter failure at (3) and directly jump to (5).

In both cases, (7) may fail due to linear map split failure. But, we care about its success *only* for the region which got successfully changed by (3). Such a region is guaranteed to be pte-mapped.

The TLDR is that (7) will surely succeed for the regions we care about.

---
 arch/arm64/mm/pageattr.c | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm64/mm/pageattr.c +9 -0
index b4ea86cd3a71..dc05f06a47f2 100644
@@ -185,6 +185,15 @@ static int change_memory_common(unsigned long addr, int numpages,
 	 */
 	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
 			    pgprot_val(clear_mask) == PTE_RDONLY)) {
+		/*
+		 * Note: One may wonder what happens if the calls to
+		 * set_area_direct_map() in vm_reset_perms() fail due ENOMEM on
+		 * linear map split failure. Observe that we care about those
+		 * calls to succeed *only* for the region whose permissions
+		 * are not default. Such a region is guaranteed to be
+		 * pte-mapped, because the below call can change those
+		 * permissions to non-default only after splitting that region.
+		 */
 		for (i = 0; i < area->nr_pages; i++) {
 			ret = __change_memory_common((u64)page_address(area->pages[i]),
 					       PAGE_SIZE, set_mask, clear_mask);
Signature · 1 line
2.30.2
#13 lore raw

Re: [PATCH 2/2] arm64/mm: Document why linear map split failure upon vm_reset_perms is not problematic

Quoted 7 lines · Dev Jain

Consider the following code path:

(1) vmalloc -> (2) set_vm_flush_reset_perms -> (3) set_memory_ro/set_memory_rox -> .... (4) use the mapping .... -> (5) vfree -> (6) vm_reset_perms -> (7) set_area_direct_map.
Or, it may happen that we encounter failure at (3) and directly jump to (5).

Quoted 7 lines

In both cases, (7) may fail due to linear map split failure. But, we care about its success *only* for the region which got successfully changed by (3). Such a region is guaranteed to be pte-mapped.

The TLDR is that (7) will surely succeed for the regions we care about.

Thanks for documenting this. Looks good to me. Reviewed-by: Yang Shi <[email protected]>

Yang

Quoted 24 lines
---
  arch/arm64/mm/pageattr.c | 9 +++++++++
  1 file changed, 9 insertions(+)
arch/arm64/mm/pageattr.c +9 -0
index b4ea86cd3a71..dc05f06a47f2 100644
@@ -185,6 +185,15 @@ static int change_memory_common(unsigned long addr, int numpages,
  	 */
  	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
  			    pgprot_val(clear_mask) == PTE_RDONLY)) {
+		/*
+		 * Note: One may wonder what happens if the calls to
+		 * set_area_direct_map() in vm_reset_perms() fail due ENOMEM on
+		 * linear map split failure. Observe that we care about those
+		 * calls to succeed *only* for the region whose permissions
+		 * are not default. Such a region is guaranteed to be
+		 * pte-mapped, because the below call can change those
+		 * permissions to non-default only after splitting that region.
+		 */
  		for (i = 0; i < area->nr_pages; i++) {
  			ret = __change_memory_common((u64)page_address(area->pages[i]),
  					       PAGE_SIZE, set_mask, clear_mask);
Reviewed-by on v1 2/2
#14 lore raw

Re: [PATCH 2/2] arm64/mm: Document why linear map split failure upon vm_reset_perms is not problematic

In reply to Dev Jain
Quoted 10 lines · Dev Jain

Consider the following code path:

(1) vmalloc -> (2) set_vm_flush_reset_perms -> (3) set_memory_ro/set_memory_rox -> .... (4) use the mapping .... -> (5) vfree -> (6) vm_reset_perms -> (7) set_area_direct_map.
Or, it may happen that we encounter failure at (3) and directly jump to (5).

In both cases, (7) may fail due to linear map split failure. But, we care about its success *only* for the region which got successfully changed by (3). Such a region is guaranteed to be pte-mapped.

I keep tripping over this bit because I keep forgetting that even if the vmalloc region whose permissions are being changed contains a huge mapping, we still change the linear map page-by-page. So the portion of the linear map is guarranteed to be pte-mapped.

Quoted 2 lines

The TLDR is that (7) will surely succeed for the regions we care about.

Appologies, we have definitely discussed this before, but I still can't quite convince myself. Consider this:

static void vm_reset_perms(struct vm_struct *area)

{
	...

	/*
	 * Set direct map to something invalid so that it won't be cached if
	 * there are any accesses after the TLB flush, then flush the TLB and
	 * reset the direct map permissions to the default.
	 */
	set_area_direct_map(area, set_direct_map_invalid_noflush);
	_vm_unmap_aliases(start, end, flush_dmap);
	set_area_direct_map(area, set_direct_map_default_noflush);
}

If we have a situation where a region of 4M is allocated with vmalloc, which is PMD-mapped, then only the second 2M has its permissions changed by set_memory_ro[x], we end up with the first 2M not pte-mapped in the linear map with default permissions and the second 2M pte-mapped in the linear with non-default permissions.

The above code tries to set the whole vm area to invalid in the linear map before issuing a TLB flush. This could fail for the first half of the area if we are unable to allocate the PTE table to split to PTE (since set_direct_map_default_noflush() is called page-by-page). So we end up with the first half of the region valid with default permissions in the linear map and the second half invalid when we do the TLB flush.

(The above code does it this way to a) reduce the number of TLB flushes to the minimum - the same one covers both the linear map and the vmalloc invalidation, and b) to ensure there is no window when memory has both X and W aliases.

Given it is guarranteed that if any of the linear map is still valid, then it's permissions are the default ones and the vmalloc alias was never changed to non-default permissions for that part, then I agree this is safe.

I've convinced myself that this is all safe and correct. Sorry for the babble:

Quoted 26 lines
---
 arch/arm64/mm/pageattr.c | 9 +++++++++
 1 file changed, 9 insertions(+)
arch/arm64/mm/pageattr.c +9 -0
index b4ea86cd3a71..dc05f06a47f2 100644
@@ -185,6 +185,15 @@ static int change_memory_common(unsigned long addr, int numpages,
 	 */
 	if (rodata_full && (pgprot_val(set_mask) == PTE_RDONLY ||
 			    pgprot_val(clear_mask) == PTE_RDONLY)) {
+		/*
+		 * Note: One may wonder what happens if the calls to
+		 * set_area_direct_map() in vm_reset_perms() fail due ENOMEM on
+		 * linear map split failure. Observe that we care about those
+		 * calls to succeed *only* for the region whose permissions
+		 * are not default. Such a region is guaranteed to be
+		 * pte-mapped, because the below call can change those
+		 * permissions to non-default only after splitting that region.
+		 */
 		for (i = 0; i < area->nr_pages; i++) {
 			ret = __change_memory_common((u64)page_address(area->pages[i]),
 					       PAGE_SIZE, set_mask, clear_mask);
maintainer Applied
#15 lore raw
In reply to Dev Jain
Quoted 9 lines · Dev Jain

The first patch is a fix to prevent suppression of error encountered during linear map alias permission change. This is needed because the rodata=on security measure requires us to proceed only if we first do the linear map alias protection change.

The second patch documents why linear map split failure during the vfreeing path isn't problematic.

[...]

Applied to arm64 (for-next/set_memory), thanks!

[1/2] arm64/pageattr: Propagate return value from __change_memory_common

      https://git.kernel.org/arm64/c/e5efd56fa157
[2/2] arm64/mm: Document why linear map split failure upon vm_reset_perms is not problematic
      https://git.kernel.org/arm64/c/0c2988aaa4d3
Signature · 1 line
Catalin