From: H.J. Lu Date: Thu, 29 Aug 2024 15:47:00 +0000 (-0700) Subject: x86: Check invalid TLS descriptor call X-Git-Tag: gdb-16-branchpoint~1026 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=67e30b15212adc1502b898a1ca224fdf65dc110d;p=thirdparty%2Fbinutils-gdb.git x86: Check invalid TLS descriptor call 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 --- diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 7d573e7e2c7..b1d997b86f0 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -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: diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 83399ea8928..cef5cbb27fb 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -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: diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index 6f97f5daa23..a66d67a3244 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -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 index 00000000000..f2c29d880f2 --- /dev/null +++ b/ld/testsuite/ld-i386/tlsgdesc3.d @@ -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 index 00000000000..6a0158b44b7 --- /dev/null +++ b/ld/testsuite/ld-x86-64/tlsdesc5.d @@ -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 diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp index 2214e08ecff..e729b69a7cd 100644 --- a/ld/testsuite/ld-x86-64/x86-64.exp +++ b/ld/testsuite/ld-x86-64/x86-64.exp @@ -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"