public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] LoongArch: Fix two bugs breaking IFUNC in static PIE
@ 2022-09-13 15:44 Xi Ruoyao
  2022-09-13 15:44 ` [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section Xi Ruoyao
  2022-09-13 15:44 ` [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs Xi Ruoyao
  0 siblings, 2 replies; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-13 15:44 UTC (permalink / raw)
  To: binutils; +Cc: liuzhensong, Lulu Cheng, Wang Xuerui, Chenghua Xu, Xi Ruoyao

To generate a static PIE, the compiler should pass "-static -pie
--no-dynamic-linker -z text" options to the linker [1].  But, LoongArch
BFD linker currently produces wrong result (missing R_LARCH_IRELATIVE
relocs) with IFUNC and those options, causing test failures in Glibc if
static PIE is enabled.  Fix them now.

For the detailed analysis of the bugs see the commit messages.

[1]: https://gcc.gnu.org/pipermail/gcc-patches/2022-September/601541.html

Xi Ruoyao (2):
  LoongArch: Avoid heap-buffer-overflow in
    loongarch_elf_relocate_section
  LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs

 bfd/elfnn-loongarch.c | 59 +++++++++++++++++++++++--------------------
 1 file changed, 32 insertions(+), 27 deletions(-)

-- 
2.37.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-13 15:44 [PATCH 0/2] LoongArch: Fix two bugs breaking IFUNC in static PIE Xi Ruoyao
@ 2022-09-13 15:44 ` Xi Ruoyao
  2022-09-14  8:57   ` liuzhensong
  2022-09-13 15:44 ` [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs Xi Ruoyao
  1 sibling, 1 reply; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-13 15:44 UTC (permalink / raw)
  To: binutils; +Cc: liuzhensong, Lulu Cheng, Wang Xuerui, Chenghua Xu, Xi Ruoyao

If a and b are different sections, we cannot access something in b with
"a->contents + (offset from a)" because "a->contents" and "b->contents"
are heap buffers allocated separately, not slices of a large buffer.

The issue was found during an attempt to add static-pie support to the
toolchain with ASAN.
---
 bfd/elfnn-loongarch.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index ed42b8b6770..4b408b1db72 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3128,6 +3128,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 	      unresolved_reloc = false;
 	      BFD_ASSERT (rel->r_addend == 0);
 
+	      asection *my_got = got;
 	      bfd_vma got_off = 0;
 	      if (h != NULL)
 		{
@@ -3145,17 +3146,14 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 			{
 			  idx = (h->plt.offset - PLT_HEADER_SIZE)
 			    / PLT_ENTRY_SIZE;
-			  got_off = sec_addr (htab->elf.sgotplt)
-			    + GOTPLT_HEADER_SIZE
-			    + (idx * GOT_ENTRY_SIZE)
-			    - sec_addr (htab->elf.sgot);
+			  my_got = htab->elf.sgotplt;
+			  got_off = GOTPLT_HEADER_SIZE + idx * GOT_ENTRY_SIZE;
 			}
 		      else
 			{
 			  idx = h->plt.offset / PLT_ENTRY_SIZE;
-			  got_off = sec_addr (htab->elf.sgotplt)
-			    + (idx * GOT_ENTRY_SIZE)
-			    - sec_addr (htab->elf.sgot);
+			  my_got = htab->elf.sgotplt;
+			  got_off = idx * GOT_ENTRY_SIZE;
 			}
 		    }
 
@@ -3172,7 +3170,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 			  && SYMBOL_REFERENCES_LOCAL (info, h))
 			{
 			  Elf_Internal_Rela rela;
-			  rela.r_offset = sec_addr (got) + got_off;
+			  rela.r_offset = sec_addr (my_got) + got_off;
 			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
 			  rela.r_addend = relocation;
 			  loongarch_elf_append_rela (output_bfd,
@@ -3202,9 +3200,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		    }
 		}
 
-	      bfd_put_NN (output_bfd, relocation, got->contents + got_off);
+	      bfd_put_NN (output_bfd, relocation, my_got->contents + got_off);
 
-	      relocation = got_off + sec_addr (got);
+	      relocation = got_off + sec_addr (my_got);
 	    }
 
 	  if (r_type == R_LARCH_GOT_PC_HI20)
-- 
2.37.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs
  2022-09-13 15:44 [PATCH 0/2] LoongArch: Fix two bugs breaking IFUNC in static PIE Xi Ruoyao
  2022-09-13 15:44 ` [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section Xi Ruoyao
@ 2022-09-13 15:44 ` Xi Ruoyao
  2022-09-15 13:03   ` liuzhensong
  1 sibling, 1 reply; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-13 15:44 UTC (permalink / raw)
  To: binutils; +Cc: liuzhensong, Lulu Cheng, Wang Xuerui, Chenghua Xu, Xi Ruoyao

loongarch_elf_finish_dynamic_symbol is called after elf_link_sort_relocs
if -z combreloc.  elf_link_sort_relocs redistributes the contents of
.rela.* sections those would be merged into .rela.dyn, so the slot for
R_LARCH_IRELATIVE may be out of relplt->contents now.

To make things worse, the boundary check

    dyn < dyn + relplt->size / sizeof (*dyn)

is obviously wrong ("x + 10 < x"? :), causing the issue undetected
during the linking process and the resulted executable suddenly crashes
at runtime.

The issue was found during an attempt to add static-pie support to the
toolchain.

Fix it by iterating through the inputs of .rela.dyn to find the slot.
---
 bfd/elfnn-loongarch.c | 41 ++++++++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index 4b408b1db72..1de9dbfecfa 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3511,6 +3511,12 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
 {
   struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
   const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
+  asection *rela_dyn = bfd_get_section_by_name (output_bfd, ".rela.dyn");
+  struct bfd_link_order *lo = NULL;
+  Elf_Internal_Rela *slot = NULL, *last_slot = NULL;
+
+  if (rela_dyn)
+    lo = rela_dyn->map_head.link_order;
 
   if (h->plt.offset != MINUS_ONE)
     {
@@ -3520,6 +3526,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
       uint32_t plt_entry[PLT_ENTRY_INSNS];
       bfd_byte *loc;
       Elf_Internal_Rela rela;
+      asection *rela_sec = NULL;
 
       if (htab->elf.splt)
 	{
@@ -3572,31 +3579,31 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
 	  && (relplt == htab->elf.srelgot
 	      || relplt == htab->elf.irelplt))
 	{
-	    {
-	      rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
-	      rela.r_addend = (h->root.u.def.value
+	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
+	  rela.r_addend = (h->root.u.def.value
 			       + h->root.u.def.section->output_section->vma
 			       + h->root.u.def.section->output_offset);
-	    }
 
-	    /* Find the space after dyn sort.  */
+	  /* Find the space after dyn sort.  */
+	  while (slot == last_slot || slot->r_offset != 0)
 	    {
-	      Elf_Internal_Rela *dyn = (Elf_Internal_Rela *)relplt->contents;
-	      bool fill = false;
-	      for (;dyn < dyn + relplt->size / sizeof (*dyn); dyn++)
+	      if (slot != last_slot)
 		{
-		  if (0 == dyn->r_offset)
-		    {
-		      bed->s->swap_reloca_out (output_bfd, &rela,
-					       (bfd_byte *)dyn);
-		      relplt->reloc_count++;
-		      fill = true;
-		      break;
-		    }
+		  slot++;
+		  continue;
 		}
-	      BFD_ASSERT (fill);
+
+	      BFD_ASSERT (lo != NULL);
+	      rela_sec = lo->u.indirect.section;
+	      lo = lo->next;
+
+	      slot = (Elf_Internal_Rela *)rela_sec->contents;
+	      last_slot = (Elf_Internal_Rela *)(rela_sec->contents +
+						rela_sec->size);
 	    }
 
+	  bed->s->swap_reloca_out (output_bfd, &rela, (bfd_byte *)slot);
+	  rela_sec->reloc_count++;
 	}
       else
 	{
-- 
2.37.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-13 15:44 ` [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section Xi Ruoyao
@ 2022-09-14  8:57   ` liuzhensong
  2022-09-14 10:15     ` Xi Ruoyao
  0 siblings, 1 reply; 13+ messages in thread
From: liuzhensong @ 2022-09-14  8:57 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Lulu Cheng, Wang Xuerui, Chenghua Xu, mengqinggang

[-- Attachment #1: Type: text/plain, Size: 3868 bytes --]


在 2022/9/13 下午11:44, Xi Ruoyao 写道:
> If a and b are different sections, we cannot access something in b with
> "a->contents + (offset from a)" because "a->contents" and "b->contents"
> are heap buffers allocated separately, not slices of a large buffer.
>
> The issue was found during an attempt to add static-pie support to the
> toolchain with ASAN.

Can you provide compile parameters?

> ---
>   bfd/elfnn-loongarch.c | 18 ++++++++----------
>   1 file changed, 8 insertions(+), 10 deletions(-)
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index ed42b8b6770..4b408b1db72 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -3128,6 +3128,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   	      unresolved_reloc = false;
>   	      BFD_ASSERT (rel->r_addend == 0);
>   
> +	      asection *my_got = got;
>   	      bfd_vma got_off = 0;
>   	      if (h != NULL)
>   		{
> @@ -3145,17 +3146,14 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   			{
>   			  idx = (h->plt.offset - PLT_HEADER_SIZE)
>   			    / PLT_ENTRY_SIZE;
> -			  got_off = sec_addr (htab->elf.sgotplt)
> -			    + GOTPLT_HEADER_SIZE
> -			    + (idx * GOT_ENTRY_SIZE)
> -			    - sec_addr (htab->elf.sgot);
> +			  my_got = htab->elf.sgotplt;
> +			  got_off = GOTPLT_HEADER_SIZE + idx * GOT_ENTRY_SIZE;
>   			}
>   		      else
>   			{
>   			  idx = h->plt.offset / PLT_ENTRY_SIZE;
> -			  got_off = sec_addr (htab->elf.sgotplt)
> -			    + (idx * GOT_ENTRY_SIZE)
> -			    - sec_addr (htab->elf.sgot);
> +			  my_got = htab->elf.sgotplt;
> +			  got_off = idx * GOT_ENTRY_SIZE;
>   			}
>   		    }
>   
> @@ -3172,7 +3170,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   			  && SYMBOL_REFERENCES_LOCAL (info, h))
>   			{
>   			  Elf_Internal_Rela rela;
> -			  rela.r_offset = sec_addr (got) + got_off;
> +			  rela.r_offset = sec_addr (my_got) + got_off;
>   			  rela.r_info = ELFNN_R_INFO (0, R_LARCH_RELATIVE);
>   			  rela.r_addend = relocation;
>   			  loongarch_elf_append_rela (output_bfd,
> @@ -3202,9 +3200,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   		    }
>   		}
>   
> -	      bfd_put_NN (output_bfd, relocation, got->contents + got_off);
> +	      bfd_put_NN (output_bfd, relocation, my_got->contents + got_off);
>   
> -	      relocation = got_off + sec_addr (got);
> +	      relocation = got_off + sec_addr (my_got);
>   	    }
>   
>   	  if (r_type == R_LARCH_GOT_PC_HI20)


This may be the reason of overflow.

Shouldn't write to got table when using hidden ifunc.


diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index ed42b8b6770..9278faa91aa 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3179,6 +3179,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, 
struct bfd_link_info *info,
htab->elf.srelgot, &rela);
                         }
                       h->got.offset |= 1;
+                     bfd_put_NN (output_bfd, relocation, got->contents 
+ got_off);
                     }
                 }
               else
@@ -3200,10 +3201,9 @@ loongarch_elf_relocate_section (bfd *output_bfd, 
struct bfd_link_info *info,
                         }
                       local_got_offsets[r_symndx] |= 1;
                     }
+                 bfd_put_NN (output_bfd, relocation, got->contents + 
got_off);
                 }

-             bfd_put_NN (output_bfd, relocation, got->contents + got_off);
-
               relocation = got_off + sec_addr (got);
             }


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-14  8:57   ` liuzhensong
@ 2022-09-14 10:15     ` Xi Ruoyao
  2022-09-14 11:15       ` Xi Ruoyao
  0 siblings, 1 reply; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-14 10:15 UTC (permalink / raw)
  To: liuzhensong, binutils; +Cc: Lulu Cheng, Wang Xuerui, Chenghua Xu, mengqinggang

On Wed, 2022-09-14 at 16:57 +0800, liuzhensong wrote:
> 在 2022/9/13 下午11:44, Xi Ruoyao 写道:
>  
> > If a and b are different sections, we cannot access something in b
> > with
> > "a->contents + (offset from a)" because "a->contents" and "b-
> > >contents"
> > are heap buffers allocated separately, not slices of a large buffer.
> > 
> > The issue was found during an attempt to add static-pie support to
> > the
> > toolchain with ASAN.
> Can you provide compile parameters?

To reproduce it easily, add a check to detect the heap buffer overflow:

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index a9bb66a1e04..716e3d5a246 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3202,6 +3202,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
                    }
                }
 
+             BFD_ASSERT (got_off < got->size);
              bfd_put_NN (output_bfd, relocation, got->contents + got_off);
 
              relocation = got_off + sec_addr (got);

Then

$ cat test.S
.text
.align 2

.local ifunc
.type ifunc, @gnu_indirect_function
.set ifunc, resolver

resolver:
  la.local $a0, impl
  jr $ra

impl:
  li.w $a0, 42
  jr $ra

.global test
.type test, @function
test:
  move $s0, $ra
  la.got $t0, ifunc
  jirl $ra, $t0, 0
  xori $a0, $a0, 42
  jr $s0
$ cc test.S -c
$ ld/ld-new test.o -shared
ld/ld-new: BFD (GNU Binutils) 2.39.50.20220914 assertion fail elfnn-loongarch.c:3205

And if GDB is used with a breakpoint at bfd_assert, we can see got_off
is "18446744073709551608" (-8).

> Shouldn't write to got table when using hidden ifunc.

Perhaps it's true, using RELA to resolve a GOT entry should not depend
on any "initial" value of the entry...
-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-14 10:15     ` Xi Ruoyao
@ 2022-09-14 11:15       ` Xi Ruoyao
  2022-09-15  1:47         ` liuzhensong
  0 siblings, 1 reply; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-14 11:15 UTC (permalink / raw)
  To: liuzhensong, binutils; +Cc: Chenghua Xu, Lulu Cheng, Wang Xuerui

On Wed, 2022-09-14 at 18:15 +0800, Xi Ruoyao via Binutils wrote:

> > Shouldn't write to got table when using hidden ifunc.
> 
> Perhaps it's true, using RELA to resolve a GOT entry should not depend
> on any "initial" value of the entry...


How about this?  We don't need to write into the GOT if R_LARCH_RELATIVE
or R_LARCH_IRELATIVE will be used:

diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
index a9bb66a1e04..1e8ecb2b8e2 100644
--- a/bfd/elfnn-loongarch.c
+++ b/bfd/elfnn-loongarch.c
@@ -3129,6 +3129,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 	      BFD_ASSERT (rel->r_addend == 0);
 
 	      bfd_vma got_off = 0;
+	      bool fill_got_entry = true;
 	      if (h != NULL)
 		{
 		  /* GOT ref or ifunc.  */
@@ -3141,6 +3142,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 		  if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
 		    {
 		      bfd_vma idx;
+
+		      /* An IFUNC is always resolved at runtime.  */
+		      fill_got_entry = false;
+
 		      if (htab->elf.splt != NULL)
 			{
 			  idx = (h->plt.offset - PLT_HEADER_SIZE)
@@ -3177,6 +3182,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 			  rela.r_addend = relocation;
 			  loongarch_elf_append_rela (output_bfd,
 						     htab->elf.srelgot, &rela);
+			  fill_got_entry = false;
 			}
 		      h->got.offset |= 1;
 		    }
@@ -3197,12 +3203,14 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
 			  rela.r_addend = relocation;
 			  loongarch_elf_append_rela (output_bfd,
 						     htab->elf.srelgot, &rela);
+			  fill_got_entry = false;
 			}
 		      local_got_offsets[r_symndx] |= 1;
 		    }
 		}
 
-	      bfd_put_NN (output_bfd, relocation, got->contents + got_off);
+	      if (fill_got_entry)
+		bfd_put_NN (output_bfd, relocation, got->contents + got_off);
 
 	      relocation = got_off + sec_addr (got);
 	    }

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-14 11:15       ` Xi Ruoyao
@ 2022-09-15  1:47         ` liuzhensong
  2022-09-15  2:56           ` Xi Ruoyao
  0 siblings, 1 reply; 13+ messages in thread
From: liuzhensong @ 2022-09-15  1:47 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Chenghua Xu, Lulu Cheng, Wang Xuerui


在 2022/9/14 下午7:15, Xi Ruoyao 写道:
> On Wed, 2022-09-14 at 18:15 +0800, Xi Ruoyao via Binutils wrote:
>
>>> Shouldn't write to got table when using hidden ifunc.
>> Perhaps it's true, using RELA to resolve a GOT entry should not depend
>> on any "initial" value of the entry...
>
> How about this?  We don't need to write into the GOT if R_LARCH_RELATIVE
> or R_LARCH_IRELATIVE will be used:
 > "We don't need to write into the GOT if R_LARCH_RELATIVE or 
R_LARCH_IRELATIVE will be used:"

Not only this, you can refer to the implementation of the function 
_bfd_elf_allocate_ifunc_dyn_relocs for details.

>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index a9bb66a1e04..1e8ecb2b8e2 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -3129,6 +3129,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   	      BFD_ASSERT (rel->r_addend == 0);
>   
>   	      bfd_vma got_off = 0;
> +	      bool fill_got_entry = true;
>   	      if (h != NULL)
>   		{
>   		  /* GOT ref or ifunc.  */
> @@ -3141,6 +3142,10 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   		  if (h->got.offset == MINUS_ONE && h->type == STT_GNU_IFUNC)
>   		    {
>   		      bfd_vma idx;
> +
> +		      /* An IFUNC is always resolved at runtime.  */
> +		      fill_got_entry = false;
> +
>   		      if (htab->elf.splt != NULL)
>   			{
>   			  idx = (h->plt.offset - PLT_HEADER_SIZE)
> @@ -3177,6 +3182,7 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   			  rela.r_addend = relocation;
>   			  loongarch_elf_append_rela (output_bfd,
>   						     htab->elf.srelgot, &rela);
> +			  fill_got_entry = false;
>   			}
>   		      h->got.offset |= 1;
>   		    }
> @@ -3197,12 +3203,14 @@ loongarch_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
>   			  rela.r_addend = relocation;
>   			  loongarch_elf_append_rela (output_bfd,
>   						     htab->elf.srelgot, &rela);
> +			  fill_got_entry = false;
>   			}
>   		      local_got_offsets[r_symndx] |= 1;
>   		    }
>   		}
>   
> -	      bfd_put_NN (output_bfd, relocation, got->contents + got_off);
> +	      if (fill_got_entry)
> +		bfd_put_NN (output_bfd, relocation, got->contents + got_off);
>   
>   	      relocation = got_off + sec_addr (got);
>   	    }
>


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-15  1:47         ` liuzhensong
@ 2022-09-15  2:56           ` Xi Ruoyao
  2022-09-15  3:54             ` liuzhensong
  0 siblings, 1 reply; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-15  2:56 UTC (permalink / raw)
  To: liuzhensong, binutils; +Cc: Chenghua Xu, Lulu Cheng, Wang Xuerui

On Thu, 2022-09-15 at 09:47 +0800, liuzhensong wrote:
> > How about this?  We don't need to write into the GOT if
> > R_LARCH_RELATIVE
> > or R_LARCH_IRELATIVE will be used:
>  > "We don't need to write into the GOT if R_LARCH_RELATIVE or 
> R_LARCH_IRELATIVE will be used:"
> 
> Not only this, you can refer to the implementation of the function 
> _bfd_elf_allocate_ifunc_dyn_relocs for details.

I don't think _bfd_elf_allocate_ifunc_dyn_relocs (or
local_allocate_ifunc_dyn_relocs for us) and
loongarch_elf_relocate_section are strictly aligned.  We need to
allocate the space for GOT entry, but no need to fill in the content if
the entry will be resolved by R_LARCH_RELATIVE or R_LARCH_IRELATIVE
because they are RELA and the "origin" value of the entry is not used
during the resolution.

By the way, the code paths for REL can be also removed from
local_allocate_ifunc_dyn_relocs because LoongArch does not use REL at
all.

And the change passes ld testsuite, the resulted ld passes glibc
testsuite.

> > 
> > diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> > index a9bb66a1e04..1e8ecb2b8e2 100644
> > --- a/bfd/elfnn-loongarch.c
> > +++ b/bfd/elfnn-loongarch.c
> > @@ -3129,6 +3129,7 @@ loongarch_elf_relocate_section (bfd
> > *output_bfd, struct bfd_link_info *info,
> >               BFD_ASSERT (rel->r_addend == 0);
> >    
> >               bfd_vma got_off = 0;
> > +             bool fill_got_entry = true;
> >               if (h != NULL)
> >                 {
> >                   /* GOT ref or ifunc.  */
> > @@ -3141,6 +3142,10 @@ loongarch_elf_relocate_section (bfd
> > *output_bfd, struct bfd_link_info *info,
> >                   if (h->got.offset == MINUS_ONE && h->type ==
> > STT_GNU_IFUNC)
> >                     {
> >                       bfd_vma idx;
> > +
> > +                     /* An IFUNC is always resolved at runtime.  */
> > +                     fill_got_entry = false;
> > +
> >                       if (htab->elf.splt != NULL)
> >                         {
> >                           idx = (h->plt.offset - PLT_HEADER_SIZE)
> > @@ -3177,6 +3182,7 @@ loongarch_elf_relocate_section (bfd
> > *output_bfd, struct bfd_link_info *info,
> >                           rela.r_addend = relocation;
> >                           loongarch_elf_append_rela (output_bfd,
> >                                                      htab-
> > >elf.srelgot, &rela);
> > +                         fill_got_entry = false;
> >                         }
> >                       h->got.offset |= 1;
> >                     }
> > @@ -3197,12 +3203,14 @@ loongarch_elf_relocate_section (bfd
> > *output_bfd, struct bfd_link_info *info,
> >                           rela.r_addend = relocation;
> >                           loongarch_elf_append_rela (output_bfd,
> >                                                      htab-
> > >elf.srelgot, &rela);
> > +                         fill_got_entry = false;
> >                         }
> >                       local_got_offsets[r_symndx] |= 1;
> >                     }
> >                 }
> >    
> > -             bfd_put_NN (output_bfd, relocation, got->contents +
> > got_off);
> > +             if (fill_got_entry)
> > +               bfd_put_NN (output_bfd, relocation, got->contents +
> > got_off);
> >    
> >               relocation = got_off + sec_addr (got);
> >             }
> > 

-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-15  2:56           ` Xi Ruoyao
@ 2022-09-15  3:54             ` liuzhensong
  2022-09-15  6:13               ` Xi Ruoyao
  0 siblings, 1 reply; 13+ messages in thread
From: liuzhensong @ 2022-09-15  3:54 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Chenghua Xu, Lulu Cheng, Wang Xuerui

[-- Attachment #1: Type: text/plain, Size: 4336 bytes --]


在 2022/9/15 上午10:56, Xi Ruoyao 写道:
> On Thu, 2022-09-15 at 09:47 +0800, liuzhensong wrote:
>>> How about this?  We don't need to write into the GOT if
>>> R_LARCH_RELATIVE
>>> or R_LARCH_IRELATIVE will be used:
>>   > "We don't need to write into the GOT if R_LARCH_RELATIVE or
>> R_LARCH_IRELATIVE will be used:"
>>
>> Not only this, you can refer to the implementation of the function
>> _bfd_elf_allocate_ifunc_dyn_relocs for details.
> I don't think _bfd_elf_allocate_ifunc_dyn_relocs (or
> local_allocate_ifunc_dyn_relocs for us) and
> loongarch_elf_relocate_section are strictly aligned.  We need to
> allocate the space for GOT entry, but no need to fill in the content if
> the entry will be resolved by R_LARCH_RELATIVE or R_LARCH_IRELATIVE
> because they are RELA and the "origin" value of the entry is not used
> during the resolution.

Some reasons of overflow.

>
> By the way, the code paths for REL can be also removed from
> local_allocate_ifunc_dyn_relocs because LoongArch does not use REL at
> all.
>
> And the change passes ld testsuite, the resulted ld passes glibc
> testsuite.
>
>>> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
>>> index a9bb66a1e04..1e8ecb2b8e2 100644
>>> --- a/bfd/elfnn-loongarch.c
>>> +++ b/bfd/elfnn-loongarch.c
>>> @@ -3129,6 +3129,7 @@ loongarch_elf_relocate_section (bfd
>>> *output_bfd, struct bfd_link_info *info,
>>>                BFD_ASSERT (rel->r_addend == 0);
>>>     
>>>                bfd_vma got_off = 0;
>>> +             bool fill_got_entry = true;
>>>                if (h != NULL)
>>>                  {
>>>                    /* GOT ref or ifunc.  */
>>> @@ -3141,6 +3142,10 @@ loongarch_elf_relocate_section (bfd
>>> *output_bfd, struct bfd_link_info *info,
>>>                    if (h->got.offset == MINUS_ONE && h->type ==
>>> STT_GNU_IFUNC)
>>>                      {
>>>                        bfd_vma idx;
>>> +
>>> +                     /* An IFUNC is always resolved at runtime.  */

Not correct, anything can be filled if h->got.offset != MINUS_ONE.

There is no space for ifunc to fill got.

>>> +                     fill_got_entry = false;
>>> +
>>>                        if (htab->elf.splt != NULL)
>>>                          {
>>>                            idx = (h->plt.offset - PLT_HEADER_SIZE)
>>> @@ -3177,6 +3182,7 @@ loongarch_elf_relocate_section (bfd
>>> *output_bfd, struct bfd_link_info *info,
>>>                            rela.r_addend = relocation;
>>>                            loongarch_elf_append_rela (output_bfd,
>>>                                                       htab-
>>>> elf.srelgot, &rela);
>>> +                         fill_got_entry = false;
>>>                          }
>>>                        h->got.offset |= 1;
>>>                      }
>>> @@ -3197,12 +3203,14 @@ loongarch_elf_relocate_section (bfd
>>> *output_bfd, struct bfd_link_info *info,
>>>                            rela.r_addend = relocation;
>>>                            loongarch_elf_append_rela (output_bfd,
>>>                                                       htab-
>>>> elf.srelgot, &rela);
>>> +                         fill_got_entry = false;
>>>                          }
>>>                        local_got_offsets[r_symndx] |= 1;
>>>                      }
>>>                  }
>>>     
>>> -             bfd_put_NN (output_bfd, relocation, got->contents +
>>> got_off);
>>> +             if (fill_got_entry)
>>> +               bfd_put_NN (output_bfd, relocation, got->contents +
>>> got_off);
>>>     
>>>                relocation = got_off + sec_addr (got);
>>>              }
>>>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section
  2022-09-15  3:54             ` liuzhensong
@ 2022-09-15  6:13               ` Xi Ruoyao
  0 siblings, 0 replies; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-15  6:13 UTC (permalink / raw)
  To: liuzhensong, binutils; +Cc: Chenghua Xu, Lulu Cheng, Wang Xuerui

On Thu, 2022-09-15 at 11:54 +0800, liuzhensong wrote:

> > > > diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> > > > index a9bb66a1e04..1e8ecb2b8e2 100644
> > > > --- a/bfd/elfnn-loongarch.c
> > > > +++ b/bfd/elfnn-loongarch.c
> > > > @@ -3129,6 +3129,7 @@ loongarch_elf_relocate_section (bfd
> > > > *output_bfd, struct bfd_link_info *info,
> > > >               BFD_ASSERT (rel->r_addend == 0);
> > > >    
> > > >               bfd_vma got_off = 0;
> > > > +             bool fill_got_entry = true;
> > > >               if (h != NULL)
> > > >                 {
> > > >                   /* GOT ref or ifunc.  */
> > > > @@ -3141,6 +3142,10 @@ loongarch_elf_relocate_section (bfd
> > > > *output_bfd, struct bfd_link_info *info,
> > > >                   if (h->got.offset == MINUS_ONE && h->type ==
> > > > STT_GNU_IFUNC)
> > > >                     {
> > > >                       bfd_vma idx;
> > > > +
> > > > +                     /* An IFUNC is always resolved at
> > > > runtime.  */
> Not correct, anything can be filled if h->got.offset != MINUS_ONE.
> There is no space for ifunc to fill got.

Alright, I'm not familiar with BFD and I don't want to spend too much
time (and brain cell deaths) learning it.  So I'll test your change and
if it works let's just do it in your way...

In the meantime please take a look of the 2nd patch, they are different
(and unrelated) issues.


-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs
  2022-09-13 15:44 ` [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs Xi Ruoyao
@ 2022-09-15 13:03   ` liuzhensong
  2022-09-16 20:11     ` Xi Ruoyao
  0 siblings, 1 reply; 13+ messages in thread
From: liuzhensong @ 2022-09-15 13:03 UTC (permalink / raw)
  To: Xi Ruoyao, binutils; +Cc: Lulu Cheng, Wang Xuerui, Chenghua Xu


在 2022/9/13 下午11:44, Xi Ruoyao 写道:
> loongarch_elf_finish_dynamic_symbol is called after elf_link_sort_relocs
> if -z combreloc.  elf_link_sort_relocs redistributes the contents of
> .rela.* sections those would be merged into .rela.dyn, so the slot for
> R_LARCH_IRELATIVE may be out of relplt->contents now.

It May be unnecessary find the slot in section of .rela.dyn.

The slot of R_LARCH_IRELATIVE is within the scope relplt->contents (the 
space

is calculated in function local_allocate_ifunc_dyn_relocs).

We can find the slot just in relplt->contents(Only for dynamic ifunc. I 
did not test for static ifunc.).

>
> To make things worse, the boundary check
>
>      dyn < dyn + relplt->size / sizeof (*dyn)
>
> is obviously wrong ("x + 10 < x"? :), causing the issue undetected
> during the linking process and the resulted executable suddenly crashes
> at runtime.
>
> The issue was found during an attempt to add static-pie support to the
> toolchain.
>
> Fix it by iterating through the inputs of .rela.dyn to find the slot.
> ---
>   bfd/elfnn-loongarch.c | 41 ++++++++++++++++++++++++-----------------
>   1 file changed, 24 insertions(+), 17 deletions(-)
>
> diff --git a/bfd/elfnn-loongarch.c b/bfd/elfnn-loongarch.c
> index 4b408b1db72..1de9dbfecfa 100644
> --- a/bfd/elfnn-loongarch.c
> +++ b/bfd/elfnn-loongarch.c
> @@ -3511,6 +3511,12 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
>   {
>     struct loongarch_elf_link_hash_table *htab = loongarch_elf_hash_table (info);
>     const struct elf_backend_data *bed = get_elf_backend_data (output_bfd);
> +  asection *rela_dyn = bfd_get_section_by_name (output_bfd, ".rela.dyn");
> +  struct bfd_link_order *lo = NULL;
> +  Elf_Internal_Rela *slot = NULL, *last_slot = NULL;
> +
> +  if (rela_dyn)
> +    lo = rela_dyn->map_head.link_order;
>   
>     if (h->plt.offset != MINUS_ONE)
>       {
> @@ -3520,6 +3526,7 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
>         uint32_t plt_entry[PLT_ENTRY_INSNS];
>         bfd_byte *loc;
>         Elf_Internal_Rela rela;
> +      asection *rela_sec = NULL;
>   
>         if (htab->elf.splt)
>   	{
> @@ -3572,31 +3579,31 @@ loongarch_elf_finish_dynamic_symbol (bfd *output_bfd,
>   	  && (relplt == htab->elf.srelgot
>   	      || relplt == htab->elf.irelplt))
>   	{
> -	    {
> -	      rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
> -	      rela.r_addend = (h->root.u.def.value
> +	  rela.r_info = ELFNN_R_INFO (0, R_LARCH_IRELATIVE);
> +	  rela.r_addend = (h->root.u.def.value
>   			       + h->root.u.def.section->output_section->vma
>   			       + h->root.u.def.section->output_offset);
> -	    }
>   
> -	    /* Find the space after dyn sort.  */
> +	  /* Find the space after dyn sort.  */
> +	  while (slot == last_slot || slot->r_offset != 0)
>   	    {
> -	      Elf_Internal_Rela *dyn = (Elf_Internal_Rela *)relplt->contents;
> -	      bool fill = false;
> -	      for (;dyn < dyn + relplt->size / sizeof (*dyn); dyn++)
My mistake.
> +	      if (slot != last_slot)
>   		{
> -		  if (0 == dyn->r_offset)
> -		    {
> -		      bed->s->swap_reloca_out (output_bfd, &rela,
> -					       (bfd_byte *)dyn);
> -		      relplt->reloc_count++;
> -		      fill = true;
> -		      break;
> -		    }
> +		  slot++;
> +		  continue;
>   		}
> -	      BFD_ASSERT (fill);
> +
> +	      BFD_ASSERT (lo != NULL);
> +	      rela_sec = lo->u.indirect.section;
> +	      lo = lo->next;
> +
> +	      slot = (Elf_Internal_Rela *)rela_sec->contents;
> +	      last_slot = (Elf_Internal_Rela *)(rela_sec->contents +
> +						rela_sec->size);
>   	    }
>   
> +	  bed->s->swap_reloca_out (output_bfd, &rela, (bfd_byte *)slot);
> +	  rela_sec->reloc_count++;
>   	}
>         else
>   	{


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs
  2022-09-15 13:03   ` liuzhensong
@ 2022-09-16 20:11     ` Xi Ruoyao
  2022-09-18  9:58       ` Xi Ruoyao
  0 siblings, 1 reply; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-16 20:11 UTC (permalink / raw)
  To: liuzhensong, binutils; +Cc: Lulu Cheng, Wang Xuerui, Chenghua Xu

On Thu, 2022-09-15 at 21:03 +0800, liuzhensong wrote:
> It May be unnecessary find the slot in section of .rela.dyn.
> 
> The slot of R_LARCH_IRELATIVE is within the scope relplt->contents (the 
> space
> 
> is calculated in function local_allocate_ifunc_dyn_relocs).
> 
> We can find the slot just in relplt->contents(Only for dynamic ifunc. I 
> did not test for static ifunc.).

The problem is loongarch_elf_finish_dynamic_symbol runs after
elf_link_sort_relocs.  elf_link_sort_relocs basically does:

(pseudo code)

buffer = []
for section in {input of .rela.dyn}
    buffer += (section.content) as [RELA]

buffer.sort_by(some_comparator)

buffer = buffer as [byte]
for section in {input of .rela.dyn}
    section.content = buffer[..section.content.len()]
    buffer = buffer[section.content.len()..]

So a "slot" in relplt->contents can end up elsewhere.  You can read the
code of elf_link_sort_relocs to see it...

I can try to write a test case for this, but it's 04:00 AM now so I'd do
it after a sleep...
-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs
  2022-09-16 20:11     ` Xi Ruoyao
@ 2022-09-18  9:58       ` Xi Ruoyao
  0 siblings, 0 replies; 13+ messages in thread
From: Xi Ruoyao @ 2022-09-18  9:58 UTC (permalink / raw)
  To: liuzhensong, binutils; +Cc: Chenghua Xu, Lulu Cheng, Wang Xuerui

On Sat, 2022-09-17 at 04:11 +0800, Xi Ruoyao via Binutils wrote:

> The problem is loongarch_elf_finish_dynamic_symbol runs after
> elf_link_sort_relocs.  elf_link_sort_relocs basically does:
> 
> (pseudo code)
> 
> buffer = []
> for section in {input of .rela.dyn}
>     buffer += (section.content) as [RELA]
> 
> buffer.sort_by(some_comparator)
> 
> buffer = buffer as [byte]
> for section in {input of .rela.dyn}
>     section.content = buffer[..section.content.len()]
>     buffer = buffer[section.content.len()..]
> 
> So a "slot" in relplt->contents can end up elsewhere.  You can read the
> code of elf_link_sort_relocs to see it...
> 
> I can try to write a test case for this, but it's 04:00 AM now so I'd do
> it after a sleep...

Take this as an example, note that the R_LARCH_IRELATIVE relocation is
missing with -z combreloc:

$ cat b1.s
.text
.align 2

.local ifunc
.type ifunc, @gnu_indirect_function
.set ifunc, resolver

resolver:
  la.local $a0, impl
  jr $ra

impl:
  li.w $a0, 42
  jr $ra

.global test
.type test, @function
test:
  move $s0, $ra
  bl ifunc
  xori $a0, $a0, 42
  jr $s0

.data
.global ptr
.type ptr, @object
ptr:
  .dword test
$ gas/as-new b1.s -o b1.o
$ ld/ld-new -shared b1.o  # "-z combreloc" is the default
$ readelf -r a.out

Relocation section '.rela.dyn' at offset 0x1f0 contains 2 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000000000  000000000000 R_LARCH_NONE                         8018
000000008000  000400000002 R_LARCH_64        0000000000000264 test + 0
$ ld/ld-new -shared b1.o -z nocombreloc
$ readelf -r a.out

Relocation section '.rela.data' at offset 0x1f0 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000008000  000400000002 R_LARCH_64        0000000000000264 test + 0

Relocation section '.rela.got' at offset 0x208 contains 1 entry:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
000000008018  00000000000c R_LARCH_IRELATIVE                    250


-- 
Xi Ruoyao <xry111@xry111.site>
School of Aerospace Science and Technology, Xidian University

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2022-09-18  9:58 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-13 15:44 [PATCH 0/2] LoongArch: Fix two bugs breaking IFUNC in static PIE Xi Ruoyao
2022-09-13 15:44 ` [PATCH 1/2] LoongArch: Avoid heap-buffer-overflow in loongarch_elf_relocate_section Xi Ruoyao
2022-09-14  8:57   ` liuzhensong
2022-09-14 10:15     ` Xi Ruoyao
2022-09-14 11:15       ` Xi Ruoyao
2022-09-15  1:47         ` liuzhensong
2022-09-15  2:56           ` Xi Ruoyao
2022-09-15  3:54             ` liuzhensong
2022-09-15  6:13               ` Xi Ruoyao
2022-09-13 15:44 ` [PATCH 2/2] LoongArch: Fix R_LARCH_IRELATIVE insertion after elf_link_sort_relocs Xi Ruoyao
2022-09-15 13:03   ` liuzhensong
2022-09-16 20:11     ` Xi Ruoyao
2022-09-18  9:58       ` Xi Ruoyao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).