diff options
author | Rabin Vincent <rabin@rab.in> | 2016-01-05 10:23:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-01-06 00:43:52 -0500 |
commit | 55795ef5469290f89f04e12e662ded604909e462 (patch) | |
tree | df413e913330af821e7989534a4d36ea621bab56 | |
parent | ff62198553e43cdffa9d539f6165d3e83f8a42bc (diff) |
net: filter: make JITs zero A for SKF_AD_ALU_XOR_X
The SKF_AD_ALU_XOR_X ancillary is not like the other ancillary data
instructions since it XORs A with X while all the others replace A with
some loaded value. All the BPF JITs fail to clear A if this is used as
the first instruction in a filter. This was found using american fuzzy
lop.
Add a helper to determine if A needs to be cleared given the first
instruction in a filter, and use this in the JITs. Except for ARM, the
rest have only been compile-tested.
Fixes: 3480593131e0 ("net: filter: get rid of BPF_S_* enum")
Signed-off-by: Rabin Vincent <rabin@rab.in>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | arch/arm/net/bpf_jit_32.c | 16 | ||||
-rw-r--r-- | arch/mips/net/bpf_jit.c | 16 | ||||
-rw-r--r-- | arch/powerpc/net/bpf_jit_comp.c | 13 | ||||
-rw-r--r-- | arch/sparc/net/bpf_jit_comp.c | 17 | ||||
-rw-r--r-- | include/linux/filter.h | 19 |
5 files changed, 25 insertions, 56 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 591f9db3bf40..e153eb065fe4 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c | |||
@@ -187,19 +187,6 @@ static inline int mem_words_used(struct jit_ctx *ctx) | |||
187 | return fls(ctx->seen & SEEN_MEM); | 187 | return fls(ctx->seen & SEEN_MEM); |
188 | } | 188 | } |
189 | 189 | ||
190 | static inline bool is_load_to_a(u16 inst) | ||
191 | { | ||
192 | switch (inst) { | ||
193 | case BPF_LD | BPF_W | BPF_LEN: | ||
194 | case BPF_LD | BPF_W | BPF_ABS: | ||
195 | case BPF_LD | BPF_H | BPF_ABS: | ||
196 | case BPF_LD | BPF_B | BPF_ABS: | ||
197 | return true; | ||
198 | default: | ||
199 | return false; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void jit_fill_hole(void *area, unsigned int size) | 190 | static void jit_fill_hole(void *area, unsigned int size) |
204 | { | 191 | { |
205 | u32 *ptr; | 192 | u32 *ptr; |
@@ -211,7 +198,6 @@ static void jit_fill_hole(void *area, unsigned int size) | |||
211 | static void build_prologue(struct jit_ctx *ctx) | 198 | static void build_prologue(struct jit_ctx *ctx) |
212 | { | 199 | { |
213 | u16 reg_set = saved_regs(ctx); | 200 | u16 reg_set = saved_regs(ctx); |
214 | u16 first_inst = ctx->skf->insns[0].code; | ||
215 | u16 off; | 201 | u16 off; |
216 | 202 | ||
217 | #ifdef CONFIG_FRAME_POINTER | 203 | #ifdef CONFIG_FRAME_POINTER |
@@ -241,7 +227,7 @@ static void build_prologue(struct jit_ctx *ctx) | |||
241 | emit(ARM_MOV_I(r_X, 0), ctx); | 227 | emit(ARM_MOV_I(r_X, 0), ctx); |
242 | 228 | ||
243 | /* do not leak kernel data to userspace */ | 229 | /* do not leak kernel data to userspace */ |
244 | if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst))) | 230 | if (bpf_needs_clear_a(&ctx->skf->insns[0])) |
245 | emit(ARM_MOV_I(r_A, 0), ctx); | 231 | emit(ARM_MOV_I(r_A, 0), ctx); |
246 | 232 | ||
247 | /* stack space for the BPF_MEM words */ | 233 | /* stack space for the BPF_MEM words */ |
diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c index 77cb27309db2..1a8c96035716 100644 --- a/arch/mips/net/bpf_jit.c +++ b/arch/mips/net/bpf_jit.c | |||
@@ -521,19 +521,6 @@ static inline u16 align_sp(unsigned int num) | |||
521 | return num; | 521 | return num; |
522 | } | 522 | } |
523 | 523 | ||
524 | static bool is_load_to_a(u16 inst) | ||
525 | { | ||
526 | switch (inst) { | ||
527 | case BPF_LD | BPF_W | BPF_LEN: | ||
528 | case BPF_LD | BPF_W | BPF_ABS: | ||
529 | case BPF_LD | BPF_H | BPF_ABS: | ||
530 | case BPF_LD | BPF_B | BPF_ABS: | ||
531 | return true; | ||
532 | default: | ||
533 | return false; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset) | 524 | static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset) |
538 | { | 525 | { |
539 | int i = 0, real_off = 0; | 526 | int i = 0, real_off = 0; |
@@ -614,7 +601,6 @@ static unsigned int get_stack_depth(struct jit_ctx *ctx) | |||
614 | 601 | ||
615 | static void build_prologue(struct jit_ctx *ctx) | 602 | static void build_prologue(struct jit_ctx *ctx) |
616 | { | 603 | { |
617 | u16 first_inst = ctx->skf->insns[0].code; | ||
618 | int sp_off; | 604 | int sp_off; |
619 | 605 | ||
620 | /* Calculate the total offset for the stack pointer */ | 606 | /* Calculate the total offset for the stack pointer */ |
@@ -641,7 +627,7 @@ static void build_prologue(struct jit_ctx *ctx) | |||
641 | emit_jit_reg_move(r_X, r_zero, ctx); | 627 | emit_jit_reg_move(r_X, r_zero, ctx); |
642 | 628 | ||
643 | /* Do not leak kernel data to userspace */ | 629 | /* Do not leak kernel data to userspace */ |
644 | if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst))) | 630 | if (bpf_needs_clear_a(&ctx->skf->insns[0])) |
645 | emit_jit_reg_move(r_A, r_zero, ctx); | 631 | emit_jit_reg_move(r_A, r_zero, ctx); |
646 | } | 632 | } |
647 | 633 | ||
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index 04782164ee67..2d66a8446198 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c | |||
@@ -78,18 +78,9 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image, | |||
78 | PPC_LI(r_X, 0); | 78 | PPC_LI(r_X, 0); |
79 | } | 79 | } |
80 | 80 | ||
81 | switch (filter[0].code) { | 81 | /* make sure we dont leak kernel information to user */ |
82 | case BPF_RET | BPF_K: | 82 | if (bpf_needs_clear_a(&filter[0])) |
83 | case BPF_LD | BPF_W | BPF_LEN: | ||
84 | case BPF_LD | BPF_W | BPF_ABS: | ||
85 | case BPF_LD | BPF_H | BPF_ABS: | ||
86 | case BPF_LD | BPF_B | BPF_ABS: | ||
87 | /* first instruction sets A register (or is RET 'constant') */ | ||
88 | break; | ||
89 | default: | ||
90 | /* make sure we dont leak kernel information to user */ | ||
91 | PPC_LI(r_A, 0); | 83 | PPC_LI(r_A, 0); |
92 | } | ||
93 | } | 84 | } |
94 | 85 | ||
95 | static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) | 86 | static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) |
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c index 22564f5f2364..3e6e05a7c4c2 100644 --- a/arch/sparc/net/bpf_jit_comp.c +++ b/arch/sparc/net/bpf_jit_comp.c | |||
@@ -420,22 +420,9 @@ void bpf_jit_compile(struct bpf_prog *fp) | |||
420 | } | 420 | } |
421 | emit_reg_move(O7, r_saved_O7); | 421 | emit_reg_move(O7, r_saved_O7); |
422 | 422 | ||
423 | switch (filter[0].code) { | 423 | /* Make sure we dont leak kernel information to the user. */ |
424 | case BPF_RET | BPF_K: | 424 | if (bpf_needs_clear_a(&filter[0])) |
425 | case BPF_LD | BPF_W | BPF_LEN: | ||
426 | case BPF_LD | BPF_W | BPF_ABS: | ||
427 | case BPF_LD | BPF_H | BPF_ABS: | ||
428 | case BPF_LD | BPF_B | BPF_ABS: | ||
429 | /* The first instruction sets the A register (or is | ||
430 | * a "RET 'constant'") | ||
431 | */ | ||
432 | break; | ||
433 | default: | ||
434 | /* Make sure we dont leak kernel information to the | ||
435 | * user. | ||
436 | */ | ||
437 | emit_clear(r_A); /* A = 0 */ | 425 | emit_clear(r_A); /* A = 0 */ |
438 | } | ||
439 | 426 | ||
440 | for (i = 0; i < flen; i++) { | 427 | for (i = 0; i < flen; i++) { |
441 | unsigned int K = filter[i].k; | 428 | unsigned int K = filter[i].k; |
diff --git a/include/linux/filter.h b/include/linux/filter.h index 4165e9ac9e36..5972ffe5719a 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h | |||
@@ -493,6 +493,25 @@ static inline void bpf_jit_free(struct bpf_prog *fp) | |||
493 | 493 | ||
494 | #define BPF_ANC BIT(15) | 494 | #define BPF_ANC BIT(15) |
495 | 495 | ||
496 | static inline bool bpf_needs_clear_a(const struct sock_filter *first) | ||
497 | { | ||
498 | switch (first->code) { | ||
499 | case BPF_RET | BPF_K: | ||
500 | case BPF_LD | BPF_W | BPF_LEN: | ||
501 | return false; | ||
502 | |||
503 | case BPF_LD | BPF_W | BPF_ABS: | ||
504 | case BPF_LD | BPF_H | BPF_ABS: | ||
505 | case BPF_LD | BPF_B | BPF_ABS: | ||
506 | if (first->k == SKF_AD_OFF + SKF_AD_ALU_XOR_X) | ||
507 | return true; | ||
508 | return false; | ||
509 | |||
510 | default: | ||
511 | return true; | ||
512 | } | ||
513 | } | ||
514 | |||
496 | static inline u16 bpf_anc_helper(const struct sock_filter *ftest) | 515 | static inline u16 bpf_anc_helper(const struct sock_filter *ftest) |
497 | { | 516 | { |
498 | BUG_ON(ftest->code & BPF_ANC); | 517 | BUG_ON(ftest->code & BPF_ANC); |