linux-riscv.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations
@ 2019-05-30 19:07 Luke Nelson
  2019-05-30 19:08 ` [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations Luke Nelson
  2019-05-30 20:53 ` [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Song Liu
  0 siblings, 2 replies; 7+ messages in thread
From: Luke Nelson @ 2019-05-30 19:07 UTC (permalink / raw)
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Luke Nelson,
	Björn Töpel, Palmer Dabbelt, Alexei Starovoitov,
	linux-kernel, netdev, Yonghong Song, linux-riscv,
	Martin KaFai Lau, Xi Wang

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


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations
  2019-05-30 19:07 [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Luke Nelson
@ 2019-05-30 19:08 ` Luke Nelson
  2019-05-30 20:30   ` Jiong Wang
  2019-05-30 20:53 ` [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Song Liu
  1 sibling, 1 reply; 7+ messages in thread
From: Luke Nelson @ 2019-05-30 19:08 UTC (permalink / raw)
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Luke Nelson,
	Björn Töpel, Palmer Dabbelt, Alexei Starovoitov,
	linux-kernel, netdev, Yonghong Song, linux-riscv,
	Martin KaFai Lau, Xi Wang

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


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations
  2019-05-30 19:08 ` [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations Luke Nelson
@ 2019-05-30 20:30   ` Jiong Wang
  0 siblings, 0 replies; 7+ messages in thread
From: Jiong Wang @ 2019-05-30 20:30 UTC (permalink / raw)
  To: Luke Nelson
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Björn Töpel,
	Palmer Dabbelt, Alexei Starovoitov, linux-kernel, netdev,
	Yonghong Song, linux-riscv, Martin KaFai Lau, Xi Wang


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

> 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 = {


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations
  2019-05-30 19:07 [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Luke Nelson
  2019-05-30 19:08 ` [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations Luke Nelson
@ 2019-05-30 20:53 ` Song Liu
  2019-05-30 22:34   ` Luke Nelson
  1 sibling, 1 reply; 7+ messages in thread
From: Song Liu @ 2019-05-30 20:53 UTC (permalink / raw)
  To: Luke Nelson
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Björn Töpel,
	Palmer Dabbelt, Alexei Starovoitov, open list, Networking,
	Yonghong Song, linux-riscv, Martin KaFai Lau, Xi Wang

On Thu, May 30, 2019 at 12:09 PM Luke Nelson <luke.r.nels@gmail.com> 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

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

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations
  2019-05-30 20:53 ` [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Song Liu
@ 2019-05-30 22:34   ` Luke Nelson
  2019-05-30 23:08     ` Song Liu
  0 siblings, 1 reply; 7+ messages in thread
From: Luke Nelson @ 2019-05-30 22:34 UTC (permalink / raw)
  To: Song Liu
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Björn Töpel,
	Palmer Dabbelt, Alexei Starovoitov, open list, Networking,
	Yonghong Song, linux-riscv, Martin KaFai Lau, Xi Wang

On Thu, May 30, 2019 at 1:53 PM Song Liu <liu.song.a23@gmail.com> 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?

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations
  2019-05-30 22:34   ` Luke Nelson
@ 2019-05-30 23:08     ` Song Liu
  2019-05-31  7:22       ` Jiong Wang
  0 siblings, 1 reply; 7+ messages in thread
From: Song Liu @ 2019-05-30 23:08 UTC (permalink / raw)
  To: Luke Nelson
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Björn Töpel,
	Palmer Dabbelt, Alexei Starovoitov, open list, Networking,
	Yonghong Song, linux-riscv, Martin KaFai Lau, Xi Wang

On Thu, May 30, 2019 at 3:34 PM Luke Nelson <luke.r.nels@gmail.com> wrote:
>
> On Thu, May 30, 2019 at 1:53 PM Song Liu <liu.song.a23@gmail.com> 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?

Yes, let's do follow up patch.

Thanks,
Song

_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

* Re: [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations
  2019-05-30 23:08     ` Song Liu
@ 2019-05-31  7:22       ` Jiong Wang
  0 siblings, 0 replies; 7+ messages in thread
From: Jiong Wang @ 2019-05-31  7:22 UTC (permalink / raw)
  To: Luke Nelson, Song Liu
  Cc: Song Liu, Albert Ou, bpf, Daniel Borkmann, Björn Töpel,
	Palmer Dabbelt, Alexei Starovoitov, open list, Networking,
	Yonghong Song, linux-riscv, Martin KaFai Lau, Xi Wang


Song Liu writes:

> On Thu, May 30, 2019 at 3:34 PM Luke Nelson <luke.r.nels@gmail.com> wrote:
>>
>> On Thu, May 30, 2019 at 1:53 PM Song Liu <liu.song.a23@gmail.com> 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?

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


_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv

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

end of thread, other threads:[~2019-05-31  7:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-30 19:07 [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Luke Nelson
2019-05-30 19:08 ` [PATCH 2/2] bpf: test_bpf: add tests for upper bits of 32-bit operations Luke Nelson
2019-05-30 20:30   ` Jiong Wang
2019-05-30 20:53 ` [PATCH 1/2] bpf, riscv: fix bugs in JIT for 32-bit ALU operations Song Liu
2019-05-30 22:34   ` Luke Nelson
2019-05-30 23:08     ` Song Liu
2019-05-31  7:22       ` Jiong Wang

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