Skip to content

Commit e6ac245

Browse files
iamkafaiAlexei Starovoitov
authored andcommitted
bpf: Support bpf program calling kernel function
This patch adds support to BPF verifier to allow bpf program calling kernel function directly. The use case included in this set is to allow bpf-tcp-cc to directly call some tcp-cc helper functions (e.g. "tcp_cong_avoid_ai()"). Those functions have already been used by some kernel tcp-cc implementations. This set will also allow the bpf-tcp-cc program to directly call the kernel tcp-cc implementation, For example, a bpf_dctcp may only want to implement its own dctcp_cwnd_event() and reuse other dctcp_*() directly from the kernel tcp_dctcp.c instead of reimplementing (or copy-and-pasting) them. The tcp-cc kernel functions mentioned above will be white listed for the struct_ops bpf-tcp-cc programs to use in a later patch. The white listed functions are not bounded to a fixed ABI contract. Those functions have already been used by the existing kernel tcp-cc. If any of them has changed, both in-tree and out-of-tree kernel tcp-cc implementations have to be changed. The same goes for the struct_ops bpf-tcp-cc programs which have to be adjusted accordingly. This patch is to make the required changes in the bpf verifier. First change is in btf.c, it adds a case in "btf_check_func_arg_match()". When the passed in "btf->kernel_btf == true", it means matching the verifier regs' states with a kernel function. This will handle the PTR_TO_BTF_ID reg. It also maps PTR_TO_SOCK_COMMON, PTR_TO_SOCKET, and PTR_TO_TCP_SOCK to its kernel's btf_id. In the later libbpf patch, the insn calling a kernel function will look like: insn->code == (BPF_JMP | BPF_CALL) insn->src_reg == BPF_PSEUDO_KFUNC_CALL /* <- new in this patch */ insn->imm == func_btf_id /* btf_id of the running kernel */ [ For the future calling function-in-kernel-module support, an array of module btf_fds can be passed at the load time and insn->off can be used to index into this array. ] At the early stage of verifier, the verifier will collect all kernel function calls into "struct bpf_kfunc_desc". Those descriptors are stored in "prog->aux->kfunc_tab" and will be available to the JIT. Since this "add" operation is similar to the current "add_subprog()" and looking for the same insn->code, they are done together in the new "add_subprog_and_kfunc()". In the "do_check()" stage, the new "check_kfunc_call()" is added to verify the kernel function call instruction: 1. Ensure the kernel function can be used by a particular BPF_PROG_TYPE. A new bpf_verifier_ops "check_kfunc_call" is added to do that. The bpf-tcp-cc struct_ops program will implement this function in a later patch. 2. Call "btf_check_kfunc_args_match()" to ensure the regs can be used as the args of a kernel function. 3. Mark the regs' type, subreg_def, and zext_dst. At the later do_misc_fixups() stage, the new fixup_kfunc_call() will replace the insn->imm with the function address (relative to __bpf_call_base). If needed, the jit can find the btf_func_model by calling the new bpf_jit_find_kfunc_model(prog, insn). With the imm set to the function address, "bpftool prog dump xlated" will be able to display the kernel function calls the same way as it displays other bpf helper calls. gpl_compatible program is required to call kernel function. This feature currently requires JIT. The verifier selftests are adjusted because of the changes in the verbose log in add_subprog_and_kfunc(). Signed-off-by: Martin KaFai Lau <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 34747c4 commit e6ac245

File tree

13 files changed

+480
-46
lines changed

13 files changed

+480
-46
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,3 +2346,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
23462346
tmp : orig_prog);
23472347
return prog;
23482348
}
2349+
2350+
bool bpf_jit_supports_kfunc_call(void)
2351+
{
2352+
return true;
2353+
}

include/linux/bpf.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ enum bpf_reg_type {
427427
PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */
428428
PTR_TO_FUNC, /* reg points to a bpf program function */
429429
PTR_TO_MAP_KEY, /* reg points to a map element key */
430+
__BPF_REG_TYPE_MAX,
430431
};
431432

