diff options
-rw-r--r-- | arch/arm/net/bpf_jit_32.c | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index f412b53ed268..e0e23582c8b4 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c | |||
@@ -54,6 +54,7 @@ | |||
54 | #define SEEN_DATA (1 << (BPF_MEMWORDS + 3)) | 54 | #define SEEN_DATA (1 << (BPF_MEMWORDS + 3)) |
55 | 55 | ||
56 | #define FLAG_NEED_X_RESET (1 << 0) | 56 | #define FLAG_NEED_X_RESET (1 << 0) |
57 | #define FLAG_IMM_OVERFLOW (1 << 1) | ||
57 | 58 | ||
58 | struct jit_ctx { | 59 | struct jit_ctx { |
59 | const struct bpf_prog *skf; | 60 | const struct bpf_prog *skf; |
@@ -293,6 +294,15 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx) | |||
293 | /* PC in ARM mode == address of the instruction + 8 */ | 294 | /* PC in ARM mode == address of the instruction + 8 */ |
294 | imm = offset - (8 + ctx->idx * 4); | 295 | imm = offset - (8 + ctx->idx * 4); |
295 | 296 | ||
297 | if (imm & ~0xfff) { | ||
298 | /* | ||
299 | * literal pool is too far, signal it into flags. we | ||
300 | * can only detect it on the second pass unfortunately. | ||
301 | */ | ||
302 | ctx->flags |= FLAG_IMM_OVERFLOW; | ||
303 | return 0; | ||
304 | } | ||
305 | |||
296 | return imm; | 306 | return imm; |
297 | } | 307 | } |
298 | 308 | ||
@@ -866,6 +876,14 @@ b_epilogue: | |||
866 | default: | 876 | default: |
867 | return -1; | 877 | return -1; |
868 | } | 878 | } |
879 | |||
880 | if (ctx->flags & FLAG_IMM_OVERFLOW) | ||
881 | /* | ||
882 | * this instruction generated an overflow when | ||
883 | * trying to access the literal pool, so | ||
884 | * delegate this filter to the kernel interpreter. | ||
885 | */ | ||
886 | return -1; | ||
869 | } | 887 | } |
870 | 888 | ||
871 | /* compute offsets only during the first pass */ | 889 | /* compute offsets only during the first pass */ |
@@ -928,7 +946,14 @@ void bpf_jit_compile(struct bpf_prog *fp) | |||
928 | ctx.idx = 0; | 946 | ctx.idx = 0; |
929 | 947 | ||
930 | build_prologue(&ctx); | 948 | build_prologue(&ctx); |
931 | build_body(&ctx); | 949 | if (build_body(&ctx) < 0) { |
950 | #if __LINUX_ARM_ARCH__ < 7 | ||
951 | if (ctx.imm_count) | ||
952 | kfree(ctx.imms); | ||
953 | #endif | ||
954 | bpf_jit_binary_free(header); | ||
955 | goto out; | ||
956 | } | ||
932 | build_epilogue(&ctx); | 957 | build_epilogue(&ctx); |
933 | 958 | ||
934 | flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx)); | 959 | flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx)); |