diff mbox series

[2/7] powerpc: move __end_rodata to cover arch read-only sections

Message ID 20220914154746.1122482-3-npiggin@gmail.com (mailing list archive)
State Superseded
Headers show
Series powerpc: build / linker improvements | expand

Commit Message

Nicholas Piggin Sept. 14, 2022, 3:47 p.m. UTC
powerpc has a number of read-only sections and tables that are put
after RO_DATA(). Move the __end_rodata symbol to cover these as well.

Setting memory to read-only at boot is done using __init_begin,
change that that to use __end_rodata.

This also affects boot dmesg, is_kernel_rodata(), and some other checks.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
 arch/powerpc/kernel/vmlinux.lds.S        | 3 +++
 arch/powerpc/mm/book3s32/mmu.c           | 2 +-
 arch/powerpc/mm/book3s64/hash_pgtable.c  | 2 +-
 arch/powerpc/mm/book3s64/radix_pgtable.c | 2 +-
 arch/powerpc/mm/pgtable_32.c             | 5 ++---
 5 files changed, 8 insertions(+), 6 deletions(-)

Comments

Christophe Leroy Sept. 15, 2022, 5:50 a.m. UTC | #1
Le 14/09/2022 à 17:47, Nicholas Piggin a écrit :
> powerpc has a number of read-only sections and tables that are put
> after RO_DATA(). Move the __end_rodata symbol to cover these as well.
> 
> Setting memory to read-only at boot is done using __init_begin,
> change that that to use __end_rodata.

I see the idea after looking in more details in the generated code, but 
I think this commit description needs to be more explanatory.

In mm/pgtable_32.c there was a comment explaining why __init_begin is 
used. I think you need to explain why we don't want to use it anymore 
and why we can now use __end_rodata.

> 
> This also affects boot dmesg, is_kernel_rodata(), and some other checks.
> 
> Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
> ---
>   arch/powerpc/kernel/vmlinux.lds.S        | 3 +++
>   arch/powerpc/mm/book3s32/mmu.c           | 2 +-
>   arch/powerpc/mm/book3s64/hash_pgtable.c  | 2 +-
>   arch/powerpc/mm/book3s64/radix_pgtable.c | 2 +-
>   arch/powerpc/mm/pgtable_32.c             | 5 ++---
>   5 files changed, 8 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
> index fe22d940412f..90ac5ff73df2 100644
> --- a/arch/powerpc/kernel/vmlinux.lds.S
> +++ b/arch/powerpc/kernel/vmlinux.lds.S
> @@ -210,6 +210,9 @@ SECTIONS
>   	}
>   #endif
>   
> +	. = ALIGN(PAGE_SIZE);
> +	__end_rodata = .;
> +

I think this will likely break block mapping on PPC32.

It needs to be aligned to STRICT_ALIGN_SIZE, like __init_begin is.


>   /*
>    * Init sections discarded at runtime
>    */
> diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
> index a96b73006dfb..e13b883e4e5b 100644
> --- a/arch/powerpc/mm/book3s32/mmu.c
> +++ b/arch/powerpc/mm/book3s32/mmu.c
> @@ -240,7 +240,7 @@ void mmu_mark_rodata_ro(void)
>   	for (i = 0; i < nb; i++) {
>   		struct ppc_bat *bat = BATS[i];
>   
> -		if (bat_addrs[i].start < (unsigned long)__init_begin)
> +		if (bat_addrs[i].start < (unsigned long)__end_rodata)
>   			bat[1].batl = (bat[1].batl & ~BPP_RW) | BPP_RX;
>   	}
>   
> diff --git a/arch/powerpc/mm/book3s64/hash_pgtable.c b/arch/powerpc/mm/book3s64/hash_pgtable.c
> index ae008b9df0e6..28332001bd87 100644
> --- a/arch/powerpc/mm/book3s64/hash_pgtable.c
> +++ b/arch/powerpc/mm/book3s64/hash_pgtable.c
> @@ -541,7 +541,7 @@ void hash__mark_rodata_ro(void)
>   	unsigned long start, end, pp;
>   
>   	start = (unsigned long)_stext;
> -	end = (unsigned long)__init_begin;
> +	end = (unsigned long)__end_rodata;
>   
>   	pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL_ROX), HPTE_USE_KERNEL_KEY);
>   
> diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
> index 698274109c91..2305f34bcc33 100644
> --- a/arch/powerpc/mm/book3s64/radix_pgtable.c
> +++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
> @@ -228,7 +228,7 @@ void radix__mark_rodata_ro(void)
>   	unsigned long start, end;
>   
>   	start = (unsigned long)_stext;
> -	end = (unsigned long)__init_begin;
> +	end = (unsigned long)__end_rodata;
>   
>   	radix__change_memory_range(start, end, _PAGE_WRITE);
>   }
> diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
> index 3ac73f9fb5d5..112af8c5447a 100644
> --- a/arch/powerpc/mm/pgtable_32.c
> +++ b/arch/powerpc/mm/pgtable_32.c
> @@ -158,10 +158,9 @@ void mark_rodata_ro(void)
>   	}
>   
>   	/*
> -	 * mark .text and .rodata as read only. Use __init_begin rather than
> -	 * __end_rodata to cover NOTES and EXCEPTION_TABLE.
> +	 * mark .text and .rodata as read only.
>   	 */
> -	numpages = PFN_UP((unsigned long)__init_begin) -
> +	numpages = PFN_UP((unsigned long)__end_rodata) -
>   		   PFN_DOWN((unsigned long)_stext);
>   
>   	set_memory_ro((unsigned long)_stext, numpages);
Michael Ellerman Sept. 15, 2022, 12:47 p.m. UTC | #2
Nicholas Piggin <npiggin@gmail.com> writes:
> powerpc has a number of read-only sections and tables that are put
> after RO_DATA(). Move the __end_rodata symbol to cover these as well.
>
> Setting memory to read-only at boot is done using __init_begin,
> change that that to use __end_rodata.

