Patch "net: filter: make JITs zero A for SKF_AD_ALU_XOR_X" has been added to the 4.3-stable tree
Subsystems (11)
This is a note to let you know that I've just added the patch titled
net: filter: make JITs zero A for SKF_AD_ALU_XOR_X
to the 4.3-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
net-filter-make-jits-zero-a-for-skf_ad_alu_xor_x.patch
and it can be found in the queue-4.3 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From foo@baz Tue Jan 26 21:35:03 PST 2016
From: Rabin Vincent <[email protected]>
Date: Tue, 5 Jan 2016 16:23:07 +0100
Subject: net: filter: make JITs zero A for SKF_AD_ALU_XOR_X
From: Rabin Vincent <[email protected]>
[ Upstream commit 55795ef5469290f89f04e12e662ded604909e462 ]
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.
--- arch/arm/net/bpf_jit_32.c | 16 +--------------- arch/mips/net/bpf_jit.c | 16 +--------------- arch/powerpc/net/bpf_jit_comp.c | 13 ++----------- arch/sparc/net/bpf_jit_comp.c | 17 ++--------------- include/linux/filter.h | 19 +++++++++++++++++++ 5 files changed, 25 insertions(+), 56 deletions(-)
arch/arm/net/bpf_jit_32.c +1 -15
@@ -182,19 +182,6 @@ static inline int mem_words_used(structreturn fls (ctx->seen &SEEN_MEM ); } -static inline bool is_load_to_a (u16 inst) -{ -switch (inst) { -case BPF_LD |BPF_W |BPF_LEN : -case BPF_LD |BPF_W |BPF_ABS : -case BPF_LD |BPF_H |BPF_ABS : -case BPF_LD |BPF_B |BPF_ABS : -return true; -default : -return false; - } -} -static void jit_fill_hole (void *area,unsigned int size) {u32 *ptr;
@@ -206,7 +193,6 @@ static void jit_fill_hole(void *area, unstatic void build_prologue (struct jit_ctx *ctx) {u16 reg_set =saved_regs (ctx); -u16 first_inst = ctx->skf->insns[0 ].code;u16 off;#ifdef CONFIG_FRAME_POINTER
@@ -236,7 +222,7 @@ static void build_prologue(struct jit_ctemit (ARM_MOV_I (r_X,0 ), ctx);/* do not leak kernel data to userspace */ -if ((first_inst != (BPF_RET |BPF_K )) && !(is_load_to_a (first_inst))) +if (bpf_needs_clear_a (&ctx->skf->insns[0 ]))emit (ARM_MOV_I (r_A,0 ), ctx);/* stack space for the BPF_MEM words */
arch/mips/net/bpf_jit.c +1 -15
@@ -521,19 +521,6 @@ static inline u16 align_sp(unsigned intreturn num; } -static bool is_load_to_a (u16 inst) -{ -switch (inst) { -case BPF_LD |BPF_W |BPF_LEN : -case BPF_LD |BPF_W |BPF_ABS : -case BPF_LD |BPF_H |BPF_ABS : -case BPF_LD |BPF_B |BPF_ABS : -return true; -default : -return false; - } -} -static void save_bpf_jit_regs (struct jit_ctx *ctx,unsigned offset) {int i =0 , real_off =0 ;
@@ -614,7 +601,6 @@ static unsigned int get_stack_depth(strustatic void build_prologue (struct jit_ctx *ctx) { -u16 first_inst = ctx->skf->insns[0 ].code;int sp_off;/* Calculate the total offset for the stack pointer */
@@ -641,7 +627,7 @@ static void build_prologue(struct jit_ctemit_jit_reg_move (r_X, r_zero, ctx);/* Do not leak kernel data to userspace */ -if ((first_inst != (BPF_RET |BPF_K )) && !(is_load_to_a (first_inst))) +if (bpf_needs_clear_a (&ctx->skf->insns[0 ]))emit_jit_reg_move (r_A, r_zero, ctx); }
arch/powerpc/net/bpf_jit_comp.c +2 -11
@@ -78,18 +78,9 @@ static void bpf_jit_build_prologue(strucPPC_LI (r_X,0 ); } -switch (filter[0 ].code) { -case BPF_RET |BPF_K : -case BPF_LD |BPF_W |BPF_LEN : -case BPF_LD |BPF_W |BPF_ABS : -case BPF_LD |BPF_H |BPF_ABS : -case BPF_LD |BPF_B |BPF_ABS : -/* first instruction sets A register (or is RET 'constant') */ -break ; -default : -/* make sure we dont leak kernel information to user */ +/* make sure we dont leak kernel information to user */ +if (bpf_needs_clear_a (&filter[0 ]))PPC_LI (r_A,0 ); - } }static void bpf_jit_build_epilogue (u32 *image,struct codegen_context *ctx)
arch/sparc/net/bpf_jit_comp.c +2 -15
@@ -420,22 +420,9 @@ void bpf_jit_compile(struct bpf_prog *fp }emit_reg_move (O7 , r_saved_O7); -switch (filter[0 ].code) { -case BPF_RET |BPF_K : -case BPF_LD |BPF_W |BPF_LEN : -case BPF_LD |BPF_W |BPF_ABS : -case BPF_LD |BPF_H |BPF_ABS : -case BPF_LD |BPF_B |BPF_ABS : -/* The first instruction sets the A register (or is -* a "RET 'constant'") -*/ -break ; -default : -/* Make sure we dont leak kernel information to the -* user. -*/ +/* Make sure we dont leak kernel information to the user. */ +if (bpf_needs_clear_a (&filter[0 ]))emit_clear (r_A);/* A = 0 */ - }for (i =0 ; i < flen; i++) {unsigned int K = filter[i].k;
include/linux/filter.h +19 -0
@@ -459,6 +459,25 @@ static inline void bpf_jit_free(struct b#define BPF_ANC BIT(15) +static inline bool bpf_needs_clear_a (const struct sock_filter *first) +{ +switch (first->code) { +case BPF_RET |BPF_K : +case BPF_LD |BPF_W |BPF_LEN : +return false; + +case BPF_LD |BPF_W |BPF_ABS : +case BPF_LD |BPF_H |BPF_ABS : +case BPF_LD |BPF_B |BPF_ABS : +if (first->k ==SKF_AD_OFF +SKF_AD_ALU_XOR_X ) +return true; +return false; + +default : +return true; + } +} +static inline u16 bpf_anc_helper (const struct sock_filter *ftest) {BUG_ON (ftest->code &BPF_ANC );
Patches currently in stable-queue which might be from [email protected] are
queue-4.3/net-filter-make-jits-zero-a-for-skf_ad_alu_xor_x.patch queue-4.3/net-bpf-reject-invalid-shifts.patch