| From foo@baz Mon Nov 15 03:31:49 PM CET 2021 |
| From: "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> |
| Date: Mon, 15 Nov 2021 16:36:01 +0530 |
| Subject: powerpc/bpf: Validate branch ranges |
| To: <stable@vger.kernel.org> |
| Cc: Michael Ellerman <mpe@ellerman.id.au>, Daniel Borkmann <daniel@iogearbox.net> |
| Message-ID: <32e658e662d1310c33f7e2aa75b16d00f8e825e9.1636963359.git.naveen.n.rao@linux.vnet.ibm.com> |
| |
| From: "Naveen N. Rao" <naveen.n.rao@linux.vnet.ibm.com> |
| |
| upstream commit 3832ba4e283d7052b783dab8311df7e3590fed93 |
| |
| Add checks to ensure that we never emit branch instructions with |
| truncated branch offsets. |
| |
| Suggested-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> |
| Tested-by: Johan Almbladh <johan.almbladh@anyfinetworks.com> |
| Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu> |
| Acked-by: Song Liu <songliubraving@fb.com> |
| Acked-by: Johan Almbladh <johan.almbladh@anyfinetworks.com> |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Link: https://lore.kernel.org/r/71d33a6b7603ec1013c9734dd8bdd4ff5e929142.1633464148.git.naveen.n.rao@linux.vnet.ibm.com |
| [include header, drop ppc32 changes] |
| Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/powerpc/net/bpf_jit.h | 26 ++++++++++++++++++++------ |
| arch/powerpc/net/bpf_jit_comp64.c | 8 ++++++-- |
| 2 files changed, 26 insertions(+), 8 deletions(-) |
| |
| --- a/arch/powerpc/net/bpf_jit.h |
| +++ b/arch/powerpc/net/bpf_jit.h |
| @@ -11,6 +11,7 @@ |
| #ifndef __ASSEMBLY__ |
| |
| #include <asm/types.h> |
| +#include <asm/code-patching.h> |
| |
| #ifdef PPC64_ELF_ABI_v1 |
| #define FUNCTION_DESCR_SIZE 24 |
| @@ -180,13 +181,26 @@ |
| #define PPC_NEG(d, a) EMIT(PPC_INST_NEG | ___PPC_RT(d) | ___PPC_RA(a)) |
| |
| /* Long jump; (unconditional 'branch') */ |
| -#define PPC_JMP(dest) EMIT(PPC_INST_BRANCH | \ |
| - (((dest) - (ctx->idx * 4)) & 0x03fffffc)) |
| +#define PPC_JMP(dest) \ |
| + do { \ |
| + long offset = (long)(dest) - (ctx->idx * 4); \ |
| + if (!is_offset_in_branch_range(offset)) { \ |
| + pr_err_ratelimited("Branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \ |
| + return -ERANGE; \ |
| + } \ |
| + EMIT(PPC_INST_BRANCH | (offset & 0x03fffffc)); \ |
| + } while (0) |
| /* "cond" here covers BO:BI fields. */ |
| -#define PPC_BCC_SHORT(cond, dest) EMIT(PPC_INST_BRANCH_COND | \ |
| - (((cond) & 0x3ff) << 16) | \ |
| - (((dest) - (ctx->idx * 4)) & \ |
| - 0xfffc)) |
| +#define PPC_BCC_SHORT(cond, dest) \ |
| + do { \ |
| + long offset = (long)(dest) - (ctx->idx * 4); \ |
| + if (!is_offset_in_cond_branch_range(offset)) { \ |
| + pr_err_ratelimited("Conditional branch offset 0x%lx (@%u) out of range\n", offset, ctx->idx); \ |
| + return -ERANGE; \ |
| + } \ |
| + EMIT(PPC_INST_BRANCH_COND | (((cond) & 0x3ff) << 16) | (offset & 0xfffc)); \ |
| + } while (0) |
| + |
| /* Sign-extended 32-bit immediate load */ |
| #define PPC_LI32(d, i) do { \ |
| if ((int)(uintptr_t)(i) >= -32768 && \ |
| --- a/arch/powerpc/net/bpf_jit_comp64.c |
| +++ b/arch/powerpc/net/bpf_jit_comp64.c |
| @@ -224,7 +224,7 @@ static void bpf_jit_emit_func_call_rel(u |
| PPC_BLRL(); |
| } |
| |
| -static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) |
| +static int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) |
| { |
| /* |
| * By now, the eBPF program has already setup parameters in r3, r4 and r5 |
| @@ -285,7 +285,9 @@ static void bpf_jit_emit_tail_call(u32 * |
| bpf_jit_emit_common_epilogue(image, ctx); |
| |
| PPC_BCTR(); |
| + |
| /* out: */ |
| + return 0; |
| } |
| |
| /* Assemble the body code between the prologue & epilogue */ |
| @@ -1001,7 +1003,9 @@ cond_branch: |
| */ |
| case BPF_JMP | BPF_TAIL_CALL: |
| ctx->seen |= SEEN_TAILCALL; |
| - bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]); |
| + ret = bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]); |
| + if (ret < 0) |
| + return ret; |
| break; |
| |
| default: |