[PATCH v5] x86: Disallow GOT memory access beyond its GOT slot

H.J. Lu hjl.tools@gmail.com
Tue Feb 11 21:47:38 GMT 2025


GOT slot contains the symbol run-time address, whose size is 32 bits for
i386 and 64 bits for x86-64.  Memory beyond GOT slot is undefined, which
can be anything, including unmapped or unreadable memory.  Disallow GOT
memory access beyond its GOT slot.

	PR gas/32624
	* config/tc-i386.c (_i386_insn): Add memsize.
	(check_VecOperands): Set i.memsize when setting i.memshift.
	(check_GOT_memory): New function.
	(output_disp): Call check_GOT_memory to check valid GOT memory
	access.
	* testsuite/gas/i386/got.s: Add vector instructions with
	byte/word/dword GOT memory.
	* testsuite/gas/i386/got-no-relax.d: Updated.
	* testsuite/gas/i386/got.d: Likewise.
	* testsuite/gas/i386/x86-64-gotpcrel-2.d: Likewise.
	* testsuite/gas/i386/i386.exp: Run inval-got.
	* testsuite/gas/i386/inval-got.l: New file.
	* testsuite/gas/i386/inval-got.s: Likewise.
	* testsuite/gas/i386/x86-64-inval-got.l: Likewise.
	* testsuite/gas/i386/x86-64-inval-got.l: Likewise.
	* testsuite/gas/i386/x86-64-gotpcrel-2.s: Add vector instructions
	with byte/word/dword/qword GOT memory.
	* testsuite/gas/i386/x86-64.exp: Run x86-64-inval-got.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 gas/config/tc-i386.c                       | 70 +++++++++++++++++++++-
 gas/testsuite/gas/i386/got-no-relax.d      |  3 +
 gas/testsuite/gas/i386/got.d               |  3 +
 gas/testsuite/gas/i386/got.s               |  5 ++
 gas/testsuite/gas/i386/i386.exp            |  1 +
 gas/testsuite/gas/i386/inval-got.l         | 34 +++++++++++
 gas/testsuite/gas/i386/inval-got.s         |  8 +++
 gas/testsuite/gas/i386/x86-64-gotpcrel-2.d |  7 +++
 gas/testsuite/gas/i386/x86-64-gotpcrel-2.s |  7 +++
 gas/testsuite/gas/i386/x86-64-inval-got.l  | 34 +++++++++++
 gas/testsuite/gas/i386/x86-64-inval-got.s  |  8 +++
 gas/testsuite/gas/i386/x86-64.exp          |  1 +
 12 files changed, 179 insertions(+), 2 deletions(-)
 create mode 100644 gas/testsuite/gas/i386/inval-got.l
 create mode 100644 gas/testsuite/gas/i386/inval-got.s
 create mode 100644 gas/testsuite/gas/i386/x86-64-inval-got.l
 create mode 100644 gas/testsuite/gas/i386/x86-64-inval-got.s

diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index 99c0b5de615..038d66ab0d6 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -453,6 +453,9 @@ struct _i386_insn
     /* Compressed disp8*N attribute.  */
     unsigned int memshift;
 
+    /* Memory size for instructions with compressed disp8.  */
+    unsigned int memsize;
+
     /* SCC = EVEX.[SC3,SC2,SC1,SC0].  */
     unsigned int scc;
 
@@ -8811,9 +8814,17 @@ check_VecOperands (const insn_template *t)
       && pp.disp_encoding <= disp_encoding_8bit)
     {
       if (i.broadcast.type || i.broadcast.bytes)
-	i.memshift = t->opcode_modifier.broadcast - 1;
+	{
+	  i.memshift = t->opcode_modifier.broadcast - 1;
+	  /* Remember memory size.  */
+	  i.memsize = 1 << i.memshift;
+	}
       else if (t->opcode_modifier.disp8memshift != DISP8_SHIFT_VL)
-	i.memshift = t->opcode_modifier.disp8memshift;
+	{
+	  i.memshift = t->opcode_modifier.disp8memshift;
+	  /* Remember memory size.  */
+	  i.memsize = 1 << i.memshift;
+	}
       else
 	{
 	  const i386_operand_type *type = NULL, *fallback = NULL;
@@ -8856,6 +8867,9 @@ check_VecOperands (const insn_template *t)
 		i.memshift = 4;
 	    }
 
+	  /* Remember memory size.  */
+	  i.memsize = 1 << i.memshift;
+
 	  /* For the check in fits_in_disp8().  */
 	  if (i.memshift == 0)
 	    i.memshift = -1;
@@ -12725,6 +12739,51 @@ imm_size (unsigned int n)
   return size;
 }
 
