public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
From: Jan Beulich <jbeulich@suse.com>
To: Binutils <binutils@sourceware.org>
Subject: [PATCH v2 3/3] x86/ELF: permit correct overflow checking for 16-bit PC-relative relocs
Date: Fri, 4 Mar 2022 14:35:55 +0100	[thread overview]
Message-ID: <cb777fa8-093d-0bbf-c25f-7948b3391746@suse.com> (raw)
In-Reply-To: <af880e85-7b81-b9b5-e914-95ce9e317565@suse.com>

The only insn requiring a truly 16-bit PC-relative relocation outside of
16-bit mode is XBEGIN (with an operand size override). For it, the
relocation generated should behave similar to 8- and (for 64-bit) 32-bit
PC-relatives ones, i.e. be checked for a signed value to fit the field.
The relocation type, however, has been (ab)used by 16-bit code, assuming
wraparound at 16-bit segment boundaries. Proper overflow checks aren't
possible in this case, so introduce a command line option allowing to
have the linker apply strict checking.
---
TBD: Like for the earlier PC32 patch, I didn't put thoughts yet into
     also making this work when linking ELF to PE.
---
v2: Re-base and split.

--- a/bfd/elf-linker-x86.h
+++ b/bfd/elf-linker-x86.h
@@ -28,11 +28,12 @@ enum elf_x86_prop_report
   prop_report_shstk	= 1 << 3    /* Report missing SHSTK property.  */
 };
 
-/* Control of PC32 (on 64-bit) overflow check strictness.  */
+/* Control of PC16 (and PC32 on 64-bit) overflow check strictness.  */
 enum elf_x86_pcrel_relocs
 {
   pcrel_relocs_default,
   pcrel_relocs_lax,
+  pcrel_relocs_strict,
 };
 
 /* Used to pass x86-specific linker options from ld to bfd.  */
@@ -71,7 +72,7 @@ struct elf_linker_x86_params
   /* Report relative relocations.  */
   unsigned int report_relative_reloc : 1;
 
-  /* Strictness of PC32 (on 64-bit) overflow checks.  */
+  /* Strictness of PC16 (and PC32 on 64-bit) overflow checks.  */
   enum elf_x86_pcrel_relocs pcrel_relocs;
 
   /* X86-64 ISA level needed.  */
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -179,6 +179,10 @@ static reloc_howto_type elf_howto_table[
 
 };
 
+static reloc_howto_type elf_howto_pc16_strict =
+  HOWTO(R_386_PC16, 0, 1, 16, true, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_386_PC16", true, 0xffff, 0xffff, true);
+
 #ifdef DEBUG_GEN_RELOC
 #define TRACE(str) \
   fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str)
@@ -270,8 +274,14 @@ elf_i386_reloc_type_lookup (bfd *abfd,
       return &elf_howto_table[R_386_16 - R_386_ext_offset];
 
     case BFD_RELOC_16_PCREL:
+    {
+      const struct elf_linker_x86_params *params = elf_x86_tdata (abfd)->params;
+
       TRACE ("BFD_RELOC_16_PCREL");
+      if (params && params->pcrel_relocs == pcrel_relocs_strict)
+	return &elf_howto_pc16_strict;
       return &elf_howto_table[R_386_PC16 - R_386_ext_offset];
+    }
 
     case BFD_RELOC_8:
       TRACE ("BFD_RELOC_8");
@@ -349,21 +359,32 @@ elf_i386_reloc_type_lookup (bfd *abfd,
 }
 
 static reloc_howto_type *
-elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
-			    const char *r_name)
+elf_i386_reloc_override (const bfd *abfd, reloc_howto_type *howto)
+{
+  const struct elf_linker_x86_params *params = elf_x86_tdata (abfd)->params;
+
+  if (howto->type != R_386_PC16 || params == NULL
+      || params->pcrel_relocs != pcrel_relocs_strict)
+    return howto;
+
+  return &elf_howto_pc16_strict;
+}
+
+static reloc_howto_type *
+elf_i386_reloc_name_lookup (bfd *abfd, const char *r_name)
 {
   unsigned int i;
 
   for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++)
     if (elf_howto_table[i].name != NULL
 	&& strcasecmp (elf_howto_table[i].name, r_name) == 0)
