public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [COMMITTED] bpf: gas: add field overflow checking to the BPF assembler
@ 2023-07-30 19:09 Jose E. Marchesi
  0 siblings, 0 replies; only message in thread
From: Jose E. Marchesi @ 2023-07-30 19:09 UTC (permalink / raw)
  To: binutils

This patch makes the BPF assembler to throughfully check for overflow
in immediates.  This includes relaxed instructions.

Tested in bpf-unknown-none.

gas/ChangeLog:

2023-07-30  Jose E. Marchesi  <jose.marchesi@oracle.com>

	* config/tc-bpf.c (signed_overflow): Copy function from
	tc-aarch64.c.
	(encode_insn): Check for overflow in constant immediates.
	(add_relaxed_insn): Pass relax argument to encode_insn.
	(add_fixed_insn): Likewise.
	* testsuite/gas/bpf/disp16-overflow.d: New file.
	* testsuite/gas/bpf/disp16-overflow.s: Likewise.
	* testsuite/gas/bpf/disp16-overflow.l: Likewise.
	* testsuite/gas/bpf/disp32-overflow.d: Likewise.
	* testsuite/gas/bpf/disp32-overflow.s: Likewise.
	* testsuite/gas/bpf/disp32-overflow.l: Likewise.
	* testsuite/gas/bpf/imm32-overflow.d: Likewise.
	* testsuite/gas/bpf/imm32-overflow.s: Likewise.
	* testsuite/gas/bpf/imm32-overflow.l: Likewise.
	* testsuite/gas/bpf/offset16-overflow.d: Likewise.
	* testsuite/gas/bpf/offset16-overflow.s: Likewise.
	* testsuite/gas/bpf/offset16-overflow.l: Likewise.
	* testsuite/gas/bpf/disp16-overflow-relax.d: Likewise.
	* testsuite/gas/bpf/disp16-overflow-relax.l: Likewise.
	* testsuite/gas/bpf/disp16-overflow-relax.s: Likewise.
	* testsuite/gas/bpf/jump-relax-jump-be.d: New file.
	* testsuite/gas/bpf/bpf.exp: Run new tests.
---
 gas/ChangeLog                                 | 25 ++++++++
 gas/config/tc-bpf.c                           | 63 ++++++++++++++++---
 gas/testsuite/gas/bpf/bpf.exp                 |  7 +++
 gas/testsuite/gas/bpf/disp16-overflow-relax.d |  3 +
 gas/testsuite/gas/bpf/disp16-overflow-relax.l |  3 +
 gas/testsuite/gas/bpf/disp16-overflow-relax.s |  4 ++
 gas/testsuite/gas/bpf/disp16-overflow.d       |  3 +
 gas/testsuite/gas/bpf/disp16-overflow.l       |  3 +
 gas/testsuite/gas/bpf/disp16-overflow.s       |  4 ++
 gas/testsuite/gas/bpf/disp32-overflow.d       |  3 +
 gas/testsuite/gas/bpf/disp32-overflow.l       |  3 +
 gas/testsuite/gas/bpf/disp32-overflow.s       |  4 ++
 gas/testsuite/gas/bpf/imm32-overflow.d        |  3 +
 gas/testsuite/gas/bpf/imm32-overflow.l        |  3 +
 gas/testsuite/gas/bpf/imm32-overflow.s        |  4 ++
 gas/testsuite/gas/bpf/jump-relax-jump-be.d    | 25 ++++++++
 gas/testsuite/gas/bpf/offset16-overflow.d     |  3 +
 gas/testsuite/gas/bpf/offset16-overflow.l     |  3 +
 gas/testsuite/gas/bpf/offset16-overflow.s     |  4 ++
 19 files changed, 162 insertions(+), 8 deletions(-)
 create mode 100644 gas/testsuite/gas/bpf/disp16-overflow-relax.d
 create mode 100644 gas/testsuite/gas/bpf/disp16-overflow-relax.l
 create mode 100644 gas/testsuite/gas/bpf/disp16-overflow-relax.s
 create mode 100644 gas/testsuite/gas/bpf/disp16-overflow.d
 create mode 100644 gas/testsuite/gas/bpf/disp16-overflow.l
 create mode 100644 gas/testsuite/gas/bpf/disp16-overflow.s
 create mode 100644 gas/testsuite/gas/bpf/disp32-overflow.d
 create mode 100644 gas/testsuite/gas/bpf/disp32-overflow.l
 create mode 100644 gas/testsuite/gas/bpf/disp32-overflow.s
 create mode 100644 gas/testsuite/gas/bpf/imm32-overflow.d
 create mode 100644 gas/testsuite/gas/bpf/imm32-overflow.l
 create mode 100644 gas/testsuite/gas/bpf/imm32-overflow.s
 create mode 100644 gas/testsuite/gas/bpf/jump-relax-jump-be.d
 create mode 100644 gas/testsuite/gas/bpf/offset16-overflow.d
 create mode 100644 gas/testsuite/gas/bpf/offset16-overflow.l
 create mode 100644 gas/testsuite/gas/bpf/offset16-overflow.s

