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: 622582786c9e ("net: filter: x86: internal BPF JIT") Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
6fb2a75673
commit
769e0de647
@ -178,7 +178,7 @@ static void jit_fill_hole(void *area, unsigned int size)
|
||||
}
|
||||
|
||||
struct jit_context {
|
||||
unsigned int cleanup_addr; /* epilogue code offset */
|
||||
int cleanup_addr; /* epilogue code offset */
|
||||
bool seen_ld_abs;
|
||||
};
|
||||
|
||||
@ -192,6 +192,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
|
||||
struct bpf_insn *insn = bpf_prog->insnsi;
|
||||
int insn_cnt = bpf_prog->len;
|
||||
bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0);
|
||||
bool seen_exit = false;
|
||||
u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
|
||||
int i;
|
||||
int proglen = 0;
|
||||
@ -854,10 +855,11 @@ common_load:
|
||||
goto common_load;
|
||||
|
||||
case BPF_JMP | BPF_EXIT:
|
||||
if (i != insn_cnt - 1) {
|
||||
if (seen_exit) {
|
||||
jmp_offset = ctx->cleanup_addr - addrs[i];
|
||||
goto emit_jmp;
|
||||
}
|
||||
seen_exit = true;
|
||||
/* update cleanup_addr */
|
||||
ctx->cleanup_addr = proglen;
|
||||
/* mov rbx, qword ptr [rbp-X] */
|
||||
|
Reference in New Issue
Block a user