aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/net
diff options
context:
space:
mode:
authorAlexei Starovoitov <ast@plumgrid.com>2014-11-29 17:46:13 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-06 00:23:54 -0500
commit769e0de6475e5512f88bfb4dbf6d6323fd23514f (patch)
treed6a8648b1dcc509a47e47f995159f70bcb0572c6 /arch/x86/net
parent6fb2a756739aa507c1fd5b8126f0bfc2f070dc46 (diff)
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>
Diffstat (limited to 'arch/x86/net')
-rw-r--r--arch/x86/net/bpf_jit_comp.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 3f627345d51c..7e90244c84e3 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -178,7 +178,7 @@ static void jit_fill_hole(void *area, unsigned int size)
178} 178}
179 179
180struct jit_context { 180struct jit_context {
181 unsigned int cleanup_addr; /* epilogue code offset */ 181 int cleanup_addr; /* epilogue code offset */
182 bool seen_ld_abs; 182 bool seen_ld_abs;
183}; 183};
184 184
@@ -192,6 +192,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
192 struct bpf_insn *insn = bpf_prog->insnsi; 192 struct bpf_insn *insn = bpf_prog->insnsi;
193 int insn_cnt = bpf_prog->len; 193 int insn_cnt = bpf_prog->len;
194 bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0); 194 bool seen_ld_abs = ctx->seen_ld_abs | (oldproglen == 0);
195 bool seen_exit = false;
195 u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY]; 196 u8 temp[BPF_MAX_INSN_SIZE + BPF_INSN_SAFETY];
196 int i; 197 int i;
197 int proglen = 0; 198 int proglen = 0;
@@ -854,10 +855,11 @@ common_load:
854 goto common_load; 855 goto common_load;
855 856
856 case BPF_JMP | BPF_EXIT: 857 case BPF_JMP | BPF_EXIT:
857 if (i != insn_cnt - 1) { 858 if (seen_exit) {
858 jmp_offset = ctx->cleanup_addr - addrs[i]; 859 jmp_offset = ctx->cleanup_addr - addrs[i];
859 goto emit_jmp; 860 goto emit_jmp;
860 } 861 }
862 seen_exit = true;
861 /* update cleanup_addr */ 863 /* update cleanup_addr */
862 ctx->cleanup_addr = proglen; 864 ctx->cleanup_addr = proglen;
863 /* mov rbx, qword ptr [rbp-X] */ 865 /* mov rbx, qword ptr [rbp-X] */