diff --git a/gas/ChangeLog b/gas/ChangeLog
index 1f3735d70af..ab139a9257b 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,28 @@
+2023-07-30  Jose E. Marchesi  <jose.marchesi@oracle.com>
+
+	* config/tc-bpf.c (signed_overflow): Copy function from
+	tc-aarch64.c.
+	(encode_insn): Check for overflow in constant immediates.
+	(add_relaxed_insn): Pass relax argument to encode_insn.
+	(add_fixed_insn): Likewise.
+	* testsuite/gas/bpf/disp16-overflow.d: New file.
+	* testsuite/gas/bpf/disp16-overflow.s: Likewise.
+	* testsuite/gas/bpf/disp16-overflow.l: Likewise.
+	* testsuite/gas/bpf/disp32-overflow.d: Likewise.
+	* testsuite/gas/bpf/disp32-overflow.s: Likewise.
+	* testsuite/gas/bpf/disp32-overflow.l: Likewise.
+	* testsuite/gas/bpf/imm32-overflow.d: Likewise.
+	* testsuite/gas/bpf/imm32-overflow.s: Likewise.
+	* testsuite/gas/bpf/imm32-overflow.l: Likewise.
+	* testsuite/gas/bpf/offset16-overflow.d: Likewise.
+	* testsuite/gas/bpf/offset16-overflow.s: Likewise.
+	* testsuite/gas/bpf/offset16-overflow.l: Likewise.
+	* testsuite/gas/bpf/disp16-overflow-relax.d: Likewise.
+	* testsuite/gas/bpf/disp16-overflow-relax.l: Likewise.
+	* testsuite/gas/bpf/disp16-overflow-relax.s: Likewise.
+	* testsuite/gas/bpf/jump-relax-jump-be.d: New file.
+	* testsuite/gas/bpf/bpf.exp: Run new tests.
+
 2023-07-28  Jose E. Marchesi  <jose.marchesi@oracle.com>
 
 	PR gas/30690
diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c
index 230e499aa1d..7e1bd5d40b8 100644
--- a/gas/config/tc-bpf.c
+++ b/gas/config/tc-bpf.c
@@ -272,6 +272,20 @@ md_section_align (segT segment, valueT size)
   return ((size + (1 << align) - 1) & -(1 << align));
 }
 
+/* Return non-zero if the indicated VALUE has overflowed the maximum
+   range expressible by an signed number with the indicated number of
+   BITS.  */
+
+static bool
+signed_overflow (offsetT value, unsigned bits)
+{
+  offsetT lim;
+  if (bits >= sizeof (offsetT) * 8)
+    return false;
+  lim = (offsetT) 1 << (bits - 1);
+  return (value < -lim || value >= lim);
+}
+
 \f
 /* Functions concerning relocs.  */
 
@@ -549,6 +563,11 @@ md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
       disp_is_known = 1;
     }
 
