[PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations

Subsystems: bpf jit for risc-v (32-bit), bpf jit for risc-v (64-bit), bpf [general] (safe dynamic programs and tools), risc-v architecture, the rest

STALE2650d

7 messages, 3 authors, 2019-05-31 · open the first message on its own page

[PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations

From: Luke Nelson <luke.r.nels@gmail.com>
Date: 2019-05-30 19:08:17

In BPF, 32-bit ALU operations should zero-extend their results into
the 64-bit registers.  The current BPF JIT on RISC-V emits incorrect
instructions that perform either sign extension only (e.g., addw/subw)
or no extension on 32-bit add, sub, and, or, xor, lsh, rsh, arsh,
and neg.  This behavior diverges from the interpreter and JITs for
other architectures.

This patch fixes the bugs by performing zero extension on the destination
register of 32-bit ALU operations.

Fixes: 2353ecc6f91f ("bpf, riscv: add BPF JIT for RV64G")
Cc: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
---
 arch/riscv/net/bpf_jit_comp.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
diff --git a/arch/riscv/net/bpf_jit_comp.c b/arch/riscv/net/bpf_jit_comp.c
index 80b12aa5e10d..426d5c33ea90 100644
--- a/arch/riscv/net/bpf_jit_comp.c
+++ b/arch/riscv/net/bpf_jit_comp.c
@@ -751,22 +751,32 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_ALU | BPF_ADD | BPF_X:
 	case BPF_ALU64 | BPF_ADD | BPF_X:
 		emit(is64 ? rv_add(rd, rd, rs) : rv_addw(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_SUB | BPF_X:
 	case BPF_ALU64 | BPF_SUB | BPF_X:
 		emit(is64 ? rv_sub(rd, rd, rs) : rv_subw(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_AND | BPF_X:
 	case BPF_ALU64 | BPF_AND | BPF_X:
 		emit(rv_and(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_OR | BPF_X:
 	case BPF_ALU64 | BPF_OR | BPF_X:
 		emit(rv_or(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_XOR | BPF_X:
 	case BPF_ALU64 | BPF_XOR | BPF_X:
 		emit(rv_xor(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_MUL | BPF_X:
 	case BPF_ALU64 | BPF_MUL | BPF_X:
@@ -789,14 +799,20 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_ALU | BPF_LSH | BPF_X:
 	case BPF_ALU64 | BPF_LSH | BPF_X:
 		emit(is64 ? rv_sll(rd, rd, rs) : rv_sllw(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_RSH | BPF_X:
 	case BPF_ALU64 | BPF_RSH | BPF_X:
 		emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_ARSH | BPF_X:
 	case BPF_ALU64 | BPF_ARSH | BPF_X:
 		emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 
 	/* dst = -dst */
@@ -804,6 +820,8 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_ALU64 | BPF_NEG:
 		emit(is64 ? rv_sub(rd, RV_REG_ZERO, rd) :
 		     rv_subw(rd, RV_REG_ZERO, rd), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 
 	/* dst = BSWAP##imm(dst) */
@@ -958,14 +976,20 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 	case BPF_ALU | BPF_LSH | BPF_K:
 	case BPF_ALU64 | BPF_LSH | BPF_K:
 		emit(is64 ? rv_slli(rd, rd, imm) : rv_slliw(rd, rd, imm), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_RSH | BPF_K:
 	case BPF_ALU64 | BPF_RSH | BPF_K:
 		emit(is64 ? rv_srli(rd, rd, imm) : rv_srliw(rd, rd, imm), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 	case BPF_ALU | BPF_ARSH | BPF_K:
 	case BPF_ALU64 | BPF_ARSH | BPF_K:
 		emit(is64 ? rv_srai(rd, rd, imm) : rv_sraiw(rd, rd, imm), ctx);
+		if (!is64)
+			emit_zext_32(rd, ctx);
 		break;
 
 	/* JUMP off */
-- 
2.19.1

[PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations

From: Luke Nelson <luke.r.nels@gmail.com>
Date: 2019-05-30 19:08:23

This commit introduces tests that validate the upper 32 bits
of the result of 32-bit BPF ALU operations.

The existing tests for 32-bit operations do not check the upper 32
bits of results because the exit instruction truncates the result.
These tests perform a 32-bit ALU operation followed by a right shift.
These tests can catch subtle bugs in the extension behavior of JITed
instructions, including several bugs in the RISC-V BPF JIT, fixed in
another patch.

The added tests pass the JIT and interpreter on x86, as well as the
JIT and interpreter of RISC-V once the zero extension bugs were fixed.

Cc: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
---
 lib/test_bpf.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 0845f635f404..4580dc0220f1 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -2461,6 +2461,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		"ALU_ADD_X: (1 + 4294967294) >> 32 + 4294967294 = 4294967294",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 1U),
+			BPF_ALU32_IMM(BPF_MOV, R1, 4294967294U),
+			BPF_ALU32_REG(BPF_ADD, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_REG(BPF_ADD, R0, R1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 4294967294U } },
+	},
 	{
 		"ALU64_ADD_X: 1 + 2 = 3",
 		.u.insns_int = {
@@ -2812,6 +2826,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		"ALU_SUB_X: (4294967295 - 1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 4294967295U),
+			BPF_ALU32_IMM(BPF_MOV, R1, 1U),
+			BPF_ALU32_REG(BPF_SUB, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_REG(BPF_ADD, R0, R1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_SUB_X: 3 - 1 = 2",
 		.u.insns_int = {
@@ -3391,6 +3419,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xffffffff } },
 	},
+	{
+		"ALU_AND_X: (-1 & -1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, -1UL),
+			BPF_LD_IMM64(R1, -1UL),
+			BPF_ALU32_REG(BPF_AND, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1U),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_AND_X: 3 & 2 = 2",
 		.u.insns_int = {
@@ -3533,6 +3575,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xffffffff } },
 	},
+	{
+		"ALU_OR_X: (0 & -1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0),
+			BPF_LD_IMM64(R1, -1UL),
+			BPF_ALU32_REG(BPF_OR, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1U),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_OR_X: 1 | 2 = 3",
 		.u.insns_int = {
@@ -3675,6 +3731,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xfffffffe } },
 	},
+	{
+		"ALU_XOR_X: (0 ^ -1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0),
+			BPF_LD_IMM64(R1, -1UL),
+			BPF_ALU32_REG(BPF_XOR, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1U),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_XOR_X: 5 ^ 6 = 3",
 		.u.insns_int = {
@@ -3817,6 +3887,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0x80000000 } },
 	},
+	{
+		"ALU_LSH_X: (1 << 31) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 1),
+			BPF_ALU32_IMM(BPF_MOV, R1, 31),
+			BPF_ALU32_REG(BPF_LSH, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_LSH_X: 1 << 1 = 2",
 		.u.insns_int = {
@@ -3842,6 +3926,19 @@ static struct bpf_test tests[] = {
 		{ { 0, 0x80000000 } },
 	},
 	/* BPF_ALU | BPF_LSH | BPF_K */
+	{
+		"ALU_LSH_K: (1 << 31) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 1),
+			BPF_ALU32_IMM(BPF_LSH, R0, 31),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU_LSH_K: 1 << 1 = 2",
 		.u.insns_int = {
@@ -3911,6 +4008,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		"ALU_RSH_X: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_MOV, R1, 0),
+			BPF_ALU32_REG(BPF_RSH, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_RSH_X: 2 >> 1 = 1",
 		.u.insns_int = {
@@ -3936,6 +4047,19 @@ static struct bpf_test tests[] = {
 		{ { 0, 1 } },
 	},
 	/* BPF_ALU | BPF_RSH | BPF_K */
+	{
+		"ALU_RSH_K: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_RSH, R0, 0),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU_RSH_K: 2 >> 1 = 1",
 		.u.insns_int = {
@@ -3993,7 +4117,34 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xffff00ff } },
 	},
+	{
+		"ALU_ARSH_X: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_MOV, R1, 0),
+			BPF_ALU32_REG(BPF_ARSH, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	/* BPF_ALU | BPF_ARSH | BPF_K */
+	{
+		"ALU_ARSH_K: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_ARSH, R0, 0),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU_ARSH_K: 0xff00ff0000000000 >> 40 = 0xffffffffffff00ff",
 		.u.insns_int = {
@@ -4028,6 +4179,19 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 3 } },
 	},
+	{
+		"ALU_NEG: -(1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 1),
+			BPF_ALU32_IMM(BPF_NEG, R0, 0),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU64_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_NEG: -(3) = -3",
 		.u.insns_int = {
-- 
2.19.1

Re: [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations

From: Jiong Wang <hidden>
Date: 2019-05-30 20:30:45

Luke Nelson writes:
This commit introduces tests that validate the upper 32 bits
of the result of 32-bit BPF ALU operations.

The existing tests for 32-bit operations do not check the upper 32
bits of results because the exit instruction truncates the result.
These tests perform a 32-bit ALU operation followed by a right shift.
These tests can catch subtle bugs in the extension behavior of JITed
instructions, including several bugs in the RISC-V BPF JIT, fixed in
another patch.
Hi Luke,

  Have you seen the following?

    https://www.spinics.net/lists/netdev/msg573355.html

  it has been merged to bpf tree and should have full test coverage of all
  bpf insns that could write to sub-register and are exposed to JIT
  back-end.

  And AFAIK, we add new unit tests to test_verifier which is a userspace
  test infrastructure which offers more test functionality plus tests will
  go through verifier.

Regards,
Jiong
quoted hunk
The added tests pass the JIT and interpreter on x86, as well as the
JIT and interpreter of RISC-V once the zero extension bugs were fixed.

Cc: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
---
 lib/test_bpf.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 164 insertions(+)
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 0845f635f404..4580dc0220f1 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -2461,6 +2461,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		"ALU_ADD_X: (1 + 4294967294) >> 32 + 4294967294 = 4294967294",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 1U),
+			BPF_ALU32_IMM(BPF_MOV, R1, 4294967294U),
+			BPF_ALU32_REG(BPF_ADD, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_REG(BPF_ADD, R0, R1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 4294967294U } },
+	},
 	{
 		"ALU64_ADD_X: 1 + 2 = 3",
 		.u.insns_int = {
@@ -2812,6 +2826,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		"ALU_SUB_X: (4294967295 - 1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 4294967295U),
+			BPF_ALU32_IMM(BPF_MOV, R1, 1U),
+			BPF_ALU32_REG(BPF_SUB, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_REG(BPF_ADD, R0, R1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_SUB_X: 3 - 1 = 2",
 		.u.insns_int = {
@@ -3391,6 +3419,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xffffffff } },
 	},
+	{
+		"ALU_AND_X: (-1 & -1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, -1UL),
+			BPF_LD_IMM64(R1, -1UL),
+			BPF_ALU32_REG(BPF_AND, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1U),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_AND_X: 3 & 2 = 2",
 		.u.insns_int = {
@@ -3533,6 +3575,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xffffffff } },
 	},
+	{
+		"ALU_OR_X: (0 & -1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0),
+			BPF_LD_IMM64(R1, -1UL),
+			BPF_ALU32_REG(BPF_OR, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1U),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_OR_X: 1 | 2 = 3",
 		.u.insns_int = {
@@ -3675,6 +3731,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xfffffffe } },
 	},
+	{
+		"ALU_XOR_X: (0 ^ -1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0),
+			BPF_LD_IMM64(R1, -1UL),
+			BPF_ALU32_REG(BPF_XOR, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1U),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_XOR_X: 5 ^ 6 = 3",
 		.u.insns_int = {
@@ -3817,6 +3887,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0x80000000 } },
 	},
+	{
+		"ALU_LSH_X: (1 << 31) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 1),
+			BPF_ALU32_IMM(BPF_MOV, R1, 31),
+			BPF_ALU32_REG(BPF_LSH, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_LSH_X: 1 << 1 = 2",
 		.u.insns_int = {
@@ -3842,6 +3926,19 @@ static struct bpf_test tests[] = {
 		{ { 0, 0x80000000 } },
 	},
 	/* BPF_ALU | BPF_LSH | BPF_K */
+	{
+		"ALU_LSH_K: (1 << 31) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 1),
+			BPF_ALU32_IMM(BPF_LSH, R0, 31),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU_LSH_K: 1 << 1 = 2",
 		.u.insns_int = {
@@ -3911,6 +4008,20 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 1 } },
 	},
+	{
+		"ALU_RSH_X: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_MOV, R1, 0),
+			BPF_ALU32_REG(BPF_RSH, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_RSH_X: 2 >> 1 = 1",
 		.u.insns_int = {
@@ -3936,6 +4047,19 @@ static struct bpf_test tests[] = {
 		{ { 0, 1 } },
 	},
 	/* BPF_ALU | BPF_RSH | BPF_K */
+	{
+		"ALU_RSH_K: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_RSH, R0, 0),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU_RSH_K: 2 >> 1 = 1",
 		.u.insns_int = {
@@ -3993,7 +4117,34 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 0xffff00ff } },
 	},
+	{
+		"ALU_ARSH_X: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_MOV, R1, 0),
+			BPF_ALU32_REG(BPF_ARSH, R0, R1),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	/* BPF_ALU | BPF_ARSH | BPF_K */
+	{
+		"ALU_ARSH_K: (0x80000000 >> 0) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_LD_IMM64(R0, 0x80000000),
+			BPF_ALU32_IMM(BPF_ARSH, R0, 0),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU32_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU_ARSH_K: 0xff00ff0000000000 >> 40 = 0xffffffffffff00ff",
 		.u.insns_int = {
@@ -4028,6 +4179,19 @@ static struct bpf_test tests[] = {
 		{ },
 		{ { 0, 3 } },
 	},
+	{
+		"ALU_NEG: -(1) >> 32 + 1 = 1",
+		.u.insns_int = {
+			BPF_ALU32_IMM(BPF_MOV, R0, 1),
+			BPF_ALU32_IMM(BPF_NEG, R0, 0),
+			BPF_ALU64_IMM(BPF_RSH, R0, 32),
+			BPF_ALU64_IMM(BPF_ADD, R0, 1),
+			BPF_EXIT_INSN(),
+		},
+		INTERNAL,
+		{ },
+		{ { 0, 1 } },
+	},
 	{
 		"ALU64_NEG: -(3) = -3",
 		.u.insns_int = {

Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations

From: Song Liu <hidden>
Date: 2019-05-30 20:53:21

On Thu, May 30, 2019 at 12:09 PM Luke Nelson [off-list ref] wrote:
In BPF, 32-bit ALU operations should zero-extend their results into
the 64-bit registers.  The current BPF JIT on RISC-V emits incorrect
instructions that perform either sign extension only (e.g., addw/subw)
or no extension on 32-bit add, sub, and, or, xor, lsh, rsh, arsh,
and neg.  This behavior diverges from the interpreter and JITs for
other architectures.

This patch fixes the bugs by performing zero extension on the destination
register of 32-bit ALU operations.

Fixes: 2353ecc6f91f ("bpf, riscv: add BPF JIT for RV64G")
Cc: Xi Wang <xi.wang@gmail.com>
Signed-off-by: Luke Nelson <luke.r.nels@gmail.com>
This is a little messy. How about we introduce some helper function
like:

/* please find a better name... */
emit_32_or_64(bool is64, const u32 insn_32, const u32 inst_64, struct
rv_jit_context *ctx)
{
       if (is64)
            emit(insn_64, ctx);
       else {
            emit(insn_32, ctx);
           rd = xxxx;
           emit_zext_32(rd, ctx);
       }
}

Thanks,
Song
quoted hunk
---
 arch/riscv/net/bpf_jit_comp.c | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
diff --git a/arch/riscv/net/bpf_jit_comp.c b/arch/riscv/net/bpf_jit_comp.c
index 80b12aa5e10d..426d5c33ea90 100644
--- a/arch/riscv/net/bpf_jit_comp.c
+++ b/arch/riscv/net/bpf_jit_comp.c
@@ -751,22 +751,32 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
        case BPF_ALU | BPF_ADD | BPF_X:
        case BPF_ALU64 | BPF_ADD | BPF_X:
                emit(is64 ? rv_add(rd, rd, rs) : rv_addw(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_SUB | BPF_X:
        case BPF_ALU64 | BPF_SUB | BPF_X:
                emit(is64 ? rv_sub(rd, rd, rs) : rv_subw(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_AND | BPF_X:
        case BPF_ALU64 | BPF_AND | BPF_X:
                emit(rv_and(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_OR | BPF_X:
        case BPF_ALU64 | BPF_OR | BPF_X:
                emit(rv_or(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_XOR | BPF_X:
        case BPF_ALU64 | BPF_XOR | BPF_X:
                emit(rv_xor(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_MUL | BPF_X:
        case BPF_ALU64 | BPF_MUL | BPF_X:
@@ -789,14 +799,20 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
        case BPF_ALU | BPF_LSH | BPF_X:
        case BPF_ALU64 | BPF_LSH | BPF_X:
                emit(is64 ? rv_sll(rd, rd, rs) : rv_sllw(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_RSH | BPF_X:
        case BPF_ALU64 | BPF_RSH | BPF_X:
                emit(is64 ? rv_srl(rd, rd, rs) : rv_srlw(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_ARSH | BPF_X:
        case BPF_ALU64 | BPF_ARSH | BPF_X:
                emit(is64 ? rv_sra(rd, rd, rs) : rv_sraw(rd, rd, rs), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;

        /* dst = -dst */
@@ -804,6 +820,8 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
        case BPF_ALU64 | BPF_NEG:
                emit(is64 ? rv_sub(rd, RV_REG_ZERO, rd) :
                     rv_subw(rd, RV_REG_ZERO, rd), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;

        /* dst = BSWAP##imm(dst) */
@@ -958,14 +976,20 @@ static int emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
        case BPF_ALU | BPF_LSH | BPF_K:
        case BPF_ALU64 | BPF_LSH | BPF_K:
                emit(is64 ? rv_slli(rd, rd, imm) : rv_slliw(rd, rd, imm), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_RSH | BPF_K:
        case BPF_ALU64 | BPF_RSH | BPF_K:
                emit(is64 ? rv_srli(rd, rd, imm) : rv_srliw(rd, rd, imm), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;
        case BPF_ALU | BPF_ARSH | BPF_K:
        case BPF_ALU64 | BPF_ARSH | BPF_K:
                emit(is64 ? rv_srai(rd, rd, imm) : rv_sraiw(rd, rd, imm), ctx);
+               if (!is64)
+                       emit_zext_32(rd, ctx);
                break;

        /* JUMP off */
--
2.19.1

Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations

From: Luke Nelson <luke.r.nels@gmail.com>
Date: 2019-05-30 22:34:24

On Thu, May 30, 2019 at 1:53 PM Song Liu [off-list ref] wrote:
This is a little messy. How about we introduce some helper function
like:

/* please find a better name... */
emit_32_or_64(bool is64, const u32 insn_32, const u32 inst_64, struct
rv_jit_context *ctx)
{
       if (is64)
            emit(insn_64, ctx);
       else {
            emit(insn_32, ctx);
           rd = xxxx;
           emit_zext_32(rd, ctx);
       }
}
This same check is used throughout the file, maybe clean it up in a
separate patch?

Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations

From: Song Liu <hidden>
Date: 2019-05-30 23:09:09

On Thu, May 30, 2019 at 3:34 PM Luke Nelson [off-list ref] wrote:
On Thu, May 30, 2019 at 1:53 PM Song Liu [off-list ref] wrote:
quoted
This is a little messy. How about we introduce some helper function
like:

/* please find a better name... */
emit_32_or_64(bool is64, const u32 insn_32, const u32 inst_64, struct
rv_jit_context *ctx)
{
       if (is64)
            emit(insn_64, ctx);
       else {
            emit(insn_32, ctx);
           rd = xxxx;
           emit_zext_32(rd, ctx);
       }
}
This same check is used throughout the file, maybe clean it up in a
separate patch?
Yes, let's do follow up patch.

Thanks,
Song

Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations

From: Jiong Wang <hidden>
Date: 2019-05-31 07:22:57

Song Liu writes:
On Thu, May 30, 2019 at 3:34 PM Luke Nelson [off-list ref] wrote:
quoted
On Thu, May 30, 2019 at 1:53 PM Song Liu [off-list ref] wrote:
quoted
This is a little messy. How about we introduce some helper function
like:

/* please find a better name... */
emit_32_or_64(bool is64, const u32 insn_32, const u32 inst_64, struct
rv_jit_context *ctx)
{
       if (is64)
            emit(insn_64, ctx);
       else {
            emit(insn_32, ctx);
           rd = xxxx;
           emit_zext_32(rd, ctx);
       }
}
This same check is used throughout the file, maybe clean it up in a
separate patch?
We also need to enable the recent 32-bit opt (on bpf-next) on these missing
insns, like what has been done at:

  https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=66d0d5a854a6625974e7de4b874e7934988b0ef8

Perhaps the best way is to wait this patch merged back to bpf-next, then we
do two patches, the first one to enable the opt, the second one then do the
re-factor. I guess this could avoid some code conflict.

Regards,
Jiong
Yes, let's do follow up patch.

Thanks,
Song

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help