Did you just do that because it seems logical?

Because it does seem logical, but it leaves a RWX region in the gap
between __end_rodata and __init_begin, which is bad.

This is the current behaviour, on radix:

---[ Start of kernel VM ]---
0xc000000000000000-0xc000000001ffffff  0x0000000000000000        32M         r      X   pte  valid  present        dirty  accessed
0xc000000002000000-0xc00000007fffffff  0x0000000002000000      2016M         r  w       pte  valid  present        dirty  accessed

And with your change:

---[ Start of kernel VM ]---
0xc000000000000000-0xc0000000013fffff  0x0000000000000000        20M         r      X   pte  valid  present        dirty  accessed
0xc000000001400000-0xc000000001ffffff  0x0000000001400000        12M         r  w   X   pte  valid  present        dirty  accessed
0xc000000002000000-0xc00000007fffffff  0x0000000002000000      2016M         r  w       pte  valid  present        dirty  accessed


On radix the 16M alignment is larger than we need, but we need to chose
a value at build time that works for radix and hash.

We could make the code smarter on radix, to mark those pages in between
__end_rodata and __init_begin as RW_ and use them for data. But that
would be a more involved change.

I think if we just drop the changes to the C files this patch is OK to
go in.

cheers
Nicholas Piggin Sept. 16, 2022, 12:28 a.m. UTC | #3
On Thu Sep 15, 2022 at 10:47 PM AEST, Michael Ellerman wrote:
> Nicholas Piggin <npiggin@gmail.com> writes:
> > powerpc has a number of read-only sections and tables that are put
> > after RO_DATA(). Move the __end_rodata symbol to cover these as well.
> >
> > Setting memory to read-only at boot is done using __init_begin,
> > change that that to use __end_rodata.
>
> Did you just do that because it seems logical?

I actually was looking at moving init so runtime code and data is
closer.

> Because it does seem logical, but it leaves a RWX region in the gap
> between __end_rodata and __init_begin, which is bad.
>
> This is the current behaviour, on radix:
>
> ---[ Start of kernel VM ]---
> 0xc000000000000000-0xc000000001ffffff  0x0000000000000000        32M         r      X   pte  valid  present        dirty  accessed
> 0xc000000002000000-0xc00000007fffffff  0x0000000002000000      2016M         r  w       pte  valid  present        dirty  accessed
>
> And with your change:
>
> ---[ Start of kernel VM ]---
> 0xc000000000000000-0xc0000000013fffff  0x0000000000000000        20M         r      X   pte  valid  present        dirty  accessed
> 0xc000000001400000-0xc000000001ffffff  0x0000000001400000        12M         r  w   X   pte  valid  present        dirty  accessed
> 0xc000000002000000-0xc00000007fffffff  0x0000000002000000      2016M         r  w       pte  valid  present        dirty  accessed
>
>
> On radix the 16M alignment is larger than we need, but we need to chose
> a value at build time that works for radix and hash.
>
> We could make the code smarter on radix, to mark those pages in between
> __end_rodata and __init_begin as RW_ and use them for data. But that
> would be a more involved change.

Ah, yes Christophe pointed out it's broken too. We could just align
__end_rodata to STRICT_ALIGN_SIZE for this patch?

