bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] bpf, mips: Validate conditional branch offsets
@ 2021-09-15 16:04 Piotr Krysiuk
  2021-09-15 17:38 ` Johan Almbladh
  2021-09-15 19:50 ` patchwork-bot+netdevbpf
  0 siblings, 2 replies; 3+ messages in thread
From: Piotr Krysiuk @ 2021-09-15 16:04 UTC (permalink / raw)
  To: bpf
  Cc: ast, daniel, andrii, paulburton, johan.almbladh, tsbogend, Piotr Krysiuk

The conditional branch instructions on MIPS use 18-bit signed offsets
allowing for a branch range of 128 KBytes (backward and forward).
However, this limit is not observed by the cBPF JIT compiler, and so
the JIT compiler emits out-of-range branches when translating certain
cBPF programs. A specific example of such a cBPF program is included in
the "BPF_MAXINSNS: exec all MSH" test from lib/test_bpf.c that executes
anomalous machine code containing incorrect branch offsets under JIT.

Furthermore, this issue can be abused to craft undesirable machine
code, where the control flow is hijacked to execute arbitrary Kernel
code.

The following steps can be used to reproduce the issue:

# echo 1 > /proc/sys/net/core/bpf_jit_enable
# modprobe test_bpf test_name="BPF_MAXINSNS: exec all MSH"

This should produce multiple warnings from build_bimm() similar to:

------------[ cut here ]------------
WARNING: CPU: 0 PID: 209 at arch/mips/mm/uasm-mips.c:210 build_insn+0x558/0x590
Micro-assembler field overflow
Modules linked in: test_bpf(+)
CPU: 0 PID: 209 Comm: modprobe Not tainted 5.14.3 #1
Stack : 00000000 807bb824 82b33c9c 801843c0 00000000 00000004 00000000 63c9b5ee
        82b33af4 80999898 80910000 80900000 82fd6030 00000001 82b33a98 82087180
        00000000 00000000 80873b28 00000000 000000fc 82b3394c 00000000 2e34312e
        6d6d6f43 809a180f 809a1836 6f6d203a 80900000 00000001 82b33bac 80900000
        00027f80 00000000 00000000 807bb824 00000000 804ed790 001cc317 00000001
        ...
Call Trace:
[<80108f44>] show_stack+0x38/0x118
[<807a7aac>] dump_stack_lvl+0x5c/0x7c
[<807a4b3c>] __warn+0xcc/0x140
[<807a4c3c>] warn_slowpath_fmt+0x8c/0xb8
[<8011e198>] build_insn+0x558/0x590
[<8011e358>] uasm_i_bne+0x20/0x2c
[<80127b48>] build_body+0xa58/0x2a94
[<80129c98>] bpf_jit_compile+0x114/0x1e4
[<80613fc4>] bpf_prepare_filter+0x2ec/0x4e4
[<8061423c>] bpf_prog_create+0x80/0xc4
[<c0a006e4>] test_bpf_init+0x300/0xba8 [test_bpf]
[<8010051c>] do_one_initcall+0x50/0x1d4
[<801c5e54>] do_init_module+0x60/0x220
[<801c8b20>] sys_finit_module+0xc4/0xfc
[<801144d0>] syscall_common+0x34/0x58

---[ end trace a287d9742503c645 ]---

Then the anomalous machine code executes:

