netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits.
@ 2015-05-07 15:14 Nicolas Schichan
  2015-05-07 16:18 ` Daniel Borkmann
  2015-05-10 23:22 ` David Miller
  0 siblings, 2 replies; 3+ messages in thread
From: Nicolas Schichan @ 2015-05-07 15:14 UTC (permalink / raw)
  To: Russell King, David S. Miller, Alexei Starovoitov,
	Daniel Borkmann, Nicolas Schichan, Mircea Gherzan,
	linux-arm-kernel, linux-kernel, netdev

The ARM JIT code emits "ldr rX, [pc, #offset]" to access the literal
pool. #offset maximum value is 4095 and if the generated code is too
large, the #offset value can overflow and not point to the expected
slot in the literal pool. Additionally, when overflow occurs, bits of
the overflow can end up changing the destination register of the ldr
instruction.

Fix that by detecting the overflow in imm_offset() and setting a flag
that is checked for each BPF instructions converted in
build_body(). As of now it can only be detected in the second pass. As
a result the second build_body() call can now fail, so add the
corresponding cleanup code in that case.

Using multiple literal pools in the JITed code is going to require
lots of intrusive changes to the JIT code (which would better be done
as a feature instead of fix), just delegating to the kernel BPF
interpreter in that case is a more straight forward, minimal fix and
easy to backport.

Signed-off-by: Nicolas Schichan <nschichan@freebox.fr>
---
 arch/arm/net/bpf_jit_32.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 6bda637..bb8ffcd 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -54,6 +54,7 @@
 #define SEEN_DATA		(1 << (BPF_MEMWORDS + 3))
 
 #define FLAG_NEED_X_RESET	(1 << 0)
+#define FLAG_IMM_OVERFLOW	(1 << 1)
 
 struct jit_ctx {
 	const struct bpf_prog *skf;
@@ -293,6 +294,15 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx)
 	/* PC in ARM mode == address of the instruction + 8 */
 	imm = offset - (8 + ctx->idx * 4);
 
+	if (imm & ~0xfff) {
+		/*
+		 * literal pool is too far, signal it into flags. we
+		 * can only detect it on the second pass unfortunately.
+		 */
+		ctx->flags |= FLAG_IMM_OVERFLOW;
+		return 0;
+	}
+
 	return imm;
 }
 
@@ -876,6 +886,14 @@ b_epilogue:
 		default:
 			return -1;
 		}
+
+		if (ctx->flags & FLAG_IMM_OVERFLOW)
+			/*
+			 * this instruction generated an overflow when
+			 * trying to access the literal pool, so
+			 * delegate this filter to the kernel interpreter.
+			 */
+			return -1;
 	}
 
 	/* compute offsets only during the first pass */
@@ -938,7 +956,14 @@ void bpf_jit_compile(struct bpf_prog *fp)
 	ctx.idx = 0;
 
 	build_prologue(&ctx);
-	build_body(&ctx);
+	if (build_body(&ctx) < 0) {
+#if __LINUX_ARM_ARCH__ < 7
+		if (ctx.imm_count)
+			kfree(ctx.imms);
+#endif
+		bpf_jit_binary_free(header);
+		goto out;
+	}
 	build_epilogue(&ctx);
 
 	flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
-- 
1.9.1

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

* Re: [PATCH] ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits.
  2015-05-07 15:14 [PATCH] ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits Nicolas Schichan
@ 2015-05-07 16:18 ` Daniel Borkmann
  2015-05-10 23:22 ` David Miller
  1 sibling, 0 replies; 3+ messages in thread
From: Daniel Borkmann @ 2015-05-07 16:18 UTC (permalink / raw)
  To: Nicolas Schichan, Russell King, David S. Miller,
	Alexei Starovoitov, Mircea Gherzan, linux-arm-kernel,
	linux-kernel, netdev

On 05/07/2015 05:14 PM, Nicolas Schichan wrote:
> The ARM JIT code emits "ldr rX, [pc, #offset]" to access the literal
> pool. #offset maximum value is 4095 and if the generated code is too
> large, the #offset value can overflow and not point to the expected
> slot in the literal pool. Additionally, when overflow occurs, bits of
> the overflow can end up changing the destination register of the ldr
> instruction.
>
> Fix that by detecting the overflow in imm_offset() and setting a flag
> that is checked for each BPF instructions converted in
> build_body(). As of now it can only be detected in the second pass. As
> a result the second build_body() call can now fail, so add the
> corresponding cleanup code in that case.
>
> Using multiple literal pools in the JITed code is going to require
> lots of intrusive changes to the JIT code (which would better be done
> as a feature instead of fix), just delegating to the kernel BPF
> interpreter in that case is a more straight forward, minimal fix and
> easy to backport.
>
> Signed-off-by: Nicolas Schichan <nschichan@freebox.fr>

Fix looks good to me.

Fixes: ddecdfcea0ae ("ARM: 7259/3: net: JIT compiler for packet filters")
Acked-by: Daniel Borkmann <daniel@iogearbox.net>

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

* Re: [PATCH] ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits.
  2015-05-07 15:14 [PATCH] ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits Nicolas Schichan
  2015-05-07 16:18 ` Daniel Borkmann
@ 2015-05-10 23:22 ` David Miller
  1 sibling, 0 replies; 3+ messages in thread
From: David Miller @ 2015-05-10 23:22 UTC (permalink / raw)
  To: nschichan
  Cc: linux, ast, daniel, mgherzan, linux-arm-kernel, linux-kernel, netdev

From: Nicolas Schichan <nschichan@freebox.fr>
Date: Thu,  7 May 2015 17:14:21 +0200

> The ARM JIT code emits "ldr rX, [pc, #offset]" to access the literal
> pool. #offset maximum value is 4095 and if the generated code is too
> large, the #offset value can overflow and not point to the expected
> slot in the literal pool. Additionally, when overflow occurs, bits of
> the overflow can end up changing the destination register of the ldr
> instruction.
> 
> Fix that by detecting the overflow in imm_offset() and setting a flag
> that is checked for each BPF instructions converted in
> build_body(). As of now it can only be detected in the second pass. As
> a result the second build_body() call can now fail, so add the
> corresponding cleanup code in that case.
> 
> Using multiple literal pools in the JITed code is going to require
> lots of intrusive changes to the JIT code (which would better be done
> as a feature instead of fix), just delegating to the kernel BPF
> interpreter in that case is a more straight forward, minimal fix and
> easy to backport.
> 
> Signed-off-by: Nicolas Schichan <nschichan@freebox.fr>

Applied, thanks Nicolas.

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

end of thread, other threads:[~2015-05-10 23:22 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-07 15:14 [PATCH] ARM: net: delegate filter to kernel interpreter when imm_offset() return value can't fit into 12bits Nicolas Schichan
2015-05-07 16:18 ` Daniel Borkmann
2015-05-10 23:22 ` David Miller

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