All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values
@ 2019-02-15 20:14 Paul Burton
  2019-02-15 20:14 ` [PATCH 2/2] MIPS: eBPF: Remove REG_32BIT_ZERO_EX Paul Burton
  2019-02-19 20:48 ` [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values Paul Burton
  0 siblings, 2 replies; 3+ messages in thread
From: Paul Burton @ 2019-02-15 20:14 UTC (permalink / raw)
  To: linux-mips, Alexei Starovoitov, Daniel Borkmann,
	Martin KaFai Lau, Song Liu, Yonghong Song, netdev
  Cc: linux-kernel, Jiong Wang, Paul Burton, stable

The function prototype used to call JITed eBPF code (ie. the type of the
struct bpf_prog bpf_func field) returns an unsigned int. The MIPS n64
ABI that MIPS64 kernels target defines that 32 bit integers should
always be sign extended when passed in registers as either arguments or
return values.

This means that when returning any value which may not already be sign
extended (ie. of type REG_64BIT or REG_32BIT_ZERO_EX) we need to perform
that sign extension in order to comply with the n64 ABI. Without this we
see strange looking test failures from test_bpf.ko, such as:

  test_bpf: #65 ALU64_MOV_X:
    dst = 4294967295 jited:1 ret -1 != -1 FAIL (1 times)

Although the return value printed matches the expected value, this is
only because printf is only examining the least significant 32 bits of
the 64 bit register value we returned. The register holding the expected
value is sign extended whilst the v0 register was set to a zero extended
value by our JITed code, so when compared by a conditional branch
instruction the values are not equal.

We already handle this when the return value register is of type
REG_32BIT_ZERO_EX, so simply extend this to also cover REG_64BIT.

Signed-off-by: Paul Burton <paul.burton@mips.com>
Fixes: b6bd53f9c4e8 ("MIPS: Add missing file for eBPF JIT.")
Cc: stable@vger.kernel.org # v4.13+
---

 arch/mips/net/ebpf_jit.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c
index b16710a8a9e7..715415fa2345 100644
--- a/arch/mips/net/ebpf_jit.c
+++ b/arch/mips/net/ebpf_jit.c
@@ -343,12 +343,15 @@ static int build_int_epilogue(struct jit_ctx *ctx, int dest_reg)
 	const struct bpf_prog *prog = ctx->skf;
 	int stack_adjust = ctx->stack_size;
 	int store_offset = stack_adjust - 8;
+	enum reg_val_type td;
 	int r0 = MIPS_R_V0;
 
-	if (dest_reg == MIPS_R_RA &&
-	    get_reg_val_type(ctx, prog->len, BPF_REG_0) == REG_32BIT_ZERO_EX)
+	if (dest_reg == MIPS_R_RA) {
 		/* Don't let zero extended value escape. */
-		emit_instr(ctx, sll, r0, r0, 0);
+		td = get_reg_val_type(ctx, prog->len, BPF_REG_0);
+		if (td == REG_64BIT || td == REG_32BIT_ZERO_EX)
+			emit_instr(ctx, sll, r0, r0, 0);
+	}
 
 	if (ctx->flags & EBPF_SAVE_RA) {
 		emit_instr(ctx, ld, MIPS_R_RA, store_offset, MIPS_R_SP);
-- 
2.20.1


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

* [PATCH 2/2] MIPS: eBPF: Remove REG_32BIT_ZERO_EX
  2019-02-15 20:14 [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values Paul Burton
@ 2019-02-15 20:14 ` Paul Burton
  2019-02-19 20:48 ` [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values Paul Burton
  1 sibling, 0 replies; 3+ messages in thread
From: Paul Burton @ 2019-02-15 20:14 UTC (permalink / raw)
  To: linux-mips, Alexei Starovoitov, Daniel Borkmann,
	Martin KaFai Lau, Song Liu, Yonghong Song, netdev
  Cc: linux-kernel, Jiong Wang, Paul Burton

REG_32BIT_ZERO_EX and REG_64BIT are always handled in exactly the same
way, and reg_val_propagate_range() never actually sets any register to
type REG_32BIT_ZERO_EX.

Remove the redundant & unused REG_32BIT_ZERO_EX.

Signed-off-by: Paul Burton <paul.burton@mips.com>
---

 arch/mips/net/ebpf_jit.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/arch/mips/net/ebpf_jit.c b/arch/mips/net/ebpf_jit.c
index 715415fa2345..76e9bf88d3b9 100644
--- a/arch/mips/net/ebpf_jit.c
+++ b/arch/mips/net/ebpf_jit.c
@@ -79,8 +79,6 @@ enum reg_val_type {
 	REG_64BIT_32BIT,
 	/* 32-bit compatible, need truncation for 64-bit ops. */
 	REG_32BIT,
-	/* 32-bit zero extended. */
-	REG_32BIT_ZERO_EX,
 	/* 32-bit no sign/zero extension needed. */
 	REG_32BIT_POS
 };
@@ -349,7 +347,7 @@ static int build_int_epilogue(struct jit_ctx *ctx, int dest_reg)
 	if (dest_reg == MIPS_R_RA) {
 		/* Don't let zero extended value escape. */
 		td = get_reg_val_type(ctx, prog->len, BPF_REG_0);
-		if (td == REG_64BIT || td == REG_32BIT_ZERO_EX)
+		if (td == REG_64BIT)
 			emit_instr(ctx, sll, r0, r0, 0);
 	}
 
@@ -695,7 +693,7 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
 		if (dst < 0)
 			return dst;
 		td = get_reg_val_type(ctx, this_idx, insn->dst_reg);
-		if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) {
+		if (td == REG_64BIT) {
 			/* sign extend */
 			emit_instr(ctx, sll, dst, dst, 0);
 		}
@@ -710,7 +708,7 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
 		if (dst < 0)
 			return dst;
 		td = get_reg_val_type(ctx, this_idx, insn->dst_reg);
-		if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) {
+		if (td == REG_64BIT) {
 			/* sign extend */
 			emit_instr(ctx, sll, dst, dst, 0);
 		}
@@ -724,7 +722,7 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
 		if (dst < 0)
 			return dst;
 		td = get_reg_val_type(ctx, this_idx, insn->dst_reg);
-		if (td == REG_64BIT || td == REG_32BIT_ZERO_EX)
+		if (td == REG_64BIT)
 			/* sign extend */
 			emit_instr(ctx, sll, dst, dst, 0);
 		if (insn->imm == 1) {
@@ -863,13 +861,13 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
 		if (src < 0 || dst < 0)
 			return -EINVAL;
 		td = get_reg_val_type(ctx, this_idx, insn->dst_reg);
-		if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) {
+		if (td == REG_64BIT) {
 			/* sign extend */
 			emit_instr(ctx, sll, dst, dst, 0);
 		}
 		did_move = false;
 		ts = get_reg_val_type(ctx, this_idx, insn->src_reg);
-		if (ts == REG_64BIT || ts == REG_32BIT_ZERO_EX) {
+		if (ts == REG_64BIT) {
 			int tmp_reg = MIPS_R_AT;
 
 			if (bpf_op == BPF_MOV) {
@@ -1257,8 +1255,7 @@ static int build_one_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
 		if (insn->imm == 64 && td == REG_32BIT)
 			emit_instr(ctx, dinsu, dst, MIPS_R_ZERO, 32, 32);
 
-		if (insn->imm != 64 &&
-		    (td == REG_64BIT || td == REG_32BIT_ZERO_EX)) {
+		if (insn->imm != 64 && td == REG_64BIT) {
 			/* sign extend */
 			emit_instr(ctx, sll, dst, dst, 0);
 		}
-- 
2.20.1


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

* Re: [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values
  2019-02-15 20:14 [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values Paul Burton
  2019-02-15 20:14 ` [PATCH 2/2] MIPS: eBPF: Remove REG_32BIT_ZERO_EX Paul Burton
@ 2019-02-19 20:48 ` Paul Burton
  1 sibling, 0 replies; 3+ messages in thread
From: Paul Burton @ 2019-02-19 20:48 UTC (permalink / raw)
  To: Paul Burton
  Cc: linux-mips, Alexei Starovoitov, Daniel Borkmann,
	Martin KaFai Lau, Song Liu, Yonghong Song, netdev, linux-kernel,
	Jiong Wang, Paul Burton, stable, linux-mips

Hello,

Paul Burton wrote:
> The function prototype used to call JITed eBPF code (ie. the type of the
> struct bpf_prog bpf_func field) returns an unsigned int. The MIPS n64
> ABI that MIPS64 kernels target defines that 32 bit integers should
> always be sign extended when passed in registers as either arguments or
> return values.
> 
> This means that when returning any value which may not already be sign
> extended (ie. of type REG_64BIT or REG_32BIT_ZERO_EX) we need to perform
> that sign extension in order to comply with the n64 ABI. Without this we
> see strange looking test failures from test_bpf.ko, such as:
> 
> test_bpf: #65 ALU64_MOV_X:
> dst = 4294967295 jited:1 ret -1 != -1 FAIL (1 times)
> 
> Although the return value printed matches the expected value, this is
> only because printf is only examining the least significant 32 bits of
> the 64 bit register value we returned. The register holding the expected
> value is sign extended whilst the v0 register was set to a zero extended
> value by our JITed code, so when compared by a conditional branch
> instruction the values are not equal.
> 
> We already handle this when the return value register is of type
> REG_32BIT_ZERO_EX, so simply extend this to also cover REG_64BIT.
> 
> Signed-off-by: Paul Burton <paul.burton@mips.com>
> Fixes: b6bd53f9c4e8 ("MIPS: Add missing file for eBPF JIT.")
> Cc: stable@vger.kernel.org # v4.13+

Series applied to mips-next.

Thanks,
    Paul

[ This message was auto-generated; if you believe anything is incorrect
  then please email paul.burton@mips.com to report it. ]

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

end of thread, other threads:[~2019-02-19 20:48 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-15 20:14 [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values Paul Burton
2019-02-15 20:14 ` [PATCH 2/2] MIPS: eBPF: Remove REG_32BIT_ZERO_EX Paul Burton
2019-02-19 20:48 ` [PATCH 1/2] MIPS: eBPF: Always return sign extended 32b values Paul Burton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.