432433
/* The information passed from prog-specific *_is_valid_access
@@ -480,6 +481,7 @@ struct bpf_verifier_ops {
480481
const struct btf_type *t, int off, int size,
481482
enum bpf_access_type atype,
482483
u32 *next_btf_id);
484+
bool (*check_kfunc_call)(u32 kfunc_btf_id);
483485
};
484486

485487
struct bpf_prog_offload_ops {
@@ -796,6 +798,8 @@ struct btf_mod_pair {
796798
struct module *module;
797799
};
798800

801+
struct bpf_kfunc_desc_tab;
802+
799803
struct bpf_prog_aux {
800804
atomic64_t refcnt;
801805
u32 used_map_cnt;
@@ -832,6 +836,7 @@ struct bpf_prog_aux {
832836
struct bpf_prog **func;
833837
void *jit_data; /* JIT specific data. arch dependent */
834838
struct bpf_jit_poke_descriptor *poke_tab;
839+
struct bpf_kfunc_desc_tab *kfunc_tab;
835840
u32 size_poke_tab;
836841
struct bpf_ksym ksym;
837842
const struct bpf_prog_ops *ops;
@@ -1547,6 +1552,9 @@ int btf_distill_func_proto(struct bpf_verifier_log *log,
15471552
struct bpf_reg_state;
15481553
int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
15491554
struct bpf_reg_state *regs);
1555+
int btf_check_kfunc_arg_match(struct bpf_verifier_env *env,
1556+
const struct btf *btf, u32 func_id,
1557+
struct bpf_reg_state *regs);
15501558
int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog,
15511559
struct bpf_reg_state *reg);
15521560
int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *prog,
@@ -1557,6 +1565,10 @@ struct bpf_link *bpf_link_by_id(u32 id);
15571565

15581566
const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id);
15591567
void bpf_task_storage_free(struct task_struct *task);
1568+
bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog);
1569+
const struct btf_func_model *
1570+
bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
1571+
const struct bpf_insn *insn);
15601572
#else /* !CONFIG_BPF_SYSCALL */
15611573
static inline struct bpf_prog *bpf_prog_get(u32 ufd)
15621574
{
@@ -1737,6 +1749,18 @@ bpf_base_func_proto(enum bpf_func_id func_id)
17371749
static inline void bpf_task_storage_free(struct task_struct *task)
17381750
{
17391751
}
1752+
1753+
static inline bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
1754+
{
1755+
return false;
1756+
}
1757+
1758+
static inline const struct btf_func_model *
1759+
bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
1760+
const struct bpf_insn *insn)
1761+
{
1762+
return NULL;
1763+
}
17401764
#endif /* CONFIG_BPF_SYSCALL */
17411765

