Skip to content

Commit fd264ca

Browse files
yonghong-songAlexei Starovoitov
authored andcommitted
bpf: Add a kfunc to type cast from bpf uapi ctx to kernel ctx
Implement bpf_cast_to_kern_ctx() kfunc which does a type cast of a uapi ctx object to the corresponding kernel ctx. Previously if users want to access some data available in kctx but not in uapi ctx, bpf_probe_read_kernel() helper is needed. The introduction of bpf_cast_to_kern_ctx() allows direct memory access which makes code simpler and easier to understand. Signed-off-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/r/20221120195432.3113982-1-yhs@fb.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent cfe1456 commit fd264ca

File tree

4 files changed

+53
-0
lines changed

4 files changed

+53
-0
lines changed

include/linux/btf.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,7 @@ const struct btf_member *
487487
btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
488488
const struct btf_type *t, enum bpf_prog_type prog_type,
489489
int arg);
490+
int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type);
490491
bool btf_types_are_same(const struct btf *btf1, u32 id1,
491492
const struct btf *btf2, u32 id2);
492493
#else
@@ -531,6 +532,10 @@ btf_get_prog_ctx_type(struct bpf_verifier_log *log, const struct btf *btf,
531532
{
532533
return NULL;
533534
}
535+
static inline int get_kern_ctx_btf_id(struct bpf_verifier_log *log,
536+
enum bpf_prog_type prog_type) {
537+
return -EINVAL;
538+
}
534539
static inline bool btf_types_are_same(const struct btf *btf1, u32 id1,
535540
const struct btf *btf2, u32 id2)
536541
{

kernel/bpf/btf.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5603,6 +5603,26 @@ static int btf_translate_to_vmlinux(struct bpf_verifier_log *log,
56035603
return kern_ctx_type->type;
56045604
}
56055605

5606+
int get_kern_ctx_btf_id(struct bpf_verifier_log *log, enum bpf_prog_type prog_type)
5607+
{
5608+
const struct btf_member *kctx_member;
5609+
const struct btf_type *conv_struct;
5610+
const struct btf_type *kctx_type;
5611+
u32 kctx_type_id;
5612+
5613+
conv_struct = bpf_ctx_convert.t;
5614+
/* get member for kernel ctx type */
5615+
kctx_member = btf_type_member(conv_struct) + bpf_ctx_convert_map[prog_type] * 2 + 1;
5616+
kctx_type_id = kctx_member->type;
5617+
kctx_type = btf_type_by_id(btf_vmlinux, kctx_type_id);
5618+
if (!btf_type_is_struct(kctx_type)) {
5619+
bpf_log(log, "kern ctx type id %u is not a struct\n", kctx_type_id);
5620+
return -EINVAL;
5621+
}
5622+
5623+
return kctx_type_id;
5624+
}
5625+
56065626
BTF_ID_LIST(bpf_ctx_convert_btf_id)
56075627
BTF_ID(struct, bpf_ctx_convert)
56085628

kernel/bpf/helpers.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,6 +1879,11 @@ void bpf_task_release(struct task_struct *p)
18791879
put_task_struct_rcu_user(p);
18801880
}
18811881

1882+
void *bpf_cast_to_kern_ctx(void *obj)
1883+
{
1884+
return obj;
1885+
}
1886+
18821887
__diag_pop();
18831888

18841889
BTF_SET8_START(generic_btf_ids)
@@ -1907,6 +1912,7 @@ BTF_ID(struct, task_struct)
19071912
BTF_ID(func, bpf_task_release)
19081913

19091914
BTF_SET8_START(common_btf_ids)
1915+
BTF_ID_FLAGS(func, bpf_cast_to_kern_ctx)
19101916
BTF_SET8_END(common_btf_ids)
19111917

19121918
static const struct btf_kfunc_id_set common_kfunc_set = {

kernel/bpf/verifier.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7907,6 +7907,7 @@ struct bpf_kfunc_call_arg_meta {
79077907
u32 ref_obj_id;
79087908
u8 release_regno;
79097909
bool r0_rdonly;
7910+
u32 ret_btf_id;
79107911
u64 r0_size;
79117912
struct {
79127913
u64 value;
@@ -8151,6 +8152,7 @@ enum special_kfunc_type {
81518152
KF_bpf_list_push_back,
81528153
KF_bpf_list_pop_front,
81538154
KF_bpf_list_pop_back,
8155+
KF_bpf_cast_to_kern_ctx,
81548156
};
81558157

81568158
BTF_SET_START(special_kfunc_set)
@@ -8160,6 +8162,7 @@ BTF_ID(func, bpf_list_push_front)
81608162
BTF_ID(func, bpf_list_push_back)
81618163
BTF_ID(func, bpf_list_pop_front)
81628164
BTF_ID(func, bpf_list_pop_back)
8165+
BTF_ID(func, bpf_cast_to_kern_ctx)
81638166
BTF_SET_END(special_kfunc_set)
81648167

81658168
BTF_ID_LIST(special_kfunc_list)
@@ -8169,6 +8172,7 @@ BTF_ID(func, bpf_list_push_front)
81698172
BTF_ID(func, bpf_list_push_back)
81708173
BTF_ID(func, bpf_list_pop_front)
81718174
BTF_ID(func, bpf_list_pop_back)
8175+
BTF_ID(func, bpf_cast_to_kern_ctx)
81728176

81738177
static enum kfunc_ptr_arg_type
81748178
get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
@@ -8182,6 +8186,9 @@ get_kfunc_ptr_arg_type(struct bpf_verifier_env *env,
81828186
struct bpf_reg_state *reg = &regs[regno];
81838187
bool arg_mem_size = false;
81848188

8189+
if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx])
8190+
return KF_ARG_PTR_TO_CTX;
8191+
81858192
/* In this function, we verify the kfunc's BTF as per the argument type,
81868193
* leaving the rest of the verification with respect to the register
81878194
* type to our caller. When a set of conditions hold in the BTF type of
@@ -8668,6 +8675,13 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
86688675
verbose(env, "arg#%d expected pointer to ctx, but got %s\n", i, btf_type_str(t));
86698676
return -EINVAL;
86708677
}
8678+
8679+
if (meta->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
8680+
ret = get_kern_ctx_btf_id(&env->log, resolve_prog_type(env->prog));
8681+
if (ret < 0)
8682+
return -EINVAL;
8683+
meta->ret_btf_id = ret;
8684+
}
86718685
break;
86728686
case KF_ARG_PTR_TO_ALLOC_BTF_ID:
86738687
if (reg->type != (PTR_TO_BTF_ID | MEM_ALLOC)) {
@@ -8922,6 +8936,11 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
89228936
regs[BPF_REG_0].btf = field->list_head.btf;
89238937
regs[BPF_REG_0].btf_id = field->list_head.value_btf_id;
89248938
regs[BPF_REG_0].off = field->list_head.node_offset;
8939+
} else if (meta.func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
8940+
mark_reg_known_zero(env, regs, BPF_REG_0);
8941+
regs[BPF_REG_0].type = PTR_TO_BTF_ID | PTR_TRUSTED;
8942+
regs[BPF_REG_0].btf = desc_btf;
8943+
regs[BPF_REG_0].btf_id = meta.ret_btf_id;
89258944
} else {
89268945
verbose(env, "kernel function %s unhandled dynamic return type\n",
89278946
meta.func_name);
@@ -15175,6 +15194,9 @@ static int fixup_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
1517515194
insn_buf[1] = addr[1];
1517615195
insn_buf[2] = *insn;
1517715196
*cnt = 3;
15197+
} else if (desc->func_id == special_kfunc_list[KF_bpf_cast_to_kern_ctx]) {
15198+
insn_buf[0] = BPF_MOV64_REG(BPF_REG_0, BPF_REG_1);
15199+
*cnt = 1;
1517815200
}
1517915201
return 0;
1518015202
}

0 commit comments

Comments
 (0)