Commit 769e0de6 authored by Alexei Starovoitov's avatar Alexei Starovoitov Committed by David S. Miller

bpf: x86: fix epilogue generation for eBPF programs

classic BPF has a restriction that last insn is always BPF_RET.
eBPF doesn't have BPF_RET instruction and this restriction.
It has BPF_EXIT insn which can appear anywhere in the program
one or more times and it doesn't have to be last insn.
Fix eBPF JIT to emit epilogue when first BPF_EXIT is seen
and all other BPF_EXIT instructions will be emitted as jump.

Since jump offset to epilogue is computed as:
jmp_offset = ctx->cleanup_addr - addrs[i]
we need to change type of cleanup_addr to signed to compute the offset as:
(long long) ((int)20 - (int)30)
instead of:
(long long) ((unsigned int)20 - (int)30)

Fixes: 62258278 ("net: filter: x86: internal BPF JIT")
Signed-off-by: default avatarAlexei Starovoitov <ast@plumgrid.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6fb2a756
...@@ -178,7 +178,7 @@ static void jit_fill_hole(void *area, unsigned int size) ...@@ -178,7 +178,7 @@ static void jit_fill_hole(void *area, unsigned int size)
} }
struct jit_context { struct jit_context {
unsigned int cleanup_addr; /* epilogue code offset */ int cleanup_addr; /* epilogue code offset */
bool seen_ld_abs; bool seen_ld_abs;
}; };
...@@ -192,6 +192,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, ...@@ -192,6 +192,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
struct bpf_insn *insn = bpf_prog->insnsi; struct bpf_insn *insn = bpf_prog->insnsi;
int insn_cnt = bpf_prog->len; int insn_cnt = bpf_prog->len;
bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0); bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0);
bool seen_exit = false;
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY]; u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
int i; int i;
int proglen = 0; int proglen = 0;
...@@ -854,10 +855,11 @@ xadd: if (is_imm8(insn->off)) ...@@ -854,10 +855,11 @@ xadd: if (is_imm8(insn->off))
goto common_load; goto common_load;
case BPF_JMP | BPF_EXIT: case BPF_JMP | BPF_EXIT:
if (i != insn_cnt - 1) { if (seen_exit) {
jmp_offset = ctx->cleanup_addr - addrs[i]; jmp_offset = ctx->cleanup_addr - addrs[i];
goto emit_jmp; goto emit_jmp;
} }
seen_exit = true;
/* update cleanup_addr */ /* update cleanup_addr */
ctx->cleanup_addr = proglen; ctx->cleanup_addr = proglen;
/* mov rbx, qword ptr [rbp-X] */ /* mov rbx, qword ptr [rbp-X] */
......
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