|
@@ -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;
|
|
|
}
|
|
|
|
|
@@ -866,6 +876,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 */
|
|
@@ -928,7 +946,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));
|