Thanks,
Nick
Michael Ellerman Sept. 16, 2022, 6:35 a.m. UTC | #4
"Nicholas Piggin" <npiggin@gmail.com> writes:
> On Thu Sep 15, 2022 at 10:47 PM AEST, Michael Ellerman wrote:
>> Nicholas Piggin <npiggin@gmail.com> writes:
>> > powerpc has a number of read-only sections and tables that are put
>> > after RO_DATA(). Move the __end_rodata symbol to cover these as well.
>> >
>> > Setting memory to read-only at boot is done using __init_begin,
>> > change that that to use __end_rodata.
>>
>> Did you just do that because it seems logical?
>
> I actually was looking at moving init so runtime code and data is
> closer.
>
>> Because it does seem logical, but it leaves a RWX region in the gap
>> between __end_rodata and __init_begin, which is bad.
>>
>> This is the current behaviour, on radix:
>>
>> ---[ Start of kernel VM ]---
>> 0xc000000000000000-0xc000000001ffffff  0x0000000000000000        32M         r      X   pte  valid  present        dirty  accessed
>> 0xc000000002000000-0xc00000007fffffff  0x0000000002000000      2016M         r  w       pte  valid  present        dirty  accessed
>>
>> And with your change:
>>
>> ---[ Start of kernel VM ]---
>> 0xc000000000000000-0xc0000000013fffff  0x0000000000000000        20M         r      X   pte  valid  present        dirty  accessed
>> 0xc000000001400000-0xc000000001ffffff  0x0000000001400000        12M         r  w   X   pte  valid  present        dirty  accessed
>> 0xc000000002000000-0xc00000007fffffff  0x0000000002000000      2016M         r  w       pte  valid  present        dirty  accessed
>>
>>
>> On radix the 16M alignment is larger than we need, but we need to chose
>> a value at build time that works for radix and hash.
>>
>> We could make the code smarter on radix, to mark those pages in between
>> __end_rodata and __init_begin as RW_ and use them for data. But that
>> would be a more involved change.
>
> Ah, yes Christophe pointed out it's broken too. We could just align
> __end_rodata to STRICT_ALIGN_SIZE for this patch?

Yeah that should work.

I'd be happier if we had something more explicit to document that
boundary, I'll send a patch.

cheers
diff mbox series

Patch

diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index fe22d940412f..90ac5ff73df2 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -210,6 +210,9 @@  SECTIONS
 	}
 #endif
 
+	. = ALIGN(PAGE_SIZE);
+	__end_rodata = .;
+
 /*
  * Init sections discarded at runtime
  */
diff --git a/arch/powerpc/mm/book3s32/mmu.c b/arch/powerpc/mm/book3s32/mmu.c
index a96b73006dfb..e13b883e4e5b 100644
--- a/arch/powerpc/mm/book3s32/mmu.c
+++ b/arch/powerpc/mm/book3s32/mmu.c
@@ -240,7 +240,7 @@  void mmu_mark_rodata_ro(void)
 	for (i = 0; i < nb; i++) {
 		struct ppc_bat *bat = BATS[i];
 
-		if (bat_addrs[i].start < (unsigned long)__init_begin)
+		if (bat_addrs[i].start < (unsigned long)__end_rodata)
 			bat[1].batl = (bat[1].batl & ~BPP_RW) | BPP_RX;
 	}
 
diff --git a/arch/powerpc/mm/book3s64/hash_pgtable.c b/arch/powerpc/mm/book3s64/hash_pgtable.c
index ae008b9df0e6..28332001bd87 100644
--- a/arch/powerpc/mm/book3s64/hash_pgtable.c
+++ b/arch/powerpc/mm/book3s64/hash_pgtable.c
@@ -541,7 +541,7 @@  void hash__mark_rodata_ro(void)
 	unsigned long start, end, pp;
 
 	start = (unsigned long)_stext;
-	end = (unsigned long)__init_begin;
+	end = (unsigned long)__end_rodata;
 
 	pp = htab_convert_pte_flags(pgprot_val(PAGE_KERNEL_ROX), HPTE_USE_KERNEL_KEY);
 
diff --git a/arch/powerpc/mm/book3s64/radix_pgtable.c b/arch/powerpc/mm/book3s64/radix_pgtable.c
index 698274109c91..2305f34bcc33 100644
--- a/arch/powerpc/mm/book3s64/radix_pgtable.c
+++ b/arch/powerpc/mm/book3s64/radix_pgtable.c
@@ -228,7 +228,7 @@  void radix__mark_rodata_ro(void)
 	unsigned long start, end;
 
 	start = (unsigned long)_stext;
-	end = (unsigned long)__init_begin;
+	end = (unsigned long)__end_rodata;
 
 	radix__change_memory_range(start, end, _PAGE_WRITE);
 }
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 3ac73f9fb5d5..112af8c5447a 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -158,10 +158,9 @@  void mark_rodata_ro(void)
 	}
 
 	/*
-	 * mark .text and .rodata as read only. Use __init_begin rather than
-	 * __end_rodata to cover NOTES and EXCEPTION_TABLE.
+	 * mark .text and .rodata as read only.
 	 */
-	numpages = PFN_UP((unsigned long)__init_begin) -
+	numpages = PFN_UP((unsigned long)__end_rodata) -
 		   PFN_DOWN((unsigned long)_stext);
 
 	set_memory_ro((unsigned long)_stext, numpages);