17421766
void __bpf_free_used_btfs(struct bpf_prog_aux *aux,

include/linux/btf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ const struct btf_type *btf_type_resolve_func_ptr(const struct btf *btf,
110110
const struct btf_type *
111111
btf_resolve_size(const struct btf *btf, const struct btf_type *type,
112112
u32 *type_size);
113+
const char *btf_type_str(const struct btf_type *t);
113114

114115
#define for_each_member(i, struct_type, member) \
115116
for (i = 0, member = btf_type_member(struct_type); \

include/linux/filter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
918918
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
919919
void bpf_jit_compile(struct bpf_prog *prog);
920920
bool bpf_jit_needs_zext(void);
921+
bool bpf_jit_supports_kfunc_call(void);
921922
bool bpf_helper_changes_pkt_data(void *func);
922923

923924
static inline bool bpf_dump_raw_ok(const struct cred *cred)

include/uapi/linux/bpf.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,10 @@ enum bpf_link_type {
11171117
* offset to another bpf function
11181118
*/
11191119
#define BPF_PSEUDO_CALL 1
1120+
/* when bpf_call->src_reg == BPF_PSEUDO_KFUNC_CALL,
1121+
* bpf_call->imm == btf_id of a BTF_KIND_FUNC in the running kernel
1122+
*/
1123+
#define BPF_PSEUDO_KFUNC_CALL 2
11201124

11211125
/* flags for BPF_MAP_UPDATE_ELEM command */
11221126
enum {

kernel/bpf/btf.c

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ static const char * const btf_kind_str[NR_BTF_KINDS] = {
283283
[BTF_KIND_FLOAT] = "FLOAT",
284284
};
285285

286-
static const char *btf_type_str(const struct btf_type *t)
286+
const char *btf_type_str(const struct btf_type *t)
287287
{
288288
return btf_kind_str[BTF_INFO_KIND(t->info)];
289289
}
@@ -5362,6 +5362,14 @@ int btf_check_type_match(struct bpf_verifier_log *log, const struct bpf_prog *pr
53625362
return btf_check_func_type_match(log, btf1, t1, btf2, t2);
53635363
}
53645364

5365+
static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = {
5366+
#ifdef CONFIG_NET
5367+
[PTR_TO_SOCKET] = &btf_sock_ids[BTF_SOCK_TYPE_SOCK],
5368+
[PTR_TO_SOCK_COMMON] = &btf_sock_ids[BTF_SOCK_TYPE_SOCK_COMMON],
5369+
[PTR_TO_TCP_SOCK] = &btf_sock_ids[BTF_SOCK_TYPE_TCP],
5370+
#endif
5371+
};
5372+
53655373
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
53665374
const struct btf *btf, u32 func_id,
53675375
struct bpf_reg_state *regs,
@@ -5371,12 +5379,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
53715379
const char *func_name, *ref_tname;
53725380
const struct btf_type *t, *ref_t;
53735381
const struct btf_param *args;
5374-
u32 i, nargs;
5382+
u32 i, nargs, ref_id;
53755383

53765384
t = btf_type_by_id(btf, func_id);
53775385
if (!t || !btf_type_is_func(t)) {
53785386
/* These checks were already done by the verifier while loading
5379-
* struct bpf_func_info
5387+
* struct bpf_func_info or in add_kfunc_call().
53805388
*/
53815389
bpf_log(log, "BTF of func_id %u doesn't point to KIND_FUNC\n",
53825390
func_id);
@@ -5418,9 +5426,49 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
54185426
return -EINVAL;
54195427
}
54205428

5421-
ref_t = btf_type_skip_modifiers(btf, t->type, NULL);
5429+
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
54225430
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
5423-
if (btf_get_prog_ctx_type(log, btf, t, env->prog->type, i)) {
5431+
if (btf_is_kernel(btf)) {
5432+
const struct btf_type *reg_ref_t;
5433+
const struct btf *reg_btf;
5434+
const char *reg_ref_tname;
5435+
u32 reg_ref_id;
5436+
5437+
if (!btf_type_is_struct(ref_t)) {
5438+
bpf_log(log, "kernel function %s args#%d pointer type %s %s is not supported\n",
5439+
func_name, i, btf_type_str(ref_t),
5440+
ref_tname);
5441+
return -EINVAL;
5442+
}
5443+
5444+
if (reg->type == PTR_TO_BTF_ID) {
5445+
reg_btf = reg->btf;
5446+
reg_ref_id = reg->btf_id;
5447+
} else if (reg2btf_ids[reg->type]) {
5448+
reg_btf = btf_vmlinux;
5449+
reg_ref_id = *reg2btf_ids[reg->type];
5450+
} else {
5451+
bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d is not a pointer to btf_id\n",
5452+
func_name, i,
5453+
btf_type_str(ref_t), ref_tname, regno);
5454+
return -EINVAL;
5455+
}
5456+
5457+
reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id,
5458+
&reg_ref_id);
5459+
reg_ref_tname = btf_name_by_offset(reg_btf,
5460+
reg_ref_t->name_off);
5461+
if (!btf_struct_ids_match(log, reg_btf, reg_ref_id,
5462+
reg->off, btf, ref_id)) {
5463+
bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d has a pointer to %s %s\n",
5464+
func_name, i,
5465+
btf_type_str(ref_t), ref_tname,
5466+
regno, btf_type_str(reg_ref_t),
5467+
reg_ref_tname);
5468+
return -EINVAL;
5469+
}
5470+
} else if (btf_get_prog_ctx_type(log, btf, t,
5471+
env->prog->type, i)) {
54245472
/* If function expects ctx type in BTF check that caller
54255473
* is passing PTR_TO_CTX.
54265474
*/
@@ -5493,6 +5541,13 @@ int btf_check_subprog_arg_match(struct bpf_verifier_env *env, int subprog,
54935541
return err;
54945542
}
54955543

5544+
int btf_check_kfunc_arg_match(struct bpf_verifier_env *env,
5545+
const struct btf *btf, u32 func_id,
5546+
struct bpf_reg_state *regs)
5547+
{
5548+
return btf_check_func_arg_match(env, btf, func_id, regs, false);
5549+
}
5550+
54965551
/* Convert BTF of a function into bpf_reg_state if possible
54975552
* Returns:
54985553
* EFAULT - there is a verifier bug. Abort verification.

kernel/bpf/core.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ void bpf_prog_jit_attempt_done(struct bpf_prog *prog)
159159
kvfree(prog->aux->jited_linfo);
160160
prog->aux->jited_linfo = NULL;
161161
}
162+
163+
kfree(prog->aux->kfunc_tab);
164+
prog->aux->kfunc_tab = NULL;
162165
}
163166

164167
/* The jit engine is responsible to provide an array
@@ -1840,9 +1843,15 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
18401843
/* In case of BPF to BPF calls, verifier did all the prep
18411844
* work with regards to JITing, etc.
18421845
*/
1846+
bool jit_needed = false;
1847+
18431848
if (fp->bpf_func)
18441849
goto finalize;
18451850

1851+
if (IS_ENABLED(CONFIG_BPF_JIT_ALWAYS_ON) ||
1852+
bpf_prog_has_kfunc_call(fp))
1853+
jit_needed = true;
1854+
18461855
bpf_prog_select_func(fp);
18471856

18481857
/* eBPF JITs can rewrite the program in case constant
@@ -1858,12 +1867,10 @@ struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err)
18581867

18591868
fp = bpf_int_jit_compile(fp);
18601869
bpf_prog_jit_attempt_done(fp);
1861-
#ifdef CONFIG_BPF_JIT_ALWAYS_ON
1862-
if (!fp->jited) {
1870+
if (!fp->jited && jit_needed) {
18631871
*err = -ENOTSUPP;
18641872
return fp;
18651873
}
1866-
#endif
18671874
} else {
18681875
*err = bpf_prog_offload_compile(fp);
18691876
if (*err)
@@ -2343,6 +2350,11 @@ bool __weak bpf_jit_needs_zext(void)
23432350
return false;
23442351
}
23452352

2353+
bool __weak bpf_jit_supports_kfunc_call(void)
2354+
{
2355+
return false;
2356+
}
2357+
23462358
/* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call
23472359
* skb_copy_bits(), so provide a weak definition of it for NET-less config.
23482360
*/

kernel/bpf/disasm.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,23 @@ static const char *__func_get_name(const struct bpf_insn_cbs *cbs,
1919
{
2020
BUILD_BUG_ON(ARRAY_SIZE(func_id_str) != __BPF_FUNC_MAX_ID);
2121

22-
if (insn->src_reg != BPF_PSEUDO_CALL &&
22+
if (!insn->src_reg &&
2323
insn->imm >= 0 && insn->imm < __BPF_FUNC_MAX_ID &&
2424
func_id_str[insn->imm])
2525
return func_id_str[insn->imm];
2626

27-
if (cbs && cbs->cb_call)
28-
return cbs->cb_call(cbs->private_data, insn);
27+
if (cbs && cbs->cb_call) {
28+
const char *res;
29+
30+
res = cbs->cb_call(cbs->private_data, insn);
31+
if (res)
32+
return res;
33+
}
2934

3035
if (insn->src_reg == BPF_PSEUDO_CALL)
3136
snprintf(buff, len, "%+d", insn->imm);
37+
else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL)
38+
snprintf(buff, len, "kernel-function");
3239

3340
return buff;
3441
}

kernel/bpf/syscall.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,7 @@ static void __bpf_prog_put_noref(struct bpf_prog *prog, bool deferred)
16961696
btf_put(prog->aux->btf);
16971697
kvfree(prog->aux->jited_linfo);
16981698
kvfree(prog->aux->linfo);
1699+
kfree(prog->aux->kfunc_tab);
16991700
if (prog->aux->attach_btf)
17001701
btf_put(prog->aux->attach_btf);
17011702

0 commit comments

Comments
 (0)