[v2] arm64: lds: move .got section out of .text

Message ID 20230501222551.1254686-1-maskray@google.com
State New
Headers
Series [v2] arm64: lds: move .got section out of .text |

Commit Message

Fangrui Song May 1, 2023, 10:25 p.m. UTC
  Currently, the .got section is placed within the output section .text.
However, when .got is non-empty, the SHF_WRITE flag is set for .text
when linked by lld. GNU ld recognizes .text as a special section and
ignores the SHF_WRITE flag. By renaming .text, we can also get the
SHF_WRITE flag.

The kernel has performed R_AARCH64_RELATIVE resolving very early, and can
then assume that .got is read-only. Let's move .got to the vmlinux_rodata
pseudo-segment. The change avoids a section with both executable and
writable permissions.

Signed-off-by: Fangrui Song <maskray@google.com>

--
Changes from v1 (https://lore.kernel.org/lkml/20230428050442.180913-1-maskray@google.com/)
* move .got to the vmlinux_rodata pseudo-segment as suggested by Ard Biesheuvel
---
 arch/arm64/kernel/vmlinux.lds.S | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)
  

Comments

Ard Biesheuvel May 2, 2023, 7:31 a.m. UTC | #1
On Tue, 2 May 2023 at 00:25, Fangrui Song <maskray@google.com> wrote:
>
> Currently, the .got section is placed within the output section .text.
> However, when .got is non-empty, the SHF_WRITE flag is set for .text
> when linked by lld. GNU ld recognizes .text as a special section and
> ignores the SHF_WRITE flag. By renaming .text, we can also get the
> SHF_WRITE flag.
>
> The kernel has performed R_AARCH64_RELATIVE resolving very early, and can
> then assume that .got is read-only. Let's move .got to the vmlinux_rodata
> pseudo-segment. The change avoids a section with both executable and
> writable permissions.
>

Maybe add

"This matters to consumers of the vmlinux ELF representation of the
kernel image, such as syzkaller, which disregards writable PT_LOAD
segments when resolving code symbols. The kernel itself does not care
about this distinction, but given that the GOT contains data and not
code, it does not require executable permissions, and therefore does
not belong in .text to begin with."


> Signed-off-by: Fangrui Song <maskray@google.com>
>

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>

> --
> Changes from v1 (https://lore.kernel.org/lkml/20230428050442.180913-1-maskray@google.com/)
> * move .got to the vmlinux_rodata pseudo-segment as suggested by Ard Biesheuvel
> ---
>  arch/arm64/kernel/vmlinux.lds.S | 19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)
>
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index b9202c2ee18e..3cd7e76cc562 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -181,10 +181,17 @@ SECTIONS
>                         KPROBES_TEXT
>                         HYPERVISOR_TEXT
>                         *(.gnu.warning)
> -               . = ALIGN(16);
> -               *(.got)                 /* Global offset table          */
>         }
>
> +       . = ALIGN(SEGMENT_ALIGN);
> +       _etext = .;                     /* End of text section */
> +
> +       /* everything from this point to __init_begin will be marked RO NX */
> +       RO_DATA(PAGE_SIZE)
> +
> +       HYPERVISOR_DATA_SECTIONS
> +
> +       .got : { *(.got) }
>         /*
>          * Make sure that the .got.plt is either completely empty or it
>          * contains only the lazy dispatch entries.
> @@ -193,14 +200,6 @@ SECTIONS
>         ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18,
>                "Unexpected GOT/PLT entries detected!")
>
> -       . = ALIGN(SEGMENT_ALIGN);
> -       _etext = .;                     /* End of text section */
> -
> -       /* everything from this point to __init_begin will be marked RO NX */
> -       RO_DATA(PAGE_SIZE)
> -
> -       HYPERVISOR_DATA_SECTIONS
> -
>         /* code sections that are never executed via the kernel mapping */
>         .rodata.text : {
>                 TRAMP_TEXT
> --
> 2.40.1.495.gc816e09b53d-goog
>
  

Patch

diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index b9202c2ee18e..3cd7e76cc562 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -181,10 +181,17 @@  SECTIONS
 			KPROBES_TEXT
 			HYPERVISOR_TEXT
 			*(.gnu.warning)
-		. = ALIGN(16);
-		*(.got)			/* Global offset table		*/
 	}
 
+	. = ALIGN(SEGMENT_ALIGN);
+	_etext = .;			/* End of text section */
+
+	/* everything from this point to __init_begin will be marked RO NX */
+	RO_DATA(PAGE_SIZE)
+
+	HYPERVISOR_DATA_SECTIONS
+
+	.got : { *(.got) }
 	/*
 	 * Make sure that the .got.plt is either completely empty or it
 	 * contains only the lazy dispatch entries.
@@ -193,14 +200,6 @@  SECTIONS
 	ASSERT(SIZEOF(.got.plt) == 0 || SIZEOF(.got.plt) == 0x18,
 	       "Unexpected GOT/PLT entries detected!")
 
-	. = ALIGN(SEGMENT_ALIGN);
-	_etext = .;			/* End of text section */
-
-	/* everything from this point to __init_begin will be marked RO NX */
-	RO_DATA(PAGE_SIZE)
-
-	HYPERVISOR_DATA_SECTIONS
-
 	/* code sections that are never executed via the kernel mapping */
 	.rodata.text : {
 		TRAMP_TEXT