[1/5] LoongArch: Reject R_LARCH_32 from becoming a runtime reloc in ELFCLASS64
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:
$ cat t.s
.data
x:
.4byte x
$ as/as-new t.s -o t.o
$ ld/ld-new -shared t.s
$ objdump -R
a.out: file format elf64-loongarch
DYNAMIC RELOCATION RECORDS
OFFSET TYPE VALUE
00000000000001a8 R_LARCH_RELATIVE *ABS*+0x00000000000001a8
But this is just wrong: at runtime the dynamic linker will run
*(uintptr *)&x += load_address, causing an OOB write.
It does not make too much sense to support R_LARCH_32 in ELFCLASS64 or
R_LARCH_64 in ELFCLASS32 when creating a DLL or PIE. And, if we keep it
as-is in the linked object, it'll be rejected by Glibc dynamic linker
anyway. So we can just reject it like x86_64 and RISC-V.
Signed-off-by: Xi Ruoyao <xry111@xry111.site>
---
bfd/elfnn-loongarch.c | 23 ++++++++++++++++++-
.../ld-loongarch-elf/ld-loongarch-elf.exp | 1 +
.../ld-loongarch-elf/r_larch_32_elf64.d | 4 ++++
.../ld-loongarch-elf/r_larch_32_elf64.s | 3 +++
4 files changed, 30 insertions(+), 1 deletion(-)
create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
Comments
On Sat, Jun 22, 2024 at 3:03 AM Xi Ruoyao <xry111@xry111.site> wrote:
>
> We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:
>
> $ cat t.s
> .data
> x:
> .4byte x
> $ as/as-new t.s -o t.o
> $ ld/ld-new -shared t.s
> $ objdump -R
> a.out: file format elf64-loongarch
>
> DYNAMIC RELOCATION RECORDS
> OFFSET TYPE VALUE
> 00000000000001a8 R_LARCH_RELATIVE *ABS*+0x00000000000001a8
>
> But this is just wrong: at runtime the dynamic linker will run
> *(uintptr *)&x += load_address, causing an OOB write.
>
> It does not make too much sense to support R_LARCH_32 in ELFCLASS64 or
> R_LARCH_64 in ELFCLASS32 when creating a DLL or PIE. And, if we keep it
> as-is in the linked object, it'll be rejected by Glibc dynamic linker
> anyway. So we can just reject it like x86_64 and RISC-V.
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
LGTM.
DLL => DSO ?
> ---
> bfd/elfnn-loongarch.c | 23 ++++++++++++++++++-
> .../ld-loongarch-elf/ld-loongarch-elf.exp | 1 +
> .../ld-loongarch-elf/r_larch_32_elf64.d | 4 ++++
> .../ld-loongarch-elf/r_larch_32_elf64.s | 3 +++
> 4 files changed, 30 insertions(+), 1 deletion(-)
> create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index b1720760475..3a55ac93e20 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
> /* No alloc space of func allocate_dynrelocs. */
> if (unresolved_reloc
> && !(h && (h->is_weakalias || !h->dyn_relocs)))
> - loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
> + {
> + if (is_pic && r_type != R_LARCH_NN)
> + {
> + /* Not to use ELFCLASSNN in string literal or it'll
> + puzzle gettext. */
> +
> + /* xgettext:c-format */
> + char *msg = bfd_asprintf (
> + _("reloc is unresolved and cannot be turned to "
> + "a runtime reloc in ELFCLASS%d"),
> + NN);
> +
> + /* loongarch_reloc_is_fatal will output
> + "R_LARCH_32" or "R_LARCH_64" for us. */
> + fatal = loongarch_reloc_is_fatal (
> + info, input_bfd, input_section, rel, howto,
> + bfd_reloc_notsupported, is_undefweak, name, msg);
> + }
> + else
> + loongarch_elf_append_rela (output_bfd, sreloc,
> + &outrel);
> + }
> }
>
> relocation += rel->r_addend;
> diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> index d833a89246e..70625fa8dfe 100644
> --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> @@ -139,6 +139,7 @@ if [istarget "loongarch64-*-*"] {
> run_dump_test "reloc_le_with_shared"
> run_dump_test "reloc_ler_with_shared"
> run_dump_test "reloc_abs_with_shared"
> + run_dump_test "r_larch_32_elf64"
> }
>
> if [check_pie_support] {
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> new file mode 100644
> index 00000000000..df61f3a36c5
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> @@ -0,0 +1,4 @@
> +#name: R_LARCH_32 in ELFCLASS64
> +#source: r_larch_32_elf64.s
> +#ld: -shared -melf64loongarch
> +#error: R_LARCH_32 against `x':\nreloc is unresolved and cannot be turned to a runtime reloc in ELFCLASS64
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> new file mode 100644
> index 00000000000..6649f2bce01
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> @@ -0,0 +1,3 @@
> +.data
> +x:
> + .4byte x
> --
> 2.45.2
>
在 2024/6/22 下午6:03, Xi Ruoyao 写道:
> We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:
>
> $ cat t.s
> .data
> x:
> .4byte x
> $ as/as-new t.s -o t.o
> $ ld/ld-new -shared t.s
> $ objdump -R
> a.out: file format elf64-loongarch
>
> DYNAMIC RELOCATION RECORDS
> OFFSET TYPE VALUE
> 00000000000001a8 R_LARCH_RELATIVE *ABS*+0x00000000000001a8
>
> But this is just wrong: at runtime the dynamic linker will run
> *(uintptr *)&x += load_address, causing an OOB write.
OOB write means R_LARCH_RELATIVE writes 8 bytes to 4 bytes?
>
> It does not make too much sense to support R_LARCH_32 in ELFCLASS64 or
> R_LARCH_64 in ELFCLASS32 when creating a DLL or PIE. And, if we keep it
> as-is in the linked object, it'll be rejected by Glibc dynamic linker
> anyway. So we can just reject it like x86_64 and RISC-V.
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
> bfd/elfnn-loongarch.c | 23 ++++++++++++++++++-
> .../ld-loongarch-elf/ld-loongarch-elf.exp | 1 +
> .../ld-loongarch-elf/r_larch_32_elf64.d | 4 ++++
> .../ld-loongarch-elf/r_larch_32_elf64.s | 3 +++
> 4 files changed, 30 insertions(+), 1 deletion(-)
> create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index b1720760475..3a55ac93e20 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
> /* No alloc space of func allocate_dynrelocs. */
> if (unresolved_reloc
> && !(h && (h->is_weakalias || !h->dyn_relocs)))
> - loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
> + {
> + if (is_pic && r_type != R_LARCH_NN)
> + {
> + /* Not to use ELFCLASSNN in string literal or it'll
> + puzzle gettext. */
> +
> + /* xgettext:c-format */
> + char *msg = bfd_asprintf (
> + _("reloc is unresolved and cannot be turned to "
> + "a runtime reloc in ELFCLASS%d"),
> + NN);
> +
> + /* loongarch_reloc_is_fatal will output
> + "R_LARCH_32" or "R_LARCH_64" for us. */
> + fatal = loongarch_reloc_is_fatal (
> + info, input_bfd, input_section, rel, howto,
> + bfd_reloc_notsupported, is_undefweak, name, msg);
> + }
> + else
> + loongarch_elf_append_rela (output_bfd, sreloc,
> + &outrel);
> + }
> }
>
> relocation += rel->r_addend;
> diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> index d833a89246e..70625fa8dfe 100644
> --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> @@ -139,6 +139,7 @@ if [istarget "loongarch64-*-*"] {
> run_dump_test "reloc_le_with_shared"
> run_dump_test "reloc_ler_with_shared"
> run_dump_test "reloc_abs_with_shared"
> + run_dump_test "r_larch_32_elf64"
> }
>
> if [check_pie_support] {
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> new file mode 100644
> index 00000000000..df61f3a36c5
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> @@ -0,0 +1,4 @@
> +#name: R_LARCH_32 in ELFCLASS64
> +#source: r_larch_32_elf64.s
> +#ld: -shared -melf64loongarch
> +#error: R_LARCH_32 against `x':\nreloc is unresolved and cannot be turned to a runtime reloc in ELFCLASS64
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> new file mode 100644
> index 00000000000..6649f2bce01
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> @@ -0,0 +1,3 @@
> +.data
> +x:
> + .4byte x
On Mon, 2024-06-24 at 16:45 +0800, mengqinggang wrote:
> > But this is just wrong: at runtime the dynamic linker will run
> > *(uintptr *)&x += load_address, causing an OOB write.
>
>
> OOB write means R_LARCH_RELATIVE writes 8 bytes to 4 bytes?
Yep. If the next 4 bytes have some important data bad things happen.
在 2024/6/22 下午6:03, Xi Ruoyao 写道:
> We were converting R_LARCH_32 to R_LARCH_RELATIVE for ELFCLASS64:
>
> $ cat t.s
> .data
> x:
> .4byte x
> $ as/as-new t.s -o t.o
> $ ld/ld-new -shared t.s
t.s -> t.o?
> $ objdump -R
> a.out: file format elf64-loongarch
>
> DYNAMIC RELOCATION RECORDS
> OFFSET TYPE VALUE
> 00000000000001a8 R_LARCH_RELATIVE *ABS*+0x00000000000001a8
>
> But this is just wrong: at runtime the dynamic linker will run
> *(uintptr *)&x += load_address, causing an OOB write.
>
> It does not make too much sense to support R_LARCH_32 in ELFCLASS64 or
> R_LARCH_64 in ELFCLASS32 when creating a DLL or PIE. And, if we keep it
> as-is in the linked object, it'll be rejected by Glibc dynamic linker
> anyway. So we can just reject it like x86_64 and RISC-V.
>
> Signed-off-by: Xi Ruoyao <xry111@xry111.site>
> ---
> bfd/elfnn-loongarch.c | 23 ++++++++++++++++++-
> .../ld-loongarch-elf/ld-loongarch-elf.exp | 1 +
> .../ld-loongarch-elf/r_larch_32_elf64.d | 4 ++++
> .../ld-loongarch-elf/r_larch_32_elf64.s | 3 +++
> 4 files changed, 30 insertions(+), 1 deletion(-)
> create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> create mode 100644 ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index b1720760475..3a55ac93e20 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
> /* No alloc space of func allocate_dynrelocs. */
> if (unresolved_reloc
> && !(h && (h->is_weakalias || !h->dyn_relocs)))
> - loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
> + {
> + if (is_pic && r_type != R_LARCH_NN)
> + {
> + /* Not to use ELFCLASSNN in string literal or it'll
> + puzzle gettext. */
> +
> + /* xgettext:c-format */
> + char *msg = bfd_asprintf (
> + _("reloc is unresolved and cannot be turned to "
> + "a runtime reloc in ELFCLASS%d"),
> + NN);
> +
> + /* loongarch_reloc_is_fatal will output
> + "R_LARCH_32" or "R_LARCH_64" for us. */
> + fatal = loongarch_reloc_is_fatal (
> + info, input_bfd, input_section, rel, howto,
> + bfd_reloc_notsupported, is_undefweak, name, msg);
> + }
> + else
> + loongarch_elf_append_rela (output_bfd, sreloc,
> + &outrel);
> + }
> }
>
> relocation += rel->r_addend;
> diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> index d833a89246e..70625fa8dfe 100644
> --- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> +++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
> @@ -139,6 +139,7 @@ if [istarget "loongarch64-*-*"] {
> run_dump_test "reloc_le_with_shared"
> run_dump_test "reloc_ler_with_shared"
> run_dump_test "reloc_abs_with_shared"
> + run_dump_test "r_larch_32_elf64"
> }
>
> if [check_pie_support] {
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> new file mode 100644
> index 00000000000..df61f3a36c5
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.d
> @@ -0,0 +1,4 @@
> +#name: R_LARCH_32 in ELFCLASS64
> +#source: r_larch_32_elf64.s
> +#ld: -shared -melf64loongarch
> +#error: R_LARCH_32 against `x':\nreloc is unresolved and cannot be turned to a runtime reloc in ELFCLASS64
> diff --git a/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> new file mode 100644
> index 00000000000..6649f2bce01
> --- /dev/null
> +++ b/ld/testsuite/ld-loongarch-elf/r_larch_32_elf64.s
> @@ -0,0 +1,3 @@
> +.data
> +x:
> + .4byte x
@@ -2861,7 +2861,28 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
/* No alloc space of func allocate_dynrelocs. */
if (unresolved_reloc
&& !(h && (h->is_weakalias || !h->dyn_relocs)))
- loongarch_elf_append_rela (output_bfd, sreloc, &outrel);
+ {
+ if (is_pic && r_type != R_LARCH_NN)
+ {
+ /* Not to use ELFCLASSNN in string literal or it'll
+ puzzle gettext. */
+
+ /* xgettext:c-format */
+ char *msg = bfd_asprintf (
+ _("reloc is unresolved and cannot be turned to "
+ "a runtime reloc in ELFCLASS%d"),
+ NN);
+
+ /* loongarch_reloc_is_fatal will output
+ "R_LARCH_32" or "R_LARCH_64" for us. */
+ fatal = loongarch_reloc_is_fatal (
+ info, input_bfd, input_section, rel, howto,
+ bfd_reloc_notsupported, is_undefweak, name, msg);
+ }
+ else
+ loongarch_elf_append_rela (output_bfd, sreloc,
+ &outrel);
+ }
}
relocation += rel->r_addend;
@@ -139,6 +139,7 @@ if [istarget "loongarch64-*-*"] {
run_dump_test "reloc_le_with_shared"
run_dump_test "reloc_ler_with_shared"
run_dump_test "reloc_abs_with_shared"
+ run_dump_test "r_larch_32_elf64"
}
if [check_pie_support] {
new file mode 100644
@@ -0,0 +1,4 @@
+#name: R_LARCH_32 in ELFCLASS64
+#source: r_larch_32_elf64.s
+#ld: -shared -melf64loongarch
+#error: R_LARCH_32 against `x':\nreloc is unresolved and cannot be turned to a runtime reloc in ELFCLASS64
new file mode 100644
@@ -0,0 +1,3 @@
+.data
+x:
+ .4byte x