=> 0xc0a18000:  addiu   sp,sp,-16
   0xc0a18004:  sw      s3,0(sp)
   0xc0a18008:  sw      s4,4(sp)
   0xc0a1800c:  sw      s5,8(sp)
   0xc0a18010:  sw      ra,12(sp)
   0xc0a18014:  move    s5,a0
   0xc0a18018:  move    s4,zero
   0xc0a1801c:  move    s3,zero

   # __BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0)
   0xc0a18020:  lui     t6,0x8012
   0xc0a18024:  ori     t4,t6,0x9e14
   0xc0a18028:  li      a1,0
   0xc0a1802c:  jalr    t4
   0xc0a18030:  move    a0,s5
   0xc0a18034:  bnez    v0,0xc0a1ffb8           # incorrect branch offset
   0xc0a18038:  move    v0,zero
   0xc0a1803c:  andi    s4,s3,0xf
   0xc0a18040:  b       0xc0a18048
   0xc0a18044:  sll     s4,s4,0x2
   ...

   # __BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0)
   0xc0a1ffa0:  lui     t6,0x8012
   0xc0a1ffa4:  ori     t4,t6,0x9e14
   0xc0a1ffa8:  li      a1,0
   0xc0a1ffac:  jalr    t4
   0xc0a1ffb0:  move    a0,s5
   0xc0a1ffb4:  bnez    v0,0xc0a1ffb8           # incorrect branch offset
   0xc0a1ffb8:  move    v0,zero
   0xc0a1ffbc:  andi    s4,s3,0xf
   0xc0a1ffc0:  b       0xc0a1ffc8
   0xc0a1ffc4:  sll     s4,s4,0x2

   # __BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0)
   0xc0a1ffc8:  lui     t6,0x8012
   0xc0a1ffcc:  ori     t4,t6,0x9e14
   0xc0a1ffd0:  li      a1,0
   0xc0a1ffd4:  jalr    t4
   0xc0a1ffd8:  move    a0,s5
   0xc0a1ffdc:  bnez    v0,0xc0a3ffb8           # correct branch offset
   0xc0a1ffe0:  move    v0,zero
   0xc0a1ffe4:  andi    s4,s3,0xf
   0xc0a1ffe8:  b       0xc0a1fff0
   0xc0a1ffec:  sll     s4,s4,0x2
   ...

   # epilogue
   0xc0a3ffb8:  lw      s3,0(sp)
   0xc0a3ffbc:  lw      s4,4(sp)
   0xc0a3ffc0:  lw      s5,8(sp)
   0xc0a3ffc4:  lw      ra,12(sp)
   0xc0a3ffc8:  addiu   sp,sp,16
   0xc0a3ffcc:  jr      ra
   0xc0a3ffd0:  nop

To mitigate this issue, we assert the branch ranges for each emit call
that could generate an out-of-range branch.

Fixes: 36366e367ee9 ("MIPS: BPF: Restore MIPS32 cBPF JIT")
Fixes: c6610de353da ("MIPS: net: Add BPF JIT")
Signed-off-by: Piotr Krysiuk <piotras@gmail.com>
---
 arch/mips/net/bpf_jit.c | 57 +++++++++++++++++++++++++++++++----------
 1 file changed, 43 insertions(+), 14 deletions(-)

diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c
index 0af88622c619..cb6d22439f71 100644
--- a/arch/mips/net/bpf_jit.c
+++ b/arch/mips/net/bpf_jit.c
@@ -662,6 +662,11 @@ static void build_epilogue(struct jit_ctx *ctx)
 	((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative : func) : \
 	 func##_positive)
 
+static bool is_bad_offset(int b_off)
+{
+	return b_off > 0x1ffff || b_off < -0x20000;
+}
+
 static int build_body(struct jit_ctx *ctx)
 {
 	const struct bpf_prog *prog = ctx->skf;
@@ -728,7 +733,10 @@ static int build_body(struct jit_ctx *ctx)
 			/* Load return register on DS for failures */
 			emit_reg_move(r_ret, r_zero, ctx);
 			/* Return with error */
-			emit_b(b_imm(prog->len, ctx), ctx);
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_b(b_off, ctx);
 			emit_nop(ctx);
 			break;
 		case BPF_LD | BPF_W | BPF_IND:
@@ -775,8 +783,10 @@ static int build_body(struct jit_ctx *ctx)
 			emit_jalr(MIPS_R_RA, r_s0, ctx);
 			emit_reg_move(MIPS_R_A0, r_skb, ctx); /* delay slot */
 			/* Check the error value */
-			emit_bcond(MIPS_COND_NE, r_ret, 0,
-				   b_imm(prog->len, ctx), ctx);
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_NE, r_ret, 0, b_off, ctx);
 			emit_reg_move(r_ret, r_zero, ctx);
 			/* We are good */
 			/* X <- P[1:K] & 0xf */
@@ -855,8 +865,10 @@ static int build_body(struct jit_ctx *ctx)
 			/* A /= X */
 			ctx->flags |= SEEN_X | SEEN_A;
 			/* Check if r_X is zero */
-			emit_bcond(MIPS_COND_EQ, r_X, r_zero,
-				   b_imm(prog->len, ctx), ctx);
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_EQ, r_X, r_zero, b_off, ctx);
 			emit_load_imm(r_ret, 0, ctx); /* delay slot */
 			emit_div(r_A, r_X, ctx);
 			break;
