diff options
Diffstat (limited to 'arch/x86/net/bpf_jit_comp.c')
| -rw-r--r-- | arch/x86/net/bpf_jit_comp.c | 31 | 
1 files changed, 25 insertions, 6 deletions
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 6926d0ca6c71..b35fc8023884 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1936,7 +1936,7 @@ static int invoke_bpf_mod_ret(const struct btf_func_model *m, u8 **pprog,   * add rsp, 8                      // skip eth_type_trans's frame   * ret                             // return to its caller   */ -int arch_prepare_bpf_trampoline(void *image, void *image_end, +int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *image_end,  				const struct btf_func_model *m, u32 flags,  				struct bpf_tramp_progs *tprogs,  				void *orig_call) @@ -1975,6 +1975,15 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,  	save_regs(m, &prog, nr_args, stack_size); +	if (flags & BPF_TRAMP_F_CALL_ORIG) { +		/* arg1: mov rdi, im */ +		emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im); +		if (emit_call(&prog, __bpf_tramp_enter, prog)) { +			ret = -EINVAL; +			goto cleanup; +		} +	} +  	if (fentry->nr_progs)  		if (invoke_bpf(m, &prog, fentry, stack_size))  			return -EINVAL; @@ -1993,8 +2002,7 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,  	}  	if (flags & BPF_TRAMP_F_CALL_ORIG) { -		if (fentry->nr_progs || fmod_ret->nr_progs) -			restore_regs(m, &prog, nr_args, stack_size); +		restore_regs(m, &prog, nr_args, stack_size);  		/* call original function */  		if (emit_call(&prog, orig_call, prog)) { @@ -2003,6 +2011,9 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,  		}  		/* remember return value in a stack for bpf prog to access */  		emit_stx(&prog, BPF_DW, BPF_REG_FP, BPF_REG_0, -8); +		im->ip_after_call = prog; +		memcpy(prog, ideal_nops[NOP_ATOMIC5], X86_PATCH_SIZE); +		prog += X86_PATCH_SIZE;  	}  	if (fmod_ret->nr_progs) { @@ -2033,9 +2044,17 @@ int arch_prepare_bpf_trampoline(void *image, void *image_end,  	 * the return value is only updated on the stack and still needs to be  	 * restored to R0.  	 */ -	if (flags & BPF_TRAMP_F_CALL_ORIG) +	if (flags & BPF_TRAMP_F_CALL_ORIG) { +		im->ip_epilogue = prog; +		/* arg1: mov rdi, im */ +		emit_mov_imm64(&prog, BPF_REG_1, (long) im >> 32, (u32) (long) im); +		if (emit_call(&prog, __bpf_tramp_exit, prog)) { +			ret = -EINVAL; +			goto cleanup; +		}  		/* restore original return value back into RAX */  		emit_ldx(&prog, BPF_DW, BPF_REG_0, BPF_REG_FP, -8); +	}  	EMIT1(0x5B); /* pop rbx */  	EMIT1(0xC9); /* leave */ @@ -2225,7 +2244,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)  		padding = true;  		goto skip_init_addrs;  	} -	addrs = kmalloc_array(prog->len + 1, sizeof(*addrs), GFP_KERNEL); +	addrs = kvmalloc_array(prog->len + 1, sizeof(*addrs), GFP_KERNEL);  	if (!addrs) {  		prog = orig_prog;  		goto out_addrs; @@ -2317,7 +2336,7 @@ out_image:  		if (image)  			bpf_prog_fill_jited_linfo(prog, addrs + 1);  out_addrs: -		kfree(addrs); +		kvfree(addrs);  		kfree(jit_data);  		prog->aux->jit_data = NULL;  	}  |