Message ID | 1551982504-12597-1-git-send-email-tyhicks@canonical.com |
---|---|
State | New |
Headers | show |
Series | None | expand |
This v2 patch came in after v1 has already been applied. I took the liberty to replace v1 with v2 and force push bionic/master-next. ...Juerg > From: Daniel Borkmann <daniel@iogearbox.net> > > This change moves the on-stack 64 bit tmp variable in ___bpf_prog_run() > into the hidden ax register. The latter is currently only used in JITs > for constant blinding as a temporary scratch register, meaning the BPF > interpreter will never see the use of ax. Therefore it is safe to use > it for the cases where tmp has been used earlier. This is needed to later > on allow restricted hidden use of ax in both interpreter and JITs. > > Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> > Acked-by: Alexei Starovoitov <ast@kernel.org> > Signed-off-by: Alexei Starovoitov <ast@kernel.org> > > CVE-2019-7308 > > (backported from commit 144cd91c4c2bced6eb8a7e25e590f6618a11e854) > [tyhicks: Backport around context changes and missing commits > 1ea47e01ad6e and e0cea7ce988c] > Signed-off-by: Tyler Hicks <tyhicks@canonical.com> > Acked-by: You-Sheng Yang <vicamo.yang@canonical.com> > Acked-by: Stefan Bader <stefan.bader@canonical.com> > Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com> > --- > > * Changes since v1: > - There were three additional uses of the tmp variable in ___bpf_prog_run() > that needed to be converted to AX in order to fix a build failure seen with > our i386 kernel config. > > include/linux/filter.h | 3 ++- > kernel/bpf/core.c | 38 +++++++++++++++++++------------------- > 2 files changed, 21 insertions(+), 20 deletions(-) > > diff --git a/include/linux/filter.h b/include/linux/filter.h > index e85292a16467..ec944f15f1a4 100644 > --- a/include/linux/filter.h > +++ b/include/linux/filter.h > @@ -53,7 +53,8 @@ struct bpf_prog_aux; > * constants. See JIT pre-step in bpf_jit_blind_constants(). > */ > #define BPF_REG_AX MAX_BPF_REG > -#define MAX_BPF_JIT_REG (MAX_BPF_REG + 1) > +#define MAX_BPF_EXT_REG (MAX_BPF_REG + 1) > +#define MAX_BPF_JIT_REG MAX_BPF_EXT_REG > > /* unused opcode to mark special call to bpf_tail_call() helper */ > #define BPF_TAIL_CALL 0xf0 > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c > index 7949e8b8f94e..439574daf1f0 100644 > --- a/kernel/bpf/core.c > +++ b/kernel/bpf/core.c > @@ -51,6 +51,7 @@ > #define DST regs[insn->dst_reg] > #define SRC regs[insn->src_reg] > #define FP regs[BPF_REG_FP] > +#define AX regs[BPF_REG_AX] > #define ARG1 regs[BPF_REG_ARG1] > #define CTX regs[BPF_REG_CTX] > #define IMM insn->imm > @@ -778,7 +779,6 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); > static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, > u64 *stack) > { > - u64 tmp; > static const void *jumptable[256] = { > [0 ... 255] = &&default_label, > /* Now overwrite non-defaults ... */ > @@ -952,22 +952,22 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, > ALU64_MOD_X: > if (unlikely(SRC == 0)) > return 0; > - div64_u64_rem(DST, SRC, &tmp); > - DST = tmp; > + div64_u64_rem(DST, SRC, &AX); > + DST = AX; > CONT; > ALU_MOD_X: > if (unlikely((u32)SRC == 0)) > return 0; > - tmp = (u32) DST; > - DST = do_div(tmp, (u32) SRC); > + AX = (u32) DST; > + DST = do_div(AX, (u32) SRC); > CONT; > ALU64_MOD_K: > - div64_u64_rem(DST, IMM, &tmp); > - DST = tmp; > + div64_u64_rem(DST, IMM, &AX); > + DST = AX; > CONT; > ALU_MOD_K: > - tmp = (u32) DST; > - DST = do_div(tmp, (u32) IMM); > + AX = (u32) DST; > + DST = do_div(AX, (u32) IMM); > CONT; > ALU64_DIV_X: > if (unlikely(SRC == 0)) > @@ -977,17 +977,17 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, > ALU_DIV_X: > if (unlikely((u32)SRC == 0)) > return 0; > - tmp = (u32) DST; > - do_div(tmp, (u32) SRC); > - DST = (u32) tmp; > + AX = (u32) DST; > + do_div(AX, (u32) SRC); > + DST = (u32) AX; > CONT; > ALU64_DIV_K: > DST = div64_u64(DST, IMM); > CONT; > ALU_DIV_K: > - tmp = (u32) DST; > - do_div(tmp, (u32) IMM); > - DST = (u32) tmp; > + AX = (u32) DST; > + do_div(AX, (u32) IMM); > + DST = (u32) AX; > CONT; > ALU_END_TO_BE: > switch (IMM) { > @@ -1242,7 +1242,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, > * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness > */ > > - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); > + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &AX); > if (likely(ptr != NULL)) { > BPF_R0 = get_unaligned_be32(ptr); > CONT; > @@ -1252,7 +1252,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, > LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ > off = IMM; > load_half: > - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); > + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &AX); > if (likely(ptr != NULL)) { > BPF_R0 = get_unaligned_be16(ptr); > CONT; > @@ -1262,7 +1262,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, > LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ > off = IMM; > load_byte: > - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); > + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &AX); > if (likely(ptr != NULL)) { > BPF_R0 = *(u8 *)ptr; > CONT; > @@ -1291,7 +1291,7 @@ STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */ > static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \ > { \ > u64 stack[stack_size / sizeof(u64)]; \ > - u64 regs[MAX_BPF_REG]; \ > + u64 regs[MAX_BPF_EXT_REG]; \ > \ > FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \ > ARG1 = (u64) (unsigned long) ctx; \
diff --git a/include/linux/filter.h b/include/linux/filter.h index e85292a16467..ec944f15f1a4 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -53,7 +53,8 @@ struct bpf_prog_aux; * constants. See JIT pre-step in bpf_jit_blind_constants(). */ #define BPF_REG_AX MAX_BPF_REG -#define MAX_BPF_JIT_REG (MAX_BPF_REG + 1) +#define MAX_BPF_EXT_REG (MAX_BPF_REG + 1) +#define MAX_BPF_JIT_REG MAX_BPF_EXT_REG /* unused opcode to mark special call to bpf_tail_call() helper */ #define BPF_TAIL_CALL 0xf0 diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 7949e8b8f94e..439574daf1f0 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -51,6 +51,7 @@ #define DST regs[insn->dst_reg] #define SRC regs[insn->src_reg] #define FP regs[BPF_REG_FP] +#define AX regs[BPF_REG_AX] #define ARG1 regs[BPF_REG_ARG1] #define CTX regs[BPF_REG_CTX] #define IMM insn->imm @@ -778,7 +779,6 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) { - u64 tmp; static const void *jumptable[256] = { [0 ... 255] = &&default_label, /* Now overwrite non-defaults ... */ @@ -952,22 +952,22 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, ALU64_MOD_X: if (unlikely(SRC == 0)) return 0; - div64_u64_rem(DST, SRC, &tmp); - DST = tmp; + div64_u64_rem(DST, SRC, &AX); + DST = AX; CONT; ALU_MOD_X: if (unlikely((u32)SRC == 0)) return 0; - tmp = (u32) DST; - DST = do_div(tmp, (u32) SRC); + AX = (u32) DST; + DST = do_div(AX, (u32) SRC); CONT; ALU64_MOD_K: - div64_u64_rem(DST, IMM, &tmp); - DST = tmp; + div64_u64_rem(DST, IMM, &AX); + DST = AX; CONT; ALU_MOD_K: - tmp = (u32) DST; - DST = do_div(tmp, (u32) IMM); + AX = (u32) DST; + DST = do_div(AX, (u32) IMM); CONT; ALU64_DIV_X: if (unlikely(SRC == 0)) @@ -977,17 +977,17 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, ALU_DIV_X: if (unlikely((u32)SRC == 0)) return 0; - tmp = (u32) DST; - do_div(tmp, (u32) SRC); - DST = (u32) tmp; + AX = (u32) DST; + do_div(AX, (u32) SRC); + DST = (u32) AX; CONT; ALU64_DIV_K: DST = div64_u64(DST, IMM); CONT; ALU_DIV_K: - tmp = (u32) DST; - do_div(tmp, (u32) IMM); - DST = (u32) tmp; + AX = (u32) DST; + do_div(AX, (u32) IMM); + DST = (u32) AX; CONT; ALU_END_TO_BE: switch (IMM) { @@ -1242,7 +1242,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness */ - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &AX); if (likely(ptr != NULL)) { BPF_R0 = get_unaligned_be32(ptr); CONT; @@ -1252,7 +1252,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ off = IMM; load_half: - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &AX); if (likely(ptr != NULL)) { BPF_R0 = get_unaligned_be16(ptr); CONT; @@ -1262,7 +1262,7 @@ static unsigned int ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ off = IMM; load_byte: - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); + ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &AX); if (likely(ptr != NULL)) { BPF_R0 = *(u8 *)ptr; CONT; @@ -1291,7 +1291,7 @@ STACK_FRAME_NON_STANDARD(___bpf_prog_run); /* jump table */ static unsigned int PROG_NAME(stack_size)(const void *ctx, const struct bpf_insn *insn) \ { \ u64 stack[stack_size / sizeof(u64)]; \ - u64 regs[MAX_BPF_REG]; \ + u64 regs[MAX_BPF_EXT_REG]; \ \ FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; \ ARG1 = (u64) (unsigned long) ctx; \