-      return &elf_howto_table[i];
+      return elf_i386_reloc_override (abfd, &elf_howto_table[i]);
 
   return NULL;
 }
 
 static reloc_howto_type *
-elf_i386_rtype_to_howto (unsigned r_type)
+elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
 {
   unsigned int indx;
 
@@ -378,7 +399,7 @@ elf_i386_rtype_to_howto (unsigned r_type
   /* PR 17512: file: 0f67f69d.  */
   if (elf_howto_table [indx].type != r_type)
     return NULL;
-  return &elf_howto_table[indx];
+  return elf_i386_reloc_override (abfd, &elf_howto_table[indx]);
 }
 
 static bool
@@ -388,7 +409,7 @@ elf_i386_info_to_howto_rel (bfd *abfd,
 {
   unsigned int r_type = ELF32_R_TYPE (dst->r_info);
 
-  if ((cache_ptr->howto = elf_i386_rtype_to_howto (r_type)) == NULL)
+  if ((cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type)) == NULL)
     {
       /* xgettext:c-format */
       _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
@@ -1136,8 +1157,8 @@ elf_i386_tls_transition (struct bfd_link
       reloc_howto_type *from, *to;
       const char *name;
 
-      from = elf_i386_rtype_to_howto (from_type);
-      to = elf_i386_rtype_to_howto (to_type);
+      from = elf_i386_rtype_to_howto (abfd, from_type);
+      to = elf_i386_rtype_to_howto (abfd, to_type);
 
       if (h)
 	name = h->root.root.string;
@@ -1476,6 +1497,9 @@ elf_i386_scan_relocs (bfd *abfd,
 
   BFD_ASSERT (is_x86_elf (abfd, htab));
 
+  /* Make command line controlled settings accessible from the object.  */
+  elf_x86_tdata (abfd)->params = htab->params;
+
   /* Get the section contents.  */
   if (elf_section_data (sec)->this_hdr.contents != NULL)
     contents = elf_section_data (sec)->this_hdr.contents;
@@ -2075,7 +2099,7 @@ elf_i386_relocate_section (bfd *output_b
 	  continue;
 	}
 
-      howto = elf_i386_rtype_to_howto (r_type);
+      howto = elf_i386_rtype_to_howto (input_bfd, r_type);
       if (howto == NULL)
 	return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
 
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -193,6 +193,10 @@ static reloc_howto_type x86_64_howto_32_
 	bfd_elf_generic_reloc, "R_X86_64_32", false, 0, 0xffffffff,
 	false);
 
+static reloc_howto_type x86_64_howto_pc16_strict =
+  HOWTO(R_X86_64_PC16, 0, 1, 16, true, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_X86_64_PC16", false, 0, 0xffff, true);
+
 static reloc_howto_type x86_64_howto_pc32_lax =
   HOWTO(R_X86_64_PC32, 0, 2, 32, true, 0, complain_overflow_bitfield,
 	bfd_elf_generic_reloc, "R_X86_64_PC32", false, 0, 0xffffffff, true);
@@ -272,6 +276,11 @@ elf_x86_64_reloc_override (const bfd *ab
 	break;
       return &x86_64_howto_32_x32;
 
+    case R_X86_64_PC16:
+      if (params == NULL || params->pcrel_relocs != pcrel_relocs_strict)
+	break;
+      return &x86_64_howto_pc16_strict;
+
     case R_X86_64_PC32:
       if (params == NULL || params->pcrel_relocs != pcrel_relocs_lax)
 	break;
--- a/ld/emulparams/elf_i386.sh
+++ b/ld/emulparams/elf_i386.sh
@@ -1,6 +1,7 @@
 source_sh ${srcdir}/emulparams/plt_unwind.sh
 source_sh ${srcdir}/emulparams/extern_protected_data.sh
 source_sh ${srcdir}/emulparams/dynamic_undefined_weak.sh
+source_sh ${srcdir}/emulparams/pcrel-relocs.sh
 source_sh ${srcdir}/emulparams/call_nop.sh
 source_sh ${srcdir}/emulparams/cet.sh
 source_sh ${srcdir}/emulparams/x86-report-relative.sh
--- a/ld/emulparams/pcrel-relocs.sh
+++ b/ld/emulparams/pcrel-relocs.sh
@@ -1,8 +1,12 @@
 PARSE_AND_LIST_OPTIONS_STRICT_PCREL_RELOCS='
   fprintf (file, _("\
+  -z strict-pcrel-relocs      Strict PC-relative relocation overflow checks\n"));
+  fprintf (file, _("\
   -z lax-pcrel-relocs         Lax PC-relative relocation overflow checks\n"));
 '
 PARSE_AND_LIST_ARGS_CASE_Z_STRICT_PCREL_RELOCS='
+      else if (strcmp (optarg, "strict-pcrel-relocs") == 0)
+	params.pcrel_relocs = pcrel_relocs_strict;
       else if (strcmp (optarg, "lax-pcrel-relocs") == 0)
 	params.pcrel_relocs = pcrel_relocs_lax;
 '
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1506,6 +1506,13 @@ recommended to use @samp{-z start-stop-v
 programs and shared libraries so that these symbols are not exported
 between shared objects, which is not usually what's intended.
 
+@item strict-pcrel-relocs
+Tighten relocation overflow checks for 16-bit PC-relative relocations
+which, when used by 16-bit code, may require a larger range of values
+to be considered valid, preventing proper overflow recognition for
+native code .
+Supported for ix86 and x86-64 ELF targets.
+
 @item text
 @itemx notext
 @itemx textoff
--- a/ld/testsuite/ld-i386/pcrel16-2.d
+++ b/ld/testsuite/ld-i386/pcrel16-2.d
@@ -1,6 +1,5 @@
 #name: PCREL16 overflow (2)
 #as: --32
-#ld: -melf_i386
+#ld: -melf_i386 -z strict-pcrel-relocs
 #error: .*relocation truncated to fit: R_386_PC16 .*t16.*
 #error: .*relocation truncated to fit: R_386_PC16 .*_start.*
-#xfail: *-*-*
--- a/ld/testsuite/ld-x86-64/pcrel16-2.d
+++ b/ld/testsuite/ld-x86-64/pcrel16-2.d
@@ -1,6 +1,5 @@
 #name: PCREL16 overflow (2)
 #source: ../ld-i386/pcrel16-2.s
-#ld:
+#ld: -z strict-pcrel-relocs
 #error: .*relocation truncated to fit: R_X86_64_PC16 .*t16.*
 #error: .*relocation truncated to fit: R_X86_64_PC16 .*_start.*
-#xfail: *-*-*


      parent reply	other threads:[~2022-03-04 13:35 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-04 13:33 [PATCH v2 0/3] x86: another take at PC-relative reloc overflow checking Jan Beulich
2022-03-04 13:34 ` [PATCH v2 1/3] x86-64/ELF: permit relaxed overflow checking for 32-bit PC-relative relocs Jan Beulich
2022-03-04 14:18   ` H.J. Lu
2022-03-09  8:21     ` Jan Beulich
2022-03-09 14:27       ` H.J. Lu
2022-03-09 14:38         ` Jan Beulich
2022-03-09 15:08           ` H.J. Lu
2022-03-09 15:17             ` Jan Beulich
2022-03-09 15:32               ` H.J. Lu
2022-03-09 15:41                 ` Jan Beulich
2022-03-09 15:54                   ` H.J. Lu
2022-03-09 16:49                     ` Jan Beulich
2022-03-09 18:11                       ` H.J. Lu
2022-03-04 13:35 ` [PATCH v2 2/3] x86-64/ELF: use new reloc override model to deal with x32 special case Jan Beulich
2022-03-04 13:35 ` Jan Beulich [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cb777fa8-093d-0bbf-c25f-7948b3391746@suse.com \
    --to=jbeulich@suse.com \
    --cc=binutils@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).