Skip to content

Commit ef89f6b

Browse files
mykyta5Kernel Patches Daemon
authored andcommitted
bpf: verifier: refactor kfunc specialization
Move kfunc specialization (function address substitution) to later stage of verification to support a new use case, where we need to take into consideration whether kfunc is called in sleepable context. Minor refactoring in add_kfunc_call(), making sure that if function fails, kfunc desc is not added to tab->descs (previously it could be added or not, depending on what failed). Signed-off-by: Mykyta Yatsenko <[email protected]>
1 parent f3848a6 commit ef89f6b

File tree

1 file changed

+73
-44
lines changed

1 file changed

+73
-44
lines changed

kernel/bpf/verifier.c

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,6 @@ static void invalidate_non_owning_refs(struct bpf_verifier_env *env);
209209
static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env);
210210
static int ref_set_non_owning(struct bpf_verifier_env *env,
211211
struct bpf_reg_state *reg);
212-
static void specialize_kfunc(struct bpf_verifier_env *env,
213-
u32 func_id, u16 offset, unsigned long *addr);
214212
static bool is_trusted_reg(const struct bpf_reg_state *reg);
215213

216214
static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux)
@@ -3126,6 +3124,11 @@ struct bpf_kfunc_btf_tab {
31263124
u32 nr_descs;
31273125
};
31283126

3127+
static int kfunc_call_imm(struct bpf_verifier_env *env, unsigned long func_addr, u32 func_id,
3128+
s32 *imm);
3129+
3130+
static int specialize_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_desc *desc);
3131+
31293132
static int kfunc_desc_cmp_by_id_off(const void *a, const void *b)
31303133
{
31313134
const struct bpf_kfunc_desc *d0 = a;
@@ -3143,7 +3146,7 @@ static int kfunc_btf_cmp_by_off(const void *a, const void *b)
31433146
return d0->offset - d1->offset;
31443147
}
31453148

3146-
static const struct bpf_kfunc_desc *
3149+
static struct bpf_kfunc_desc *
31473150
find_kfunc_desc(const struct bpf_prog *prog, u32 func_id, u16 offset)
31483151
{
31493152
struct bpf_kfunc_desc desc = {
@@ -3266,12 +3269,13 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
32663269
{
32673270
const struct btf_type *func, *func_proto;
32683271
struct bpf_kfunc_btf_tab *btf_tab;
3272+
struct btf_func_model func_model;
32693273
struct bpf_kfunc_desc_tab *tab;
32703274
struct bpf_prog_aux *prog_aux;
32713275
struct bpf_kfunc_desc *desc;
32723276
const char *func_name;
32733277
struct btf *desc_btf;
3274-
unsigned long call_imm;
3278+
s32 call_imm;
32753279
unsigned long addr;
32763280
int err;
32773281

@@ -3355,38 +3359,32 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
33553359
func_name);
33563360
return -EINVAL;
33573361
}
3358-
specialize_kfunc(env, func_id, offset, &addr);
3359-
3360-
if (bpf_jit_supports_far_kfunc_call()) {
3361-
call_imm = func_id;
3362-
} else {
3363-
call_imm = BPF_CALL_IMM(addr);
3364-
/* Check whether the relative offset overflows desc->imm */
3365-
if ((unsigned long)(s32)call_imm != call_imm) {
3366-
verbose(env, "address of kernel function %s is out of range\n",
3367-
func_name);
3368-
return -EINVAL;
3369-
}
3370-
}
33713362

33723363
if (bpf_dev_bound_kfunc_id(func_id)) {
33733364
err = bpf_dev_bound_kfunc_check(&env->log, prog_aux);
33743365
if (err)
33753366
return err;
33763367
}
33773368

3369+
err = btf_distill_func_proto(&env->log, desc_btf,
3370+
func_proto, func_name,
3371+
&func_model);
3372+
if (err)
3373+
return err;
3374+
3375+
err = kfunc_call_imm(env, addr, func_id, &call_imm);
3376+
if (err)
3377+
return err;
3378+
33783379
desc = &tab->descs[tab->nr_descs++];
33793380
desc->func_id = func_id;
33803381
desc->imm = call_imm;
33813382
desc->offset = offset;
33823383
desc->addr = addr;
3383-
err = btf_distill_func_proto(&env->log, desc_btf,
3384-
func_proto, func_name,
3385-
&desc->func_model);
3386-
if (!err)
3387-
sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
3388-
kfunc_desc_cmp_by_id_off, NULL);
3389-
return err;
3384+
desc->func_model = func_model;
3385+
sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
3386+
kfunc_desc_cmp_by_id_off, NULL);
3387+
return 0;
33903388
}
33913389

33923390
static int kfunc_desc_cmp_by_imm_off(const void *a, const void *b)
@@ -21861,47 +21859,73 @@ static int fixup_call_args(struct bpf_verifier_env *env)
2186121859
return err;
2186221860
}
2186321861

