Commit a5d82727 authored by Kumar Kartikeya Dwivedi's avatar Kumar Kartikeya Dwivedi Committed by Alexei Starovoitov

bpf: Be conservative while processing invalid kfunc calls

This patch also modifies the BPF verifier to only return error for
invalid kfunc calls specially marked by userspace (with insn->imm == 0,
insn->off == 0) after the verifier has eliminated dead instructions.
This can be handled in the fixup stage, and skip processing during add
and check stages.

If such an invalid call is dropped, the fixup stage will not encounter
insn->imm as 0, otherwise it bails out and returns an error.

This will be exposed as weak ksym support in libbpf in later patches.
Signed-off-by: default avatarKumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20211002011757.311265-3-memxor@gmail.com
parent 2357672c
...@@ -1834,6 +1834,15 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset) ...@@ -1834,6 +1834,15 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
prog_aux->kfunc_tab = tab; prog_aux->kfunc_tab = tab;
} }
/* func_id == 0 is always invalid, but instead of returning an error, be
* conservative and wait until the code elimination pass before returning
* error, so that invalid calls that get pruned out can be in BPF programs
* loaded from userspace. It is also required that offset be untouched
* for such calls.
*/
if (!func_id && !offset)
return 0;
if (!btf_tab && offset) { if (!btf_tab && offset) {
btf_tab = kzalloc(sizeof(*btf_tab), GFP_KERNEL); btf_tab = kzalloc(sizeof(*btf_tab), GFP_KERNEL);
if (!btf_tab) if (!btf_tab)
...@@ -6675,6 +6684,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn) ...@@ -6675,6 +6684,10 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn)
struct btf *desc_btf; struct btf *desc_btf;
int err; int err;
/* skip for now, but return error when we find this in fixup_kfunc_call */
if (!insn->imm)
return 0;
desc_btf = find_kfunc_desc_btf(env, insn->imm, insn->off, &btf_mod); desc_btf = find_kfunc_desc_btf(env, insn->imm, insn->off, &btf_mod);
if (IS_ERR(desc_btf)) if (IS_ERR(desc_btf))
return PTR_ERR(desc_btf); return PTR_ERR(desc_btf);
...@@ -12810,6 +12823,11 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, ...@@ -12810,6 +12823,11 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env,
{ {
const struct bpf_kfunc_desc *desc; const struct bpf_kfunc_desc *desc;
if (!insn->imm) {
verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
return -EINVAL;
}
/* insn->imm has the btf func_id. Replace it with /* insn->imm has the btf func_id. Replace it with
* an address (relative to __bpf_base_call). * an address (relative to __bpf_base_call).
*/ */
......
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