Skip to content

Commit 1cf3bfc

Browse files
iii-iAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: Support 64-bit pointers to kfuncs
test_ksyms_module fails to emit a kfunc call targeting a module on s390x, because the verifier stores the difference between kfunc address and __bpf_call_base in bpf_insn.imm, which is s32, and modules are roughly (1 << 42) bytes away from the kernel on s390x. Fix by keeping BTF id in bpf_insn.imm for BPF_PSEUDO_KFUNC_CALLs, and storing the absolute address in bpf_kfunc_desc. Introduce bpf_jit_supports_far_kfunc_call() in order to limit this new behavior to the s390x JIT. Otherwise other JITs need to be modified, which is not desired. Introduce bpf_get_kfunc_addr() instead of exposing both find_kfunc_desc() and struct bpf_kfunc_desc. In addition to sorting kfuncs by imm, also sort them by offset, in order to handle conflicting imms from different modules. Do this on all architectures in order to simplify code. Factor out resolving specialized kfuncs (XPD and dynptr) from fixup_kfunc_call(). This was required in the first place, because fixup_kfunc_call() uses find_kfunc_desc(), which returns a const pointer, so it's not possible to modify kfunc addr without stripping const, which is not nice. It also removes repetition of code like: if (bpf_jit_supports_far_kfunc_call()) desc->addr = func; else insn->imm = BPF_CALL_IMM(func); and separates kfunc_desc_tab fixups from kfunc_call fixups. Suggested-by: Jiri Olsa <olsajiri@gmail.com> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/r/20230412230632.885985-1-iii@linux.ibm.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent c11bd04 commit 1cf3bfc

File tree

5 files changed

+110
-40
lines changed

5 files changed

+110
-40
lines changed

arch/s390/net/bpf_jit_comp.c

+5
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,11 @@ bool bpf_jit_supports_kfunc_call(void)
20012001
return true;
20022002
}
20032003

2004+
bool bpf_jit_supports_far_kfunc_call(void)
2005+
{
2006+
return true;
2007+
}
2008+
20042009
int bpf_arch_text_poke(void *ip, enum bpf_text_poke_type t,
20052010
void *old_addr, void *new_addr)
20062011
{

include/linux/bpf.h

+10
Original file line numberDiff line numberDiff line change
@@ -2295,6 +2295,9 @@ bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog);
22952295
const struct btf_func_model *
22962296
bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
22972297
const struct bpf_insn *insn);
2298+
int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
2299+
u16 btf_fd_idx, u8 **func_addr);
2300+
22982301
struct bpf_core_ctx {
22992302
struct bpf_verifier_log *log;
23002303
const struct btf *btf;
@@ -2545,6 +2548,13 @@ bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
25452548
return NULL;
25462549
}
25472550