@@ -864,8 +876,10 @@ static int build_body(struct jit_ctx *ctx)
 			/* A %= X */
 			ctx->flags |= SEEN_X | SEEN_A;
 			/* Check if r_X is zero */
-			emit_bcond(MIPS_COND_EQ, r_X, r_zero,
-				   b_imm(prog->len, ctx), ctx);
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_EQ, r_X, r_zero, b_off, ctx);
 			emit_load_imm(r_ret, 0, ctx); /* delay slot */
 			emit_mod(r_A, r_X, ctx);
 			break;
@@ -926,7 +940,10 @@ static int build_body(struct jit_ctx *ctx)
 			break;
 		case BPF_JMP | BPF_JA:
 			/* pc += K */
-			emit_b(b_imm(i + k + 1, ctx), ctx);
+			b_off = b_imm(i + k + 1, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_b(b_off, ctx);
 			emit_nop(ctx);
 			break;
 		case BPF_JMP | BPF_JEQ | BPF_K:
@@ -1056,12 +1073,16 @@ static int build_body(struct jit_ctx *ctx)
 			break;
 		case BPF_RET | BPF_A:
 			ctx->flags |= SEEN_A;
-			if (i != prog->len - 1)
+			if (i != prog->len - 1) {
 				/*
 				 * If this is not the last instruction
 				 * then jump to the epilogue
 				 */
-				emit_b(b_imm(prog->len, ctx), ctx);
+				b_off = b_imm(prog->len, ctx);
+				if (is_bad_offset(b_off))
+					return -E2BIG;
+				emit_b(b_off, ctx);
+			}
 			emit_reg_move(r_ret, r_A, ctx); /* delay slot */
 			break;
 		case BPF_RET | BPF_K:
@@ -1075,7 +1096,10 @@ static int build_body(struct jit_ctx *ctx)
 				 * If this is not the last instruction
 				 * then jump to the epilogue
 				 */
-				emit_b(b_imm(prog->len, ctx), ctx);
+				b_off = b_imm(prog->len, ctx);
+				if (is_bad_offset(b_off))
+					return -E2BIG;
+				emit_b(b_off, ctx);
 				emit_nop(ctx);
 			}
 			break;
@@ -1133,8 +1157,10 @@ static int build_body(struct jit_ctx *ctx)
 			/* Load *dev pointer */
 			emit_load_ptr(r_s0, r_skb, off, ctx);
 			/* error (0) in the delay slot */
