bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits
@ 2020-03-05 23:44 Luke Nelson
  2020-03-05 23:44 ` [PATCH bpf 2/2] selftests: bpf: add test for JMP32 JSET BPF_X with upper bits set Luke Nelson
  2020-03-06 14:03 ` [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits Daniel Borkmann
  0 siblings, 2 replies; 3+ messages in thread
From: Luke Nelson @ 2020-03-05 23:44 UTC (permalink / raw)
  To: bpf
  Cc: Luke Nelson, Xi Wang, Wang YanQing, David S. Miller,
	Alexey Kuznetsov, Hideaki YOSHIFUJI, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, x86,
	Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu,
	Yonghong Song, Andrii Nakryiko, Shuah Khan, Jiong Wang, netdev,
	linux-kernel, linux-kselftest

The current x32 BPF JIT is incorrect for JMP32 JSET BPF_X when the upper
32 bits of operand registers are non-zero in certain situations.

The problem is in the following code:

  case BPF_JMP | BPF_JSET | BPF_X:
  case BPF_JMP32 | BPF_JSET | BPF_X:
  ...

  /* and dreg_lo,sreg_lo */
  EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo));
  /* and dreg_hi,sreg_hi */
  EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
  /* or dreg_lo,dreg_hi */
  EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));

This code checks the upper bits of the operand registers regardless if
the BPF instruction is BPF_JMP32 or BPF_JMP64. Registers dreg_hi and
dreg_lo are not loaded from the stack for BPF_JMP32, however, they can
still be polluted with values from previous instructions.

The following BPF program demonstrates the bug. The jset64 instruction
loads the temporary registers and performs the jump, since ((u64)r7 &
(u64)r8) is non-zero. The jset32 should _not_ be taken, as the lower
32 bits are all zero, however, the current JIT will take the branch due
the pollution of temporary registers from the earlier jset64.

  mov64    r0, 0
  ld64     r7, 0x8000000000000000
  ld64     r8, 0x8000000000000000
  jset64   r7, r8, 1
  exit
  jset32   r7, r8, 1
  mov64    r0, 2
  exit

The expected return value of this program is 2; under the buggy x32 JIT
it returns 0. The fix is to skip using the upper 32 bits for jset32 and
compare the upper 32 bits for jset64 only.

All tests in test_bpf.ko and selftests/bpf/test_verifier continue to
pass with this change.

We found this bug using our automated verification tool, Serval.

Fixes: 69f827eb6e14 ("x32: bpf: implement jitting of JMP32")
Co-developed-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
---
 arch/x86/net/bpf_jit_comp32.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
index 393d251798c0..4d2a7a764602 100644
--- a/arch/x86/net/bpf_jit_comp32.c
+++ b/arch/x86/net/bpf_jit_comp32.c
@@ -2039,10 +2039,12 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
 			}
 			/* and dreg_lo,sreg_lo */
 			EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo));
-			/* and dreg_hi,sreg_hi */
-			EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
-			/* or dreg_lo,dreg_hi */
-			EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
+			if (is_jmp64) {
+				/* and dreg_hi,sreg_hi */
+				EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi));
+				/* or dreg_lo,dreg_hi */
+				EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi));
+			}
 			goto emit_cond_jmp;
 		}
 		case BPF_JMP | BPF_JSET | BPF_K:
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH bpf 2/2] selftests: bpf: add test for JMP32 JSET BPF_X with upper bits set
  2020-03-05 23:44 [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits Luke Nelson
@ 2020-03-05 23:44 ` Luke Nelson
  2020-03-06 14:03 ` [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits Daniel Borkmann
  1 sibling, 0 replies; 3+ messages in thread
From: Luke Nelson @ 2020-03-05 23:44 UTC (permalink / raw)
  To: bpf
  Cc: Luke Nelson, Xi Wang, Wang YanQing, David S. Miller,
	Alexey Kuznetsov, Hideaki YOSHIFUJI, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, x86,
	Alexei Starovoitov, Daniel Borkmann, Martin KaFai Lau, Song Liu,
	Yonghong Song, Andrii Nakryiko, Shuah Khan, Jiong Wang, netdev,
	linux-kernel, linux-kselftest

The existing tests attempt to check that JMP32 JSET ignores the upper
bits in the operand registers. However, the tests missed one such bug in
the x32 JIT that is only uncovered when a previous instruction pollutes
the upper 32 bits of the registers.

This patch adds a new test case that catches the bug by first executing
a 64-bit JSET to pollute the upper 32-bits of the temporary registers,
followed by a 32-bit JSET which should ignore the upper 32 bits.

Co-developed-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
---
 tools/testing/selftests/bpf/verifier/jmp32.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/tools/testing/selftests/bpf/verifier/jmp32.c b/tools/testing/selftests/bpf/verifier/jmp32.c
index bf0322eb5346..bd5cae4a7f73 100644
--- a/tools/testing/selftests/bpf/verifier/jmp32.c
+++ b/tools/testing/selftests/bpf/verifier/jmp32.c
@@ -61,6 +61,21 @@
 	},
 	.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
+{
+	"jset32: ignores upper bits",
+	.insns = {
+	BPF_MOV64_IMM(BPF_REG_0, 0),
+	BPF_LD_IMM64(BPF_REG_7, 0x8000000000000000),
+	BPF_LD_IMM64(BPF_REG_8, 0x8000000000000000),
+	BPF_JMP_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1),
+	BPF_EXIT_INSN(),
+	BPF_JMP32_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1),
+	BPF_MOV64_IMM(BPF_REG_0, 2),
+	BPF_EXIT_INSN(),
+	},
+	.result = ACCEPT,
+	.retval = 2,
+},
 {
 	"jset32: min/max deduction",
 	.insns = {
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits
  2020-03-05 23:44 [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits Luke Nelson
  2020-03-05 23:44 ` [PATCH bpf 2/2] selftests: bpf: add test for JMP32 JSET BPF_X with upper bits set Luke Nelson
@ 2020-03-06 14:03 ` Daniel Borkmann
  1 sibling, 0 replies; 3+ messages in thread
From: Daniel Borkmann @ 2020-03-06 14:03 UTC (permalink / raw)
  To: Luke Nelson, bpf
  Cc: Luke Nelson, Xi Wang, Wang YanQing, David S. Miller,
	Alexey Kuznetsov, Hideaki YOSHIFUJI, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, H. Peter Anvin, x86,
	Alexei Starovoitov, Martin KaFai Lau, Song Liu, Yonghong Song,
	Andrii Nakryiko, Shuah Khan, Jiong Wang, netdev, linux-kernel,
	linux-kselftest

On 3/6/20 12:44 AM, Luke Nelson wrote:
> The current x32 BPF JIT is incorrect for JMP32 JSET BPF_X when the upper
> 32 bits of operand registers are non-zero in certain situations.
[...]
> We found this bug using our automated verification tool, Serval.
> 
> Fixes: 69f827eb6e14 ("x32: bpf: implement jitting of JMP32")
> Co-developed-by: Xi Wang <xi.wang@gmail.com>
> Signed-off-by: Xi Wang <xi.wang@gmail.com>
> Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>

Applied both, thanks for the fix!

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-03-06 14:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-05 23:44 [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits Luke Nelson
2020-03-05 23:44 ` [PATCH bpf 2/2] selftests: bpf: add test for JMP32 JSET BPF_X with upper bits set Luke Nelson
2020-03-06 14:03 ` [PATCH bpf 1/2] bpf, x32: fix bug with JMP32 JSET BPF_X checking upper bits Daniel Borkmann

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 NNTP newsgroup(s).