2551+
static inline int
2552+
bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
2553+
u16 btf_fd_idx, u8 **func_addr)
2554+
{
2555+
return -ENOTSUPP;
2556+
}
2557+
25482558
static inline bool unprivileged_ebpf_enabled(void)
25492559
{
25502560
return false;

include/linux/filter.h

+1
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,7 @@ void bpf_jit_compile(struct bpf_prog *prog);
920920
bool bpf_jit_needs_zext(void);
921921
bool bpf_jit_supports_subprog_tailcalls(void);
922922
bool bpf_jit_supports_kfunc_call(void);
923+
bool bpf_jit_supports_far_kfunc_call(void);
923924
bool bpf_helper_changes_pkt_data(void *func);
924925

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

kernel/bpf/core.c

+11
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,7 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
11871187
s16 off = insn->off;
11881188
s32 imm = insn->imm;
11891189
u8 *addr;
1190+
int err;
11901191

11911192
*func_addr_fixed = insn->src_reg != BPF_PSEUDO_CALL;
11921193
if (!*func_addr_fixed) {
@@ -1201,6 +1202,11 @@ int bpf_jit_get_func_addr(const struct bpf_prog *prog,
12011202
addr = (u8 *)prog->aux->func[off]->bpf_func;
12021203
else
12031204
return -EINVAL;
1205+
} else if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL &&
1206+
bpf_jit_supports_far_kfunc_call()) {
1207+
err = bpf_get_kfunc_addr(prog, insn->imm, insn->off, &addr);
1208+
if (err)
1209+
return err;
12041210
} else {
12051211
/* Address of a BPF helper call. Since part of the core
12061212
* kernel, it's always at a fixed location. __bpf_call_base
@@ -2732,6 +2738,11 @@ bool __weak bpf_jit_supports_kfunc_call(void)
27322738
return false;
27332739
}
27342740

2741+
bool __weak bpf_jit_supports_far_kfunc_call(void)
2742+
{
2743+
return false;
2744+
}
2745+
27352746
/* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call
27362747
* skb_copy_bits(), so provide a weak definition of it for NET-less config.
27372748
*/

kernel/bpf/verifier.c

+83-40
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ static void invalidate_non_owning_refs(struct bpf_verifier_env *env);
195195
static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env);
196196
static int ref_set_non_owning(struct bpf_verifier_env *env,
197197
struct bpf_reg_state *reg);
198+
static void specialize_kfunc(struct bpf_verifier_env *env,
199+
u32 func_id, u16 offset, unsigned long *addr);
198200

199201
static bool bpf_map_ptr_poisoned(const struct bpf_insn_aux_data *aux)
200202
{
@@ -2374,6 +2376,7 @@ struct bpf_kfunc_desc {
23742376
u32 func_id;
23752377
s32 imm;
23762378
u16 offset;
2379+
unsigned long addr;
23772380
};
23782381

23792382
struct bpf_kfunc_btf {
@@ -2383,6 +2386,11 @@ struct bpf_kfunc_btf {
23832386
};
23842387

23852388
struct bpf_kfunc_desc_tab {
2389+
/* Sorted by func_id (BTF ID) and offset (fd_array offset) during
2390+
* verification. JITs do lookups by bpf_insn, where func_id may not be
2391+
* available, therefore at the end of verification do_misc_fixups()
2392+
* sorts this by imm and offset.
2393+
*/
23862394
struct bpf_kfunc_desc descs[MAX_KFUNC_DESCS];
23872395
u32 nr_descs;
23882396
};
@@ -2423,6 +2431,19 @@ find_kfunc_desc(const struct bpf_prog *prog, u32 func_id, u16 offset)
24232431
sizeof(tab->descs[0]), kfunc_desc_cmp_by_id_off);
24242432
}
24252433

2434+
int bpf_get_kfunc_addr(const struct bpf_prog *prog, u32 func_id,
2435+
u16 btf_fd_idx, u8 **func_addr)
2436+
{
2437+
const struct bpf_kfunc_desc *desc;
2438+
2439+
desc = find_kfunc_desc(prog, func_id, btf_fd_idx);
2440+
if (!desc)
2441+
return -EFAULT;
2442+
2443+
*func_addr = (u8 *)desc->addr;
2444+
return 0;
2445+
}
2446+
24262447
static struct btf *__find_kfunc_desc_btf(struct bpf_verifier_env *env,
24272448
s16 offset)
24282449
{
@@ -2602,13 +2623,18 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
26022623
func_name);
26032624
return -EINVAL;
26042625
}
2626+
specialize_kfunc(env, func_id, offset, &addr);
26052627