-			emit_bcond(MIPS_COND_EQ, r_s0, r_zero,
-				   b_imm(prog->len, ctx), ctx);
+			b_off = b_imm(prog->len, ctx);
+			if (is_bad_offset(b_off))
+				return -E2BIG;
+			emit_bcond(MIPS_COND_EQ, r_s0, r_zero, b_off, ctx);
 			emit_reg_move(r_ret, r_zero, ctx);
 			if (code == (BPF_ANC | SKF_AD_IFINDEX)) {
 				BUILD_BUG_ON(sizeof_field(struct net_device, ifindex) != 4);
@@ -1244,7 +1270,10 @@ void bpf_jit_compile(struct bpf_prog *fp)
 
 	/* Generate the actual JIT code */
 	build_prologue(&ctx);
-	build_body(&ctx);
+	if (build_body(&ctx)) {
+		module_memfree(ctx.target);
+		goto out;
+	}
 	build_epilogue(&ctx);
 
 	/* Update the icache */
-- 
2.30.2


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

* Re: [PATCH] bpf, mips: Validate conditional branch offsets
  2021-09-15 16:04 [PATCH] bpf, mips: Validate conditional branch offsets Piotr Krysiuk
@ 2021-09-15 17:38 ` Johan Almbladh
  2021-09-15 19:50 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 3+ messages in thread
From: Johan Almbladh @ 2021-09-15 17:38 UTC (permalink / raw)
  To: Piotr Krysiuk
  Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
	Paul Burton, Thomas Bogendoerfer

On Wed, Sep 15, 2021 at 6:05 PM Piotr Krysiuk <piotras@gmail.com> wrote:
>
> The conditional branch instructions on MIPS use 18-bit signed offsets
> allowing for a branch range of 128 KBytes (backward and forward).
> However, this limit is not observed by the cBPF JIT compiler, and so
> the JIT compiler emits out-of-range branches when translating certain
> cBPF programs. A specific example of such a cBPF program is included in
> the "BPF_MAXINSNS: exec all MSH" test from lib/test_bpf.c that executes
> anomalous machine code containing incorrect branch offsets under JIT.
>
> Furthermore, this issue can be abused to craft undesirable machine
> code, where the control flow is hijacked to execute arbitrary Kernel
> code.
>
> The following steps can be used to reproduce the issue:
>
> # echo 1 > /proc/sys/net/core/bpf_jit_enable
> # modprobe test_bpf test_name="BPF_MAXINSNS: exec all MSH"
>
> This should produce multiple warnings from build_bimm() similar to:
>
> ------------[ cut here ]------------
> WARNING: CPU: 0 PID: 209 at arch/mips/mm/uasm-mips.c:210 build_insn+0x558/0x590
> Micro-assembler field overflow
> Modules linked in: test_bpf(+)
> CPU: 0 PID: 209 Comm: modprobe Not tainted 5.14.3 #1
> Stack : 00000000 807bb824 82b33c9c 801843c0 00000000 00000004 00000000 63c9b5ee
>         82b33af4 80999898 80910000 80900000 82fd6030 00000001 82b33a98 82087180
>         00000000 00000000 80873b28 00000000 000000fc 82b3394c 00000000 2e34312e
>         6d6d6f43 809a180f 809a1836 6f6d203a 80900000 00000001 82b33bac 80900000
>         00027f80 00000000 00000000 807bb824 00000000 804ed790 001cc317 00000001
>         ...
> Call Trace:
> [<80108f44>] show_stack+0x38/0x118
> [<807a7aac>] dump_stack_lvl+0x5c/0x7c
> [<807a4b3c>] __warn+0xcc/0x140
> [<807a4c3c>] warn_slowpath_fmt+0x8c/0xb8
> [<8011e198>] build_insn+0x558/0x590
> [<8011e358>] uasm_i_bne+0x20/0x2c
> [<80127b48>] build_body+0xa58/0x2a94
> [<80129c98>] bpf_jit_compile+0x114/0x1e4
> [<80613fc4>] bpf_prepare_filter+0x2ec/0x4e4
> [<8061423c>] bpf_prog_create+0x80/0xc4
> [<c0a006e4>] test_bpf_init+0x300/0xba8 [test_bpf]
> [<8010051c>] do_one_initcall+0x50/0x1d4
> [<801c5e54>] do_init_module+0x60/0x220
> [<801c8b20>] sys_finit_module+0xc4/0xfc
> [<801144d0>] syscall_common+0x34/0x58
>
> ---[ end trace a287d9742503c645 ]---

Yes, the current cbpf JIT spews out a lot of those micro-assembler
field overflow warnings when I run test_bpf.ko on mips32 and mips32el
in QEMU.

>
> Then the anomalous machine code executes:
>
> => 0xc0a18000:  addiu   sp,sp,-16
>    0xc0a18004:  sw      s3,0(sp)
>    0xc0a18008:  sw      s4,4(sp)
>    0xc0a1800c:  sw      s5,8(sp)
>    0xc0a18010:  sw      ra,12(sp)
>    0xc0a18014:  move    s5,a0
>    0xc0a18018:  move    s4,zero
>    0xc0a1801c:  move    s3,zero
>
>    # __BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0)
>    0xc0a18020:  lui     t6,0x8012
>    0xc0a18024:  ori     t4,t6,0x9e14
>    0xc0a18028:  li      a1,0
>    0xc0a1802c:  jalr    t4
>    0xc0a18030:  move    a0,s5
>    0xc0a18034:  bnez    v0,0xc0a1ffb8           # incorrect branch offset
>    0xc0a18038:  move    v0,zero
>    0xc0a1803c:  andi    s4,s3,0xf
>    0xc0a18040:  b       0xc0a18048
>    0xc0a18044:  sll     s4,s4,0x2
>    ...
>
>    # __BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0)
>    0xc0a1ffa0:  lui     t6,0x8012
>    0xc0a1ffa4:  ori     t4,t6,0x9e14
>    0xc0a1ffa8:  li      a1,0
>    0xc0a1ffac:  jalr    t4
>    0xc0a1ffb0:  move    a0,s5
>    0xc0a1ffb4:  bnez    v0,0xc0a1ffb8           # incorrect branch offset
>    0xc0a1ffb8:  move    v0,zero
>    0xc0a1ffbc:  andi    s4,s3,0xf
>    0xc0a1ffc0:  b       0xc0a1ffc8
>    0xc0a1ffc4:  sll     s4,s4,0x2
>
>    # __BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, 0)
>    0xc0a1ffc8:  lui     t6,0x8012
>    0xc0a1ffcc:  ori     t4,t6,0x9e14
>    0xc0a1ffd0:  li      a1,0
>    0xc0a1ffd4:  jalr    t4
>    0xc0a1ffd8:  move    a0,s5
>    0xc0a1ffdc:  bnez    v0,0xc0a3ffb8           # correct branch offset
>    0xc0a1ffe0:  move    v0,zero
>    0xc0a1ffe4:  andi    s4,s3,0xf
>    0xc0a1ffe8:  b       0xc0a1fff0
>    0xc0a1ffec:  sll     s4,s4,0x2
>    ...
>
>    # epilogue
>    0xc0a3ffb8:  lw      s3,0(sp)
>    0xc0a3ffbc:  lw      s4,4(sp)
>    0xc0a3ffc0:  lw      s5,8(sp)
>    0xc0a3ffc4:  lw      ra,12(sp)
>    0xc0a3ffc8:  addiu   sp,sp,16
>    0xc0a3ffcc:  jr      ra
>    0xc0a3ffd0:  nop
>
> To mitigate this issue, we assert the branch ranges for each emit call
> that could generate an out-of-range branch.
>
> Fixes: 36366e367ee9 ("MIPS: BPF: Restore MIPS32 cBPF JIT")
> Fixes: c6610de353da ("MIPS: net: Add BPF JIT")
> Signed-off-by: Piotr Krysiuk <piotras@gmail.com>
> ---
>  arch/mips/net/bpf_jit.c | 57 +++++++++++++++++++++++++++++++----------
>  1 file changed, 43 insertions(+), 14 deletions(-)
>
> diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c
> index 0af88622c619..cb6d22439f71 100644
> --- a/arch/mips/net/bpf_jit.c
> +++ b/arch/mips/net/bpf_jit.c
> @@ -662,6 +662,11 @@ static void build_epilogue(struct jit_ctx *ctx)
>         ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative : func) : \
>          func##_positive)
>
> +static bool is_bad_offset(int b_off)
> +{
> +       return b_off > 0x1ffff || b_off < -0x20000;
> +}
> +
>  static int build_body(struct jit_ctx *ctx)
>  {
>         const struct bpf_prog *prog = ctx->skf;
> @@ -728,7 +733,10 @@ static int build_body(struct jit_ctx *ctx)
>                         /* Load return register on DS for failures */
>                         emit_reg_move(r_ret, r_zero, ctx);
>                         /* Return with error */
> -                       emit_b(b_imm(prog->len, ctx), ctx);
> +                       b_off = b_imm(prog->len, ctx);
> +                       if (is_bad_offset(b_off))
> +                               return -E2BIG;
> +                       emit_b(b_off, ctx);
>                         emit_nop(ctx);
>                         break;
>                 case BPF_LD | BPF_W | BPF_IND:
> @@ -775,8 +783,10 @@ static int build_body(struct jit_ctx *ctx)
>                         emit_jalr(MIPS_R_RA, r_s0, ctx);
>                         emit_reg_move(MIPS_R_A0, r_skb, ctx); /* delay slot */
>                         /* Check the error value */
> -                       emit_bcond(MIPS_COND_NE, r_ret, 0,
> -                                  b_imm(prog->len, ctx), ctx);
> +                       b_off = b_imm(prog->len, ctx);
> +                       if (is_bad_offset(b_off))
> +                               return -E2BIG;
> +                       emit_bcond(MIPS_COND_NE, r_ret, 0, b_off, ctx);
>                         emit_reg_move(r_ret, r_zero, ctx);
>                         /* We are good */
>                         /* X <- P[1:K] & 0xf */
> @@ -855,8 +865,10 @@ static int build_body(struct jit_ctx *ctx)
>                         /* A /= X */
>                         ctx->flags |= SEEN_X | SEEN_A;
>                         /* Check if r_X is zero */
> -                       emit_bcond(MIPS_COND_EQ, r_X, r_zero,
> -                                  b_imm(prog->len, ctx), ctx);
> +                       b_off = b_imm(prog->len, ctx);
> +                       if (is_bad_offset(b_off))
> +                               return -E2BIG;
> +                       emit_bcond(MIPS_COND_EQ, r_X, r_zero, b_off, ctx);
>                         emit_load_imm(r_ret, 0, ctx); /* delay slot */
>                         emit_div(r_A, r_X, ctx);
>                         break;
> @@ -864,8 +876,10 @@ static int build_body(struct jit_ctx *ctx)
>                         /* A %= X */
>                         ctx->flags |= SEEN_X | SEEN_A;
>                         /* Check if r_X is zero */
> -                       emit_bcond(MIPS_COND_EQ, r_X, r_zero,
> -                                  b_imm(prog->len, ctx), ctx);
> +                       b_off = b_imm(prog->len, ctx);
> +                       if (is_bad_offset(b_off))
> +                               return -E2BIG;
> +                       emit_bcond(MIPS_COND_EQ, r_X, r_zero, b_off, ctx);
>                         emit_load_imm(r_ret, 0, ctx); /* delay slot */
>                         emit_mod(r_A, r_X, ctx);
>                         break;
> @@ -926,7 +940,10 @@ static int build_body(struct jit_ctx *ctx)
>                         break;
>                 case BPF_JMP | BPF_JA:
>                         /* pc += K */
> -                       emit_b(b_imm(i + k + 1, ctx), ctx);
> +                       b_off = b_imm(i + k + 1, ctx);
> +                       if (is_bad_offset(b_off))
> +                               return -E2BIG;
> +                       emit_b(b_off, ctx);
>                         emit_nop(ctx);
>                         break;
>                 case BPF_JMP | BPF_JEQ | BPF_K:
> @@ -1056,12 +1073,16 @@ static int build_body(struct jit_ctx *ctx)
>                         break;
>                 case BPF_RET | BPF_A:
>                         ctx->flags |= SEEN_A;
> -                       if (i != prog->len - 1)
> +                       if (i != prog->len - 1) {
>                                 /*
>                                  * If this is not the last instruction
>                                  * then jump to the epilogue
>                                  */
> -                               emit_b(b_imm(prog->len, ctx), ctx);
> +                               b_off = b_imm(prog->len, ctx);
> +                               if (is_bad_offset(b_off))
> +                                       return -E2BIG;
> +                               emit_b(b_off, ctx);
> +                       }
>                         emit_reg_move(r_ret, r_A, ctx); /* delay slot */
>                         break;
>                 case BPF_RET | BPF_K:
> @@ -1075,7 +1096,10 @@ static int build_body(struct jit_ctx *ctx)
>                                  * If this is not the last instruction
>                                  * then jump to the epilogue
>                                  */
> -                               emit_b(b_imm(prog->len, ctx), ctx);
> +                               b_off = b_imm(prog->len, ctx);
> +                               if (is_bad_offset(b_off))
> +                                       return -E2BIG;
> +                               emit_b(b_off, ctx);
>                                 emit_nop(ctx);
>                         }
>                         break;
> @@ -1133,8 +1157,10 @@ static int build_body(struct jit_ctx *ctx)
>                         /* Load *dev pointer */
>                         emit_load_ptr(r_s0, r_skb, off, ctx);
>                         /* error (0) in the delay slot */
> -                       emit_bcond(MIPS_COND_EQ, r_s0, r_zero,
> -                                  b_imm(prog->len, ctx), ctx);
> +                       b_off = b_imm(prog->len, ctx);
> +                       if (is_bad_offset(b_off))
> +                               return -E2BIG;
> +                       emit_bcond(MIPS_COND_EQ, r_s0, r_zero, b_off, ctx);
>                         emit_reg_move(r_ret, r_zero, ctx);
>                         if (code == (BPF_ANC | SKF_AD_IFINDEX)) {
>                                 BUILD_BUG_ON(sizeof_field(struct net_device, ifindex) != 4);
> @@ -1244,7 +1270,10 @@ void bpf_jit_compile(struct bpf_prog *fp)
>
>         /* Generate the actual JIT code */
>         build_prologue(&ctx);
> -       build_body(&ctx);
> +       if (build_body(&ctx)) {
> +               module_memfree(ctx.target);
> +               goto out;
> +       }
>         build_epilogue(&ctx);
>
>         /* Update the icache */
> --
> 2.30.2
>

The patch looks good to me.

Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>
Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com>

Thanks,
Johan

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

* Re: [PATCH] bpf, mips: Validate conditional branch offsets
  2021-09-15 16:04 [PATCH] bpf, mips: Validate conditional branch offsets Piotr Krysiuk
  2021-09-15 17:38 ` Johan Almbladh
@ 2021-09-15 19:50 ` patchwork-bot+netdevbpf
  1 sibling, 0 replies; 3+ messages in thread
From: patchwork-bot+netdevbpf @ 2021-09-15 19:50 UTC (permalink / raw)
  To: Piotr Krysiuk
  Cc: bpf, ast, daniel, andrii, paulburton, johan.almbladh, tsbogend

Hello:

This patch was applied to bpf/bpf.git (refs/heads/master):

On Wed, 15 Sep 2021 17:04:37 +0100 you wrote:
> The conditional branch instructions on MIPS use 18-bit signed offsets
> allowing for a branch range of 128 KBytes (backward and forward).
> However, this limit is not observed by the cBPF JIT compiler, and so
> the JIT compiler emits out-of-range branches when translating certain
> cBPF programs. A specific example of such a cBPF program is included in
> the "BPF_MAXINSNS: exec all MSH" test from lib/test_bpf.c that executes
> anomalous machine code containing incorrect branch offsets under JIT.
> 
> [...]

Here is the summary with links:
  - bpf, mips: Validate conditional branch offsets
    https://git.kernel.org/bpf/bpf/c/37cb28ec7d3a

You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2021-09-15 19:50 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-15 16:04 [PATCH] bpf, mips: Validate conditional branch offsets Piotr Krysiuk
2021-09-15 17:38 ` Johan Almbladh
2021-09-15 19:50 ` patchwork-bot+netdevbpf

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