+/* Since GOT slot size is 32 bits for i386 and 64 bits for x86-64,
+   disallow GOT memory access beyond its GOT slot.  */
+
+static bool
+check_GOT_memory (enum bfd_reloc_code_real reloc_type, unsigned int n)
+{
+  bool qword;
+
+  qword = false;
+  if (reloc_type == BFD_RELOC_32_PCREL)
+    {
+      if (!GOT_symbol || GOT_symbol != i.op[n].disps->X_op_symbol)
+	return true;
+      qword = true;
+    }
+  else if (reloc_type != BFD_RELOC_386_GOT32)
+    return true;
+
+  /* Disallow AMX TILE configuration load and store instructions.  */
+  if (is_cpu (&i.tm, CpuAMX_TILE))
+    return false;
+
+  /* Disallow instructions with 6-byte and 10-byte memory access.  */
+  if (i.tm.operand_types[n].bitfield.fword
+      || i.tm.operand_types[n].bitfield.tbyte)
+    return false;
+
+  if (i.tm.operand_types[n].bitfield.xmmword
+      || i.tm.operand_types[n].bitfield.ymmword
+      || i.tm.operand_types[n].bitfield.zmmword)
+    {
+      /* Allow memory access within GOT slot.  */
+      if (i.memsize != 0)
+	return i.memsize <= (qword ? 8 : 4);
+
+      /* Disallow memory access beyond GOT slot size.  */
+      return (i.tm.operand_types[n].bitfield.byte
+	      || i.tm.operand_types[n].bitfield.word
+	      || i.tm.operand_types[n].bitfield.dword
+	      || (qword && i.tm.operand_types[n].bitfield.qword));
+    }
+
+  return true;
+}
+
 static void
 output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 {
@@ -12785,6 +12844,13 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off)
 
 	      p = frag_more (size);
 	      reloc_type = reloc (size, pcrel, sign, i.reloc[n]);