2606-
call_imm = BPF_CALL_IMM(addr);
2607-
/* Check whether or not the relative offset overflows desc->imm */
2608-
if ((unsigned long)(s32)call_imm != call_imm) {
2609-
verbose(env, "address of kernel function %s is out of range\n",
2610-
func_name);
2611-
return -EINVAL;
2628+
if (bpf_jit_supports_far_kfunc_call()) {
2629+
call_imm = func_id;
2630+
} else {
2631+
call_imm = BPF_CALL_IMM(addr);
2632+
/* Check whether the relative offset overflows desc->imm */
2633+
if ((unsigned long)(s32)call_imm != call_imm) {
2634+
verbose(env, "address of kernel function %s is out of range\n",
2635+
func_name);
2636+
return -EINVAL;
2637+
}
26122638
}
26132639

26142640
if (bpf_dev_bound_kfunc_id(func_id)) {
@@ -2621,6 +2647,7 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
26212647
desc->func_id = func_id;
26222648
desc->imm = call_imm;
26232649
desc->offset = offset;
2650+
desc->addr = addr;
26242651
err = btf_distill_func_proto(&env->log, desc_btf,
26252652
func_proto, func_name,
26262653
&desc->func_model);
@@ -2630,19 +2657,19 @@ static int add_kfunc_call(struct bpf_verifier_env *env, u32 func_id, s16 offset)
26302657
return err;
26312658
}
26322659

2633-
static int kfunc_desc_cmp_by_imm(const void *a, const void *b)
2660+
static int kfunc_desc_cmp_by_imm_off(const void *a, const void *b)
26342661
{
26352662
const struct bpf_kfunc_desc *d0 = a;
26362663
const struct bpf_kfunc_desc *d1 = b;
26372664

2638-
if (d0->imm > d1->imm)
2639-
return 1;
2640-
else if (d0->imm < d1->imm)
2641-
return -1;
2665+
if (d0->imm != d1->imm)
2666+
return d0->imm < d1->imm ? -1 : 1;
2667+
if (d0->offset != d1->offset)
2668+
return d0->offset < d1->offset ? -1 : 1;
26422669
return 0;
26432670
}
26442671

2645-
static void sort_kfunc_descs_by_imm(struct bpf_prog *prog)
2672+
static void sort_kfunc_descs_by_imm_off(struct bpf_prog *prog)
26462673
{
26472674
struct bpf_kfunc_desc_tab *tab;
26482675

@@ -2651,7 +2678,7 @@ static void sort_kfunc_descs_by_imm(struct bpf_prog *prog)
26512678
return;
26522679

26532680
sort(tab->descs, tab->nr_descs, sizeof(tab->descs[0]),
2654-
kfunc_desc_cmp_by_imm, NULL);
2681+
kfunc_desc_cmp_by_imm_off, NULL);
26552682
}
26562683

26572684
bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog)
@@ -2665,13 +2692,14 @@ bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
26652692
{
26662693
const struct bpf_kfunc_desc desc = {
26672694
.imm = insn->imm,
2695+
.offset = insn->off,
26682696
};
26692697
const struct bpf_kfunc_desc *res;
26702698
struct bpf_kfunc_desc_tab *tab;
26712699

26722700
tab = prog->aux->kfunc_tab;
26732701
res = bsearch(&desc, tab->descs, tab->nr_descs,
2674-
sizeof(tab->descs[0]), kfunc_desc_cmp_by_imm);
2702+
sizeof(tab->descs[0]), kfunc_desc_cmp_by_imm_off);
26752703

26762704
return res ? &res->func_model : NULL;
26772705
}
@@ -17293,11 +17321,45 @@ static int fixup_call_args(struct bpf_verifier_env *env)
1729317321
return err;
1729417322
}
1729517323