+  /* The displacement should fit in a signed 32-bit number.  */
+  if (disp_is_known && signed_overflow (disp_to_target, 32))
+    as_bad_where (fragp->fr_file, fragp->fr_line,
+                  _("signed instruction operand out of range, shall fit in 32 bits"));
+
   /* Now relax particular jump instructions.  */
   if (code == BPF_CODE_JA)
     {
@@ -835,7 +854,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
    immediates are encoded as zeroes.  */
 
 static void
-encode_insn (struct bpf_insn *insn, char *bytes)
+encode_insn (struct bpf_insn *insn, char *bytes, int relaxed)
 {
   uint8_t src, dst;
 
@@ -889,16 +908,44 @@ encode_insn (struct bpf_insn *insn, char *bytes)
   /* Now the immediates that are known to be constant.  */
 
   if (insn->has_imm32 && insn->imm32.X_op == O_constant)
-    encode_int32 (insn->imm32.X_add_number, bytes + 4);
+    {
+      int64_t imm = insn->imm32.X_add_number;
+
+      if (signed_overflow (imm, 32))
+        as_bad (_("signed immediate out of range, shall fit in 32 bits"));
+      else
+        encode_int32 (insn->imm32.X_add_number, bytes + 4);        
+    }
 
   if (insn->has_disp32 && insn->disp32.X_op == O_constant)
-    encode_int32 (insn->disp32.X_add_number, bytes + 4);
+    {
+      int64_t disp = insn->disp32.X_add_number;
+
+      if (signed_overflow (disp, 32))
+        as_bad (_("signed pc-relative offset out of range, shall fit in 32 bits"));
+      else
+        encode_int32 (insn->disp32.X_add_number, bytes + 4);
+    }
 
   if (insn->has_offset16 && insn->offset16.X_op == O_constant)
-    encode_int16 (insn->offset16.X_add_number, bytes + 2);
+    {
+      int64_t offset = insn->offset16.X_add_number;
+
+      if (signed_overflow (offset, 16))
+        as_bad (_("signed pc-relative offset out of range, shall fit in 16 bits"));
+      else
+        encode_int16 (insn->offset16.X_add_number, bytes + 2);
+    }
 
   if (insn->has_disp16 && insn->disp16.X_op == O_constant)
-    encode_int16 (insn->disp16.X_add_number, bytes + 2);
+    {
+      int64_t disp = insn->disp16.X_add_number;
+
+      if (!relaxed && signed_overflow (disp, 16))
+        as_bad (_("signed pc-relative offset out of range, shall fit in 16 bits"));
+      else
+        encode_int16 (insn->disp16.X_add_number, bytes + 2);
+    }
 
   if (insn->has_imm64 && insn->imm64.X_op == O_constant)
     {
@@ -1105,7 +1152,7 @@ add_fixed_insn (struct bpf_insn *insn)
 
   /* First encode the known parts of the instruction, including
      opcodes and constant immediates, and write them to the frag.  */
-  encode_insn (insn, bytes);
+  encode_insn (insn, bytes, 0 /* relax */);
   for (i = 0; i < insn->size; ++i)
     md_number_to_chars (this_frag + i, (valueT) bytes[i], 1);
 
@@ -1136,7 +1183,7 @@ add_relaxed_insn (struct bpf_insn *insn, expressionS *exp)
 
   /* First encode the known parts of the instruction, including
      opcodes and constant immediates, and write them to the frag.  */
-  encode_insn (insn, bytes);
+  encode_insn (insn, bytes, 1 /* relax */);
   for (i = 0; i < insn->size; ++i)
     md_number_to_chars (this_frag + i, (valueT) bytes[i], 1);
 
@@ -1555,7 +1602,7 @@ md_assemble (char *str ATTRIBUTE_UNUSED)
 #undef PARSE_ERROR
 
   /* Generate the frags and fixups for the parsed instruction.  */
-  if (do_relax && insn.is_relaxable)
+  if (do_relax && isa_spec >= BPF_V4 && insn.is_relaxable)
     {
       expressionS *relaxable_exp = NULL;
 
diff --git a/gas/testsuite/gas/bpf/bpf.exp b/gas/testsuite/gas/bpf/bpf.exp
index 6e6a0003e17..80f5a1dbc2d 100644
--- a/gas/testsuite/gas/bpf/bpf.exp
+++ b/gas/testsuite/gas/bpf/bpf.exp
@@ -65,4 +65,11 @@ if {[istarget bpf*-*-*]} {
 
     run_dump_test jump-relax-ja-be
     run_dump_test jump-relax-jump-be
+
+    # Overflow tests
+    run_dump_test offset16-overflow
+    run_dump_test disp16-overflow
+    run_dump_test disp16-overflow-relax
+    run_dump_test disp32-overflow
+    run_dump_test imm32-overflow
 }
diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.d b/gas/testsuite/gas/bpf/disp16-overflow-relax.d
new file mode 100644
index 00000000000..051e2fa4e99
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.d
@@ -0,0 +1,3 @@
+#as: -EL -misa-spec=v4
+#source: disp16-overflow-relax.s
+#error_output: disp16-overflow-relax.l
diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.l b/gas/testsuite/gas/bpf/disp16-overflow-relax.l
new file mode 100644
index 00000000000..ca572cbd0ff
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed instruction operand out of range, shall fit in 32 bits
+.*:4: Error: signed instruction operand out of range, shall fit in 32 bits
diff --git a/gas/testsuite/gas/bpf/disp16-overflow-relax.s b/gas/testsuite/gas/bpf/disp16-overflow-relax.s
new file mode 100644
index 00000000000..3953992ad07
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow-relax.s
@@ -0,0 +1,4 @@
+        jeq %r1,%r2,2147483647
+        jlt %r3,%r4,2147483648  ; Overflows.
+        jge %r5,10,-2147483648
+        ja -2147483649          ; Overflows.
diff --git a/gas/testsuite/gas/bpf/disp16-overflow.d b/gas/testsuite/gas/bpf/disp16-overflow.d
new file mode 100644
index 00000000000..5a0094ff4e1
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL -mno-relax
+#source: disp16-overflow.s
+#error_output: disp16-overflow.l
diff --git a/gas/testsuite/gas/bpf/disp16-overflow.l b/gas/testsuite/gas/bpf/disp16-overflow.l
new file mode 100644
index 00000000000..6404b1b2076
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed pc-relative offset out of range, shall fit in 16 bits
+.*:4: Error: signed pc-relative offset out of range, shall fit in 16 bits
diff --git a/gas/testsuite/gas/bpf/disp16-overflow.s b/gas/testsuite/gas/bpf/disp16-overflow.s
new file mode 100644
index 00000000000..ab66753af7d
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp16-overflow.s
@@ -0,0 +1,4 @@
+        ja 32767
+        jeq %r1,%r2,32768       ; Overflows
+        jlt %r3,%r4,-32768
+        jge %r5,10,-32769       ; Overflows
diff --git a/gas/testsuite/gas/bpf/disp32-overflow.d b/gas/testsuite/gas/bpf/disp32-overflow.d
new file mode 100644
index 00000000000..09fa1892487
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp32-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL
+#source: disp32-overflow.s
+#error_output: disp32-overflow.l
diff --git a/gas/testsuite/gas/bpf/disp32-overflow.l b/gas/testsuite/gas/bpf/disp32-overflow.l
new file mode 100644
index 00000000000..8a6b6479f07
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp32-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed pc-relative offset out of range, shall fit in 32 bits
+.*:4: Error: signed pc-relative offset out of range, shall fit in 32 bits
diff --git a/gas/testsuite/gas/bpf/disp32-overflow.s b/gas/testsuite/gas/bpf/disp32-overflow.s
new file mode 100644
index 00000000000..03a0d97e6c6
--- /dev/null
+++ b/gas/testsuite/gas/bpf/disp32-overflow.s
@@ -0,0 +1,4 @@
+        call -2147483648
+        call -2147483649        ; This overflows.
+        call 2147483647
+        call 2147483648         ; This overflows.
diff --git a/gas/testsuite/gas/bpf/imm32-overflow.d b/gas/testsuite/gas/bpf/imm32-overflow.d
new file mode 100644
index 00000000000..c8e35a93520
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm32-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL
+#source: imm32-overflow.s
+#error_output: imm32-overflow.l
diff --git a/gas/testsuite/gas/bpf/imm32-overflow.l b/gas/testsuite/gas/bpf/imm32-overflow.l
new file mode 100644
index 00000000000..f6691c49cd5
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm32-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed immediate out of range, shall fit in 32 bits
+.*:4: Error: signed immediate out of range, shall fit in 32 bits
diff --git a/gas/testsuite/gas/bpf/imm32-overflow.s b/gas/testsuite/gas/bpf/imm32-overflow.s
new file mode 100644
index 00000000000..5cb858cee05
--- /dev/null
+++ b/gas/testsuite/gas/bpf/imm32-overflow.s
@@ -0,0 +1,4 @@
+        add %r1, 2147483647
+        or %r2, 2147483648         ; This overflows.
+        xor %r3, -2147483648
+        sub %r4, -2147483649       ; This overflows.
diff --git a/gas/testsuite/gas/bpf/jump-relax-jump-be.d b/gas/testsuite/gas/bpf/jump-relax-jump-be.d
new file mode 100644
index 00000000000..5626d568734
--- /dev/null
+++ b/gas/testsuite/gas/bpf/jump-relax-jump-be.d
@@ -0,0 +1,25 @@
+#as: -EB -mdialect=normal
+#objdump: -dr -M dec
+#source: jump-relax-jump.s
+#name: Relaxation of conditional branch instructions, big-endian
+
+.*: +file format .*bpf.*
+
+Disassembly of section .text:
+
+0+ <.*>:
+   0:	1d 12 80 00 00 00 00 00 	jeq %r1,%r2,-32768
+   8:	ad 12 7f ff 00 00 00 00 	jlt %r1,%r2,32767
+  10:	bd 12 ff fd 00 00 00 00 	jle %r1,%r2,-3
+  18:	3d 12 00 01 00 00 00 00 	jge %r1,%r2,1
+  20:	05 00 00 01 00 00 00 00 	ja 1
+  28:	06 00 00 00 ff ff 7f ff 	jal -32769
+  30:	2d 12 00 01 00 00 00 00 	jgt %r1,%r2,1
+  38:	05 00 00 01 00 00 00 00 	ja 1
+  40:	06 00 00 00 00 00 80 00 	jal 32768
+  48:	1d 12 00 01 00 00 00 00 	jeq %r1,%r2,1
+  50:	05 00 00 01 00 00 00 00 	ja 1
+  58:	06 00 00 00 00 00 80 01 	jal 32769
+  60:	2d 12 00 01 00 00 00 00 	jgt %r1,%r2,1
+  68:	05 00 00 01 00 00 00 00 	ja 1
+  70:	06 00 00 00 00 00 80 01 	jal 32769
diff --git a/gas/testsuite/gas/bpf/offset16-overflow.d b/gas/testsuite/gas/bpf/offset16-overflow.d
new file mode 100644
index 00000000000..102edca6777
--- /dev/null
+++ b/gas/testsuite/gas/bpf/offset16-overflow.d
@@ -0,0 +1,3 @@
+#as: -EL
+#source: offset16-overflow.s
+#error_output: offset16-overflow.l
diff --git a/gas/testsuite/gas/bpf/offset16-overflow.l b/gas/testsuite/gas/bpf/offset16-overflow.l
new file mode 100644
index 00000000000..6404b1b2076
--- /dev/null
+++ b/gas/testsuite/gas/bpf/offset16-overflow.l
@@ -0,0 +1,3 @@
+.*: Assembler messages:
+.*:2: Error: signed pc-relative offset out of range, shall fit in 16 bits
+.*:4: Error: signed pc-relative offset out of range, shall fit in 16 bits
diff --git a/gas/testsuite/gas/bpf/offset16-overflow.s b/gas/testsuite/gas/bpf/offset16-overflow.s
new file mode 100644
index 00000000000..da9f633a337
--- /dev/null
+++ b/gas/testsuite/gas/bpf/offset16-overflow.s
@@ -0,0 +1,4 @@
+        ldxh %r2, [%r1 + 32767]
+        ldxw %r2, [%r1 + 32768]  ; This overflows
+        stxw [%r2 - 32768], %r1
+        stxdw [%r2 - 32769], %r1  ; This overflows
-- 
2.30.2


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-07-30 19:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-30 19:09 [COMMITTED] bpf: gas: add field overflow checking to the BPF assembler Jose E. Marchesi

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).