21862+
static int kfunc_call_imm(struct bpf_verifier_env *env, unsigned long func_addr, u32 func_id,
21863+
s32 *imm)
21864+
{
21865+
unsigned long call_imm;
21866+
21867+
if (bpf_jit_supports_far_kfunc_call()) {
21868+
*imm = func_id;
21869+
return 0;
21870+
}
21871+
21872+
call_imm = BPF_CALL_IMM(func_addr);
21873+
/* Check whether the relative offset overflows desc->imm */
21874+
if ((unsigned long)(s32)call_imm != call_imm) {
21875+
verbose(env, "address of kernel func_id %u is out of range\n", func_id);
21876+
return -EINVAL;
21877+
}
21878+
*imm = call_imm;
21879+
return 0;
21880+
}
21881+
2186421882
/* replace a generic kfunc with a specialized version if necessary */
21865-
static void specialize_kfunc(struct bpf_verifier_env *env,
21866-
u32 func_id, u16 offset, unsigned long *addr)
21883+
static int specialize_kfunc(struct bpf_verifier_env *env, struct bpf_kfunc_desc *desc)
2186721884
{
2186821885
struct bpf_prog *prog = env->prog;
2186921886
bool seen_direct_write;
2187021887
void *xdp_kfunc;
2187121888
bool is_rdonly;
21889+
u32 func_id = desc->func_id;
21890+
u16 offset = desc->offset;
21891+
unsigned long addr = 0;
21892+
int err;
21893+
21894+
if (offset) /* return if module BTF is used */
21895+
return 0;
2187221896

2187321897
if (bpf_dev_bound_kfunc_id(func_id)) {
2187421898
xdp_kfunc = bpf_dev_bound_resolve_kfunc(prog, func_id);
21875-
if (xdp_kfunc) {
21876-
*addr = (unsigned long)xdp_kfunc;
21877-
return;
21878-
}
21899+
if (xdp_kfunc)
21900+
addr = (unsigned long)xdp_kfunc;
2187921901
/* fallback to default kfunc when not supported by netdev */
21880-
}
21881-
21882-
if (offset)
21883-
return;
21884-
21885-
if (func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
21902+
} else if (func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
2188621903
seen_direct_write = env->seen_direct_write;
2188721904
is_rdonly = !may_access_direct_pkt_data(env, NULL, BPF_WRITE);
2188821905

2188921906
if (is_rdonly)
21890-
*addr = (unsigned long)bpf_dynptr_from_skb_rdonly;
21907+
addr = (unsigned long)bpf_dynptr_from_skb_rdonly;
2189121908

2189221909
/* restore env->seen_direct_write to its original value, since
2189321910
* may_access_direct_pkt_data mutates it
2189421911
*/
2189521912
env->seen_direct_write = seen_direct_write;
21913+
} else if (func_id == special_kfunc_list[KF_bpf_set_dentry_xattr]) {
21914+
if (bpf_lsm_has_d_inode_locked(prog))
21915+
addr = (unsigned long)bpf_set_dentry_xattr_locked;
21916+
} else if (func_id == special_kfunc_list[KF_bpf_remove_dentry_xattr]) {
21917+
if (bpf_lsm_has_d_inode_locked(prog))
21918+
addr = (unsigned long)bpf_remove_dentry_xattr_locked;
2189621919
}
2189721920

21898-
if (func_id == special_kfunc_list[KF_bpf_set_dentry_xattr] &&
21899-
bpf_lsm_has_d_inode_locked(prog))
21900-
*addr = (unsigned long)bpf_set_dentry_xattr_locked;
21921+
if (!addr) /* Nothing to patch with */
21922+
return 0;
2190121923

21902-
if (func_id == special_kfunc_list[KF_bpf_remove_dentry_xattr] &&
21903-
bpf_lsm_has_d_inode_locked(prog))
21904-
*addr = (unsigned long)bpf_remove_dentry_xattr_locked;
21924+
err = kfunc_call_imm(env, addr, func_id, &desc->imm);
21925+
if (err)
21926+
return err;
21927+
desc->addr = addr;
21928+
return 0;
2190521929
}
2190621930

2190721931
static void __fixup_collection_insert_kfunc(struct bpf_insn_aux_data *insn_aux,
@@ -21924,7 +21948,8 @@ static void __fixup_collection_insert_kfunc(struct bpf_insn_aux_data *insn_aux,
2192421948
static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
2192521949
struct bpf_insn *insn_buf, int insn_idx, int *cnt)
2192621950
{
21927-
const struct bpf_kfunc_desc *desc;
21951+
struct bpf_kfunc_desc *desc;
21952+
int err;
2192821953

2192921954
if (!insn->imm) {
2193021955
verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
@@ -21944,6 +21969,10 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
2194421969
return -EFAULT;
2194521970
}
2194621971

21972+
err = specialize_kfunc(env, desc);
21973+
if (err)
21974+
return err;
21975+
2194721976
if (!bpf_jit_supports_far_kfunc_call())
2194821977
insn->imm = BPF_CALL_IMM(desc->addr);
2194921978
if (insn->off)

0 commit comments

Comments
 (0)