Commit 13443154 authored by Paul Burton's avatar Paul Burton Committed by Daniel Borkmann
Browse files

MIPS: eBPF: Always return sign extended 32b values



The function prototype used to call JITed eBPF code (ie. the type of the
struct bpf_prog bpf_func field) returns an unsigned int. The MIPS n64
ABI that MIPS64 kernels target defines that 32 bit integers should
always be sign extended when passed in registers as either arguments or
return values.

This means that when returning any value which may not already be sign
extended (ie. of type REG_64BIT or REG_32BIT_ZERO_EX) we need to perform
that sign extension in order to comply with the n64 ABI. Without this we
see strange looking test failures from test_bpf.ko, such as:

  test_bpf: #65 ALU64_MOV_X:
    dst = 4294967295 jited:1 ret -1 != -1 FAIL (1 times)

Although the return value printed matches the expected value, this is
only because printf is only examining the least significant 32 bits of
the 64 bit register value we returned. The register holding the expected
value is sign extended whilst the v0 register was set to a zero extended
value by our JITed code, so when compared by a conditional branch
instruction the values are not equal.

We already handle this when the return value register is of type
REG_32BIT_ZERO_EX, so simply extend this to also cover REG_64BIT.
Signed-off-by: default avatarPaul Burton <paul.burton@mips.com>
Fixes: b6bd53f9

 ("MIPS: Add missing file for eBPF JIT.")
Cc: stable@vger.kernel.org # v4.13+
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 1e405c1a
...@@ -343,12 +343,15 @@ static int build_int_epilogue(struct jit_ctx *ctx, int dest_reg) ...@@ -343,12 +343,15 @@ static int build_int_epilogue(struct jit_ctx *ctx, int dest_reg)
const struct bpf_prog *prog = ctx->skf; const struct bpf_prog *prog = ctx->skf;
int stack_adjust = ctx->stack_size; int stack_adjust = ctx->stack_size;
int store_offset = stack_adjust - 8; int store_offset = stack_adjust - 8;
enum reg_val_type td;
int r0 = MIPS_R_V0; int r0 = MIPS_R_V0;
if (dest_reg == MIPS_R_RA && if (dest_reg == MIPS_R_RA) {
get_reg_val_type(ctx, prog->len, BPF_REG_0) == REG_32BIT_ZERO_EX)
/* Don't let zero extended value escape. */ /* Don't let zero extended value escape. */
emit_instr(ctx, sll, r0, r0, 0); td = get_reg_val_type(ctx, prog->len, BPF_REG_0);
if (td == REG_64BIT || td == REG_32BIT_ZERO_EX)
emit_instr(ctx, sll, r0, r0, 0);
}
if (ctx->flags & EBPF_SAVE_RA) { if (ctx->flags & EBPF_SAVE_RA) {
emit_instr(ctx, ld, MIPS_R_RA, store_offset, MIPS_R_SP); emit_instr(ctx, ld, MIPS_R_RA, store_offset, MIPS_R_SP);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment