]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
x86: Check invalid TLS descriptor call
authorH.J. Lu <hjl.tools@gmail.com>
Thu, 29 Aug 2024 15:47:00 +0000 (08:47 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Fri, 30 Aug 2024 12:18:10 +0000 (05:18 -0700)
TLS descriptor call,

call *x@tlsdesc(%rax)

or

call *x@tlsdesc(%eax)

calls _dl_tlsdesc_return which expects that RAX/EAX points to the TLS
descriptor.  Update x86 linker to issue an error with or without TLS
transition.

bfd/

PR ld/32123
* elf32-i386.c (elf_i386_check_tls_transition): Move
R_386_TLS_DESC_CALL to ...
(elf_i386_tls_transition): Here.
* elf64-x86-64.c (elf_x86_64_check_tls_transition): Move.
R_X86_64_TLSDESC_CALL check to ...
(elf_x86_64_tls_transition): Here.

ld/

PR ld/32123
* testsuite/ld-i386/i386.exp: Run tlsgdesc3.
* testsuite/ld-i386/tlsgdesc3.d: New file.
* testsuite/ld-x86-64/tlsdesc5.d: Likewise.
* testsuite/ld-x86-64/x86-64.exp: Run tlsdesc5.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
bfd/elf32-i386.c
bfd/elf64-x86-64.c
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-i386/tlsgdesc3.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/tlsdesc5.d [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp

index 7d573e7e2c7e29e3a0fd847722fe22cfcba0af23..b1d997b86f0db7de656ffda076bda3002caba2a2 100644 (file)
@@ -1039,19 +1039,8 @@ elf_i386_check_tls_transition (asection *sec,
              : elf_x86_tls_error_yes);
 
     case R_386_TLS_DESC_CALL:
-      /* Check transition from GDesc access model:
-               call *x@tlsdesc(%eax)
-       */
-      if (offset + 2 <= sec->size)
-       {
-         /* Make sure that it's a call *x@tlsdesc(%eax).  */
-         call = contents + offset;
-         return (call[0] == 0xff && call[1] == 0x10
-                 ? elf_x86_tls_error_none
-                 : elf_x86_tls_error_indirect_call);
-       }
-
-      return elf_x86_tls_error_yes;
+      /* It has been checked in elf_i386_tls_transition.  */
+      return elf_x86_tls_error_none;
 
     default:
       abort ();
@@ -1077,6 +1066,8 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
   unsigned int to_type = from_type;
   bool check = true;
   unsigned int to_le_type, to_ie_type;
+  bfd_vma offset;
+  bfd_byte *call;
 
   /* Skip TLS transition for functions.  */
   if (h != NULL
@@ -1098,9 +1089,34 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd,
 
   switch (from_type)
     {
+    case R_386_TLS_DESC_CALL:
+      /* Check valid GDesc call:
+               call *x@tlsdesc(%eax)
+       */
+      offset = rel->r_offset;
+      call = NULL;
+      if (offset + 2 <= sec->size)
+       {
+         /* Make sure that it's a call *x@tlsdesc(%eax).  */
+         call = contents + offset;
+         if (call[0] != 0xff || call[1] != 0x10)
+           call = NULL;
+       }
+
+      if (call == NULL)
+       {
+         _bfd_x86_elf_link_report_tls_transition_error
+           (info, abfd, sec, symtab_hdr, h, sym, rel,
+            "R_386_TLS_DESC_CALL", NULL,
+            elf_x86_tls_error_indirect_call);
+
+         return false;
+       }
+
+      /* Fall through.  */
+
     case R_386_TLS_GD:
     case R_386_TLS_GOTDESC:
-    case R_386_TLS_DESC_CALL:
     case R_386_TLS_IE_32:
     case R_386_TLS_IE:
     case R_386_TLS_GOTIE:
index 83399ea8928856df7e7421f848b73a253b57773f..cef5cbb27fbb14a4921ab4afb5189ba6b6ec20e0 100644 (file)
@@ -1409,32 +1409,8 @@ elf_x86_64_check_tls_transition (bfd *abfd,
              : elf_x86_tls_error_yes);
 
     case R_X86_64_TLSDESC_CALL:
-      /* Check transition from GDesc access model:
-               call *x@tlsdesc(%rax) <--- LP64 mode.
-               call *x@tlsdesc(%eax) <--- X32 mode.
-       */
-      if (offset + 2 <= sec->size)
-       {
-         unsigned int prefix;
-         call = contents + offset;
-         prefix = 0;
-         if (!ABI_64_P (abfd))
-           {
-             /* Check for call *x@tlsdesc(%eax).  */
-             if (call[0] == 0x67)
-               {
-                 prefix = 1;
-                 if (offset + 3 > sec->size)
-                   return elf_x86_tls_error_yes;
-               }
-           }
-         /* Make sure that it's a call *x@tlsdesc(%rax).  */
-         return (call[prefix] == 0xff && call[1 + prefix] == 0x10
-                 ? elf_x86_tls_error_none
-                 : elf_x86_tls_error_indirect_call);
-       }
-
-      return elf_x86_tls_error_yes;
+      /* It has been checked in elf_x86_64_tls_transition.  */
+      return elf_x86_tls_error_none;
 
     default:
       abort ();
@@ -1459,6 +1435,8 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
   unsigned int from_type = *r_type;
   unsigned int to_type = from_type;
   bool check = true;
+  bfd_vma offset;
+  bfd_byte *call;
 
   /* Skip TLS transition for functions.  */
   if (h != NULL
@@ -1468,10 +1446,49 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd,
 
   switch (from_type)
     {
+    case R_X86_64_TLSDESC_CALL:
+      /* Check valid GDesc call:
+               call *x@tlsdesc(%rax) <--- LP64 mode.
+               call *x@tlsdesc(%eax) <--- X32 mode.
+       */
+      offset = rel->r_offset;
+      call = NULL;
+      if (offset + 2 <= sec->size)
+       {
+         unsigned int prefix;
+         call = contents + offset;
+         prefix = 0;
+         if (!ABI_64_P (abfd))
+           {
+             /* Check for call *x@tlsdesc(%eax).  */
+             if (call[0] == 0x67)
+               {
+                 prefix = 1;
+                 if (offset + 3 > sec->size)
+                   call = NULL;
+               }
+           }
+
+         /* Make sure that it's a call *x@tlsdesc(%rax).  */
+         if (call != NULL
+             && (call[prefix] != 0xff || call[1 + prefix] != 0x10))
+           call = NULL;
+       }
+
+      if (call == NULL)
+       {
+         _bfd_x86_elf_link_report_tls_transition_error
+           (info, abfd, sec, symtab_hdr, h, sym, rel,
+            "R_X86_64_TLSDESC_CALL", NULL,
+            elf_x86_tls_error_indirect_call);
+         return false;
+       }
+
+      /* Fall through.  */
+
     case R_X86_64_TLSGD:
     case R_X86_64_GOTPC32_TLSDESC:
     case R_X86_64_CODE_4_GOTPC32_TLSDESC:
-    case R_X86_64_TLSDESC_CALL:
     case R_X86_64_GOTTPOFF:
     case R_X86_64_CODE_4_GOTTPOFF:
     case R_X86_64_CODE_6_GOTTPOFF:
index 6f97f5daa23dd949d19a1760eeb0b84ee5f4f9e1..a66d67a3244099cd154572be9888e4ed0a59788c 100644 (file)
@@ -547,6 +547,7 @@ run_dump_test "pr31868b"
 run_dump_test "pr31868c"
 run_dump_test "tlsgdesc1"
 run_dump_test "tlsgdesc2"
+run_dump_test "tlsgdesc3"
 
 proc undefined_weak {cflags ldflags} {
     set testname "Undefined weak symbol"
diff --git a/ld/testsuite/ld-i386/tlsgdesc3.d b/ld/testsuite/ld-i386/tlsgdesc3.d
new file mode 100644 (file)
index 0000000..f2c29d8
--- /dev/null
@@ -0,0 +1,5 @@
+#source: tlsgdesc2.s
+#name: TLS GDesc call (indirect CALL)
+#as: --32
+#ld: -shared -melf_i386
+#error: .*: relocation R_386_TLS_DESC_CALL against `foo' must be used in indirect CALL with EAX register only
diff --git a/ld/testsuite/ld-x86-64/tlsdesc5.d b/ld/testsuite/ld-x86-64/tlsdesc5.d
new file mode 100644 (file)
index 0000000..6a0158b
--- /dev/null
@@ -0,0 +1,5 @@
+#source: tlsdesc4.s
+#name: TLS GDesc call (indirect CALL)
+#as: --64
+#ld: -shared -melf_x86_64
+#error: .*: relocation R_X86_64_TLSDESC_CALL against `foo' must be used in indirect CALL with RAX register only
index 2214e08ecff11ec87d213496e713ec5134337790..e729b69a7cd08af6cb659a93a7adc8276605bb7f 100644 (file)
@@ -540,6 +540,7 @@ run_dump_test "pr31868c-x32"
 run_dump_test "tlsie5"
 run_dump_test "tlsdesc3"
 run_dump_test "tlsdesc4"
+run_dump_test "tlsdesc5"
 
 if { ![skip_sframe_tests] } {
     run_dump_test "sframe-simple-1"