lkml.org 
[lkml]   [2016]   [Jan]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.1 070/127] net: filter: make JITs zero A for SKF_AD_ALU_XOR_X
    Date
    4.1-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Rabin Vincent <rabin@rab.in>

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

    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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    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(-)

    --- a/arch/arm/net/bpf_jit_32.c
    +++ b/arch/arm/net/bpf_jit_32.c
    @@ -162,19 +162,6 @@ static inline int mem_words_used(struct
    return 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;
    @@ -186,7 +173,6 @@ static void jit_fill_hole(void *area, un
    static 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
    @@ -216,7 +202,7 @@ static void build_prologue(struct jit_ct
    emit(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 */
    --- a/arch/mips/net/bpf_jit.c
    +++ b/arch/mips/net/bpf_jit.c
    @@ -556,19 +556,6 @@ static inline u16 align_sp(unsigned int
    return 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;
    @@ -686,7 +673,6 @@ static unsigned int get_stack_depth(stru

    static 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 */
    @@ -700,7 +686,7 @@ static void build_prologue(struct jit_ct
    emit_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);
    }

    --- 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(struc
    PPC_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)
    --- 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
    }
    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;
    --- a/include/linux/filter.h
    +++ b/include/linux/filter.h
    @@ -428,6 +428,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);

    \
     
     \ /
      Last update: 2016-01-27 20:41    [W:4.052 / U:0.064 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site