+
+	      if (!check_GOT_memory (reloc_type, n))
+		{
+		  as_bad (_("invalid GOT memory operand"));
+		  return;
+		}
+
 	      if (GOT_symbol
 		  && GOT_symbol == i.op[n].disps->X_add_symbol
 		  && (((reloc_type == BFD_RELOC_32
diff --git a/gas/testsuite/gas/i386/got-no-relax.d b/gas/testsuite/gas/i386/got-no-relax.d
index acc8055e880..57e44942ef4 100644
--- a/gas/testsuite/gas/i386/got-no-relax.d
+++ b/gas/testsuite/gas/i386/got-no-relax.d
@@ -37,4 +37,7 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	ff 15 00 00 00 00    	call   \*0x0	a1: R_386_GOT32X	foo
 [ 	]*[a-f0-9]+:	ff a0 00 00 00 00    	jmp    \*0x0\(%eax\)	a7: R_386_GOT32	foo
 [ 	]*[a-f0-9]+:	ff 25 00 00 00 00    	jmp    \*0x0	ad: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	c4 e2 7d 78 25 00 00 00 00 	vpbroadcastb 0x0,%ymm4	b6: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	62 f5 7c 18 68 05 00 00 00 00 	vcvttph2ibs 0x0\{1to8\},%xmm0	c0: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	62 f5 7d 08 7b 05 00 00 00 00 	vcvtph2qq 0x0,%xmm0	ca: R_386_GOT32	foo
 #pass
diff --git a/gas/testsuite/gas/i386/got.d b/gas/testsuite/gas/i386/got.d
index 9610e2cf2c0..61328c71fe6 100644
--- a/gas/testsuite/gas/i386/got.d
+++ b/gas/testsuite/gas/i386/got.d
@@ -36,4 +36,7 @@ Disassembly of section .text:
 [ 	]*[a-f0-9]+:	ff 15 00 00 00 00    	call   \*0x0	a1: R_386_GOT32X	foo
 [ 	]*[a-f0-9]+:	ff a0 00 00 00 00    	jmp    \*0x0\(%eax\)	a7: R_386_GOT32X	foo
 [ 	]*[a-f0-9]+:	ff 25 00 00 00 00    	jmp    \*0x0	ad: R_386_GOT32X	foo
+[ 	]*[a-f0-9]+:	c4 e2 7d 78 25 00 00 00 00 	vpbroadcastb 0x0,%ymm4	b6: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	62 f5 7c 18 68 05 00 00 00 00 	vcvttph2ibs 0x0\{1to8\},%xmm0	c0: R_386_GOT32	foo
+[ 	]*[a-f0-9]+:	62 f5 7d 08 7b 05 00 00 00 00 	vcvtph2qq 0x0,%xmm0	ca: R_386_GOT32	foo
 #pass
diff --git a/gas/testsuite/gas/i386/got.s b/gas/testsuite/gas/i386/got.s
index 47194115bc8..c5ae7c89d3a 100644
--- a/gas/testsuite/gas/i386/got.s
+++ b/gas/testsuite/gas/i386/got.s
@@ -40,3 +40,8 @@ _start:
 	call	DWORD PTR [foo@GOT]
 	jmp	DWORD PTR [eax + foo@GOT]
 	jmp	DWORD PTR [foo@GOT]
+
+	.att_syntax prefix
+	vpbroadcastb	foo@got,%ymm4		# Byte memory
+	vcvttph2ibs	foo@got{1to8}, %xmm0	# Word memory
+	vcvtph2qq	foo@got, %xmm0		# Dword memory
diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp
index 34d0a2fab8c..4699fc31bca 100644
--- a/gas/testsuite/gas/i386/i386.exp
+++ b/gas/testsuite/gas/i386/i386.exp
@@ -53,6 +53,7 @@ if [gas_32_check] then {
     run_list_test "general" "-al --listing-lhs-width=2"
     run_list_test "inval" "-aln"
     run_list_test "inval-16" "-al"
+    run_list_test "inval-got" "-al"
     run_list_test "segment" "-al"
     run_list_test "inval-seg" "-al"
     run_list_test "inval-reg" "-al"
diff --git a/gas/testsuite/gas/i386/inval-got.l b/gas/testsuite/gas/i386/inval-got.l
new file mode 100644
index 00000000000..40f4f3d82a3
--- /dev/null
+++ b/gas/testsuite/gas/i386/inval-got.l
@@ -0,0 +1,34 @@
+.*: Assembler messages:
+.*:3: Error: .*
+.*:4: Error: .*
+.*:5: Error: .*
+.*:6: Error: .*
+.*:7: Error: .*
+.*:8: Error: .*
+GAS LISTING .*
+
+
+[ 	]*1[ 	]+\.text
+[ 	]*2[ 	]+\# All the followings should be illegal\.
+[ 	]*3[ 	]+\?\?\?\? 0F011500 		lgdt	foo@got
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*3[ 	]+000000
+[ 	]*4[ 	]+\?\?\?\? 62F27548 		vpermb	foo@got, %zmm1, %zmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*4[ 	]+8D050000 
+[ 	]*4[ 	]+0000
+[ 	]*5[ 	]+\?\?\?\? 62F1F518 		vmaxpd	foo@got\{1to2\}, %xmm1, %xmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*5[ 	]+5F050000 
+[ 	]*5[ 	]+0000
+[ 	]*6[ 	]+\?\?\?\? C5F15F05 		vmaxpd	foo@got, %xmm1, %xmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*6[ 	]+00000000 
+[ 	]*7[ 	]+\?\?\?\? 62F57C08 		vcvttph2ibs foo@got, %xmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*7[ 	]+68050000 
+[ 	]*7[ 	]+0000
+[ 	]*8[ 	]+\?\?\?\? 0F5A0500 		cvtps2pd foo@GOT, %xmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*8[ 	]+000000
+#pass
diff --git a/gas/testsuite/gas/i386/inval-got.s b/gas/testsuite/gas/i386/inval-got.s
new file mode 100644
index 00000000000..398ecd94263
--- /dev/null
+++ b/gas/testsuite/gas/i386/inval-got.s
@@ -0,0 +1,8 @@
+	.text
+# All the followings should be illegal.
+	lgdt	foo@got
+	vpermb	foo@got, %zmm1, %zmm0
+	vmaxpd	foo@got{1to2}, %xmm1, %xmm0
+	vmaxpd	foo@got, %xmm1, %xmm0
+	vcvttph2ibs foo@got, %xmm0
+	cvtps2pd foo@GOT, %xmm0
diff --git a/gas/testsuite/gas/i386/x86-64-gotpcrel-2.d b/gas/testsuite/gas/i386/x86-64-gotpcrel-2.d
index 3d07631bd6a..8edc7fe2c44 100644
--- a/gas/testsuite/gas/i386/x86-64-gotpcrel-2.d
+++ b/gas/testsuite/gas/i386/x86-64-gotpcrel-2.d
@@ -8,4 +8,11 @@ Disassembly of section .text:
 
 0+ <foo>:
  +[a-f0-9]+:	48 8b 05 00 00 00 00 	mov    0x0\(%rip\),%rax        # 7 <foo\+0x7>	3: R_X86_64_GOTPCREL	foo-0x4
+ +[a-f0-9]+:	c4 e2 7d 78 25 00 00 00 00 	vpbroadcastb 0x0\(%rip\),%ymm4        # 10 <foo\+0x10>	c: R_X86_64_GOTPCREL	foo-0x4
+ +[a-f0-9]+:	62 f5 7c 18 68 05 00 00 00 00 	vcvttph2ibs 0x0\(%rip\)\{1to8\},%xmm0        # 1a <foo\+0x1a>	16: R_X86_64_GOTPCREL	foo-0x4
+ +[a-f0-9]+:	62 f5 7d 08 7b 05 00 00 00 00 	vcvtph2qq 0x0\(%rip\),%xmm0        # 24 <foo\+0x24>	20: R_X86_64_GOTPCREL	foo-0x4
+ +[a-f0-9]+:	62 f1 f5 18 5f 05 00 00 00 00 	vmaxpd 0x0\(%rip\)\{1to2\},%xmm1,%xmm0        # 2e <foo\+0x2e>	2a: R_X86_64_GOTPCREL	foo-0x4
+ +[a-f0-9]+:	0f 5a 05 00 00 00 00 	cvtps2pd 0x0\(%rip\),%xmm0        # 35 <foo\+0x35>	31: R_X86_64_GOTPCREL	foo-0x4
+ +[a-f0-9]+:	c5 fc 5a 05 c3 ff ff ff 	vcvtps2pd -0x3d\(%rip\),%ymm0        # 0 <foo>
+ +[a-f0-9]+:	66 0f 6f 05 00 00 00 00 	movdqa 0x0\(%rip\),%xmm0        # 45 <foo\+0x45>	41: R_X86_64_PC32	bar-0x4
 #pass
diff --git a/gas/testsuite/gas/i386/x86-64-gotpcrel-2.s b/gas/testsuite/gas/i386/x86-64-gotpcrel-2.s
index db5ddf579a0..6f1c081b6a1 100644
--- a/gas/testsuite/gas/i386/x86-64-gotpcrel-2.s
+++ b/gas/testsuite/gas/i386/x86-64-gotpcrel-2.s
@@ -1,3 +1,10 @@
 	.text
 foo:
 	movq	foo@GOTPCREL(%rip), %rax
+	vpbroadcastb foo@GOTPCREL(%rip), %ymm4		# Byte memory
+	vcvttph2ibs foo@GOTPCREL(%rip){1to8}, %xmm0	# Word memory
+	vcvtph2qq foo@GOTPCREL(%rip), %xmm0		# Dword memory
+	vmaxpd	foo@GOTPCREL(%rip){1to2}, %xmm1, %xmm0	# Qword memory
+	cvtps2pd foo@GOTPCREL(%rip), %xmm0		# Qword memory
+	vcvtps2pd foo(%rip), %ymm0			# Xmmword memory
+	movdqa	bar(%rip), %xmm0			# Xmmword memory
diff --git a/gas/testsuite/gas/i386/x86-64-inval-got.l b/gas/testsuite/gas/i386/x86-64-inval-got.l
new file mode 100644
index 00000000000..565c080e057
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-inval-got.l
@@ -0,0 +1,34 @@
+.*: Assembler messages:
+.*:3: Error: .*
+.*:4: Error: .*
+.*:5: Error: .*
+.*:6: Error: .*
+.*:7: Error: .*
+.*:8: Error: .*
+GAS LISTING .*
+
+
+[ 	]*1[ 	]+\.text
+[ 	]*2[ 	]+\# All the followings should be illegal for x86-64\.
+[ 	]*3[ 	]+\?\?\?\? 0F011500 		lgdt	foo@GOTPCREL\(%rip\)
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*3[ 	]+000000
+[ 	]*4[ 	]+\?\?\?\? 62F27548 		vpermb	foo@GOTPCREL\(%rip\), %zmm1, %zmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*4[ 	]+8D050000 
+[ 	]*4[ 	]+0000
+[ 	]*5[ 	]+\?\?\?\? C5F15F05 		vmaxpd	foo@GOTPCREL\(%rip\), %xmm1, %xmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*5[ 	]+00000000 
+[ 	]*6[ 	]+\?\?\?\? 62F57C08 		vcvttph2ibs foo@GOTPCREL\(%rip\), %xmm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*6[ 	]+68050000 
+[ 	]*6[ 	]+0000
+[ 	]*7[ 	]+\?\?\?\? C4E27849 		ldtilecfg foo@GOTPCREL\(%rip\)
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*7[ 	]+05000000 
+[ 	]*7[ 	]+00
+[ 	]*8[ 	]+\?\?\?\? C5FC5A05 		vcvtps2pd foo@GOTPCREL\(%rip\), %ymm0
+\*\*\*\*  Error: invalid GOT memory operand
+[ 	]*8[ 	]+00000000 
+#pass
diff --git a/gas/testsuite/gas/i386/x86-64-inval-got.s b/gas/testsuite/gas/i386/x86-64-inval-got.s
new file mode 100644
index 00000000000..265ff1976b6
--- /dev/null
+++ b/gas/testsuite/gas/i386/x86-64-inval-got.s
@@ -0,0 +1,8 @@
+	.text
+# All the followings should be illegal for x86-64.
+	lgdt	foo@GOTPCREL(%rip)
+	vpermb	foo@GOTPCREL(%rip), %zmm1, %zmm0
+	vmaxpd	foo@GOTPCREL(%rip), %xmm1, %xmm0
+	vcvttph2ibs foo@GOTPCREL(%rip), %xmm0
+	ldtilecfg foo@GOTPCREL(%rip)
+	vcvtps2pd foo@GOTPCREL(%rip), %ymm0
diff --git a/gas/testsuite/gas/i386/x86-64.exp b/gas/testsuite/gas/i386/x86-64.exp
index edacbaa0f20..f1462e36131 100644
--- a/gas/testsuite/gas/i386/x86-64.exp
+++ b/gas/testsuite/gas/i386/x86-64.exp
@@ -71,6 +71,7 @@ run_dump_test "x86-64-stack"
 run_dump_test "x86-64-stack-intel"
 run_dump_test "x86-64-stack-suffix"
 run_list_test "x86-64-inval" "-al"
+run_list_test "x86-64-inval-got" "-al"
 run_list_test "x86-64-segment" "-al"
 run_dump_test "x86-64-segovr"
 run_list_test "x86-64-inval-seg" "-al"
-- 
2.48.1



More information about the Binutils mailing list