17324+
/* replace a generic kfunc with a specialized version if necessary */
17325+
static void specialize_kfunc(struct bpf_verifier_env *env,
17326+
u32 func_id, u16 offset, unsigned long *addr)
17327+
{
17328+
struct bpf_prog *prog = env->prog;
17329+
bool seen_direct_write;
17330+
void *xdp_kfunc;
17331+
bool is_rdonly;
17332+
17333+
if (bpf_dev_bound_kfunc_id(func_id)) {
17334+
xdp_kfunc = bpf_dev_bound_resolve_kfunc(prog, func_id);
17335+
if (xdp_kfunc) {
17336+
*addr = (unsigned long)xdp_kfunc;
17337+
return;
17338+
}
17339+
/* fallback to default kfunc when not supported by netdev */
17340+
}
17341+
17342+
if (offset)
17343+
return;
17344+
17345+
if (func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
17346+
seen_direct_write = env->seen_direct_write;
17347+
is_rdonly = !may_access_direct_pkt_data(env, NULL, BPF_WRITE);
17348+
17349+
if (is_rdonly)
17350+
*addr = (unsigned long)bpf_dynptr_from_skb_rdonly;
17351+
17352+
/* restore env->seen_direct_write to its original value, since
17353+
* may_access_direct_pkt_data mutates it
17354+
*/
17355+
env->seen_direct_write = seen_direct_write;
17356+
}
17357+
}
17358+
1729617359
static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1729717360
struct bpf_insn *insn_buf, int insn_idx, int *cnt)
1729817361
{
1729917362
const struct bpf_kfunc_desc *desc;
17300-
void *xdp_kfunc;
1730117363

1730217364
if (!insn->imm) {
1730317365
verbose(env, "invalid kernel function call not eliminated in verifier pass\n");
@@ -17306,18 +17368,9 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1730617368

1730717369
*cnt = 0;
1730817370

17309-
if (bpf_dev_bound_kfunc_id(insn->imm)) {
17310-
xdp_kfunc = bpf_dev_bound_resolve_kfunc(env->prog, insn->imm);
17311-
if (xdp_kfunc) {
17312-
insn->imm = BPF_CALL_IMM(xdp_kfunc);
17313-
return 0;
17314-
}
17315-
17316-
/* fallback to default kfunc when not supported by netdev */
17317-
}
17318-
17319-
/* insn->imm has the btf func_id. Replace it with
17320-
* an address (relative to __bpf_call_base).
17371+
/* insn->imm has the btf func_id. Replace it with an offset relative to
17372+
* __bpf_call_base, unless the JIT needs to call functions that are
17373+
* further than 32 bits away (bpf_jit_supports_far_kfunc_call()).
1732117374
*/
1732217375
desc = find_kfunc_desc(env->prog, insn->imm, insn->off);
1732317376
if (!desc) {
@@ -17326,7 +17379,8 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1732617379
return -EFAULT;
1732717380
}
1732817381

17329-
insn->imm = desc->imm;
17382+
if (!bpf_jit_supports_far_kfunc_call())
17383+
insn->imm = BPF_CALL_IMM(desc->addr);
1733017384
if (insn->off)
1733117385
return 0;
1733217386
if (desc->func_id == special_kfunc_list[KF_bpf_obj_new_impl]) {
@@ -17351,17 +17405,6 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1735117405
desc->func_id == special_kfunc_list[KF_bpf_rdonly_cast]) {
1735217406
insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
1735317407
*cnt = 1;
17354-
} else if (desc->func_id == special_kfunc_list[KF_bpf_dynptr_from_skb]) {
17355-
bool seen_direct_write = env->seen_direct_write;
17356-
bool is_rdonly = !may_access_direct_pkt_data(env, NULL, BPF_WRITE);
17357-
17358-
if (is_rdonly)
17359-
insn->imm = BPF_CALL_IMM(bpf_dynptr_from_skb_rdonly);
17360-
17361-
/* restore env->seen_direct_write to its original value, since
17362-
* may_access_direct_pkt_data mutates it
17363-
*/
17364-
env->seen_direct_write = seen_direct_write;
1736517408
}
1736617409
return 0;
1736717410
}
@@ -17891,7 +17934,7 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
1789117934
}
1789217935
}
1789317936

17894-
sort_kfunc_descs_by_imm(env->prog);
17937+
sort_kfunc_descs_by_imm_off(env->prog);
1789517938

1789617939
return 0;
1789717940
}

0 commit comments

Comments
 (0)