History

bpf: Extend kfunc with PTR_TO_CTX, PTR_TO_MEM argument support

Allow passing PTR_TO_CTX, if the kfunc expects a matching struct type, and punt to PTR_TO_MEM block if reg->type does not fall in one of PTR_TO_BTF_ID or PTR_TO_SOCK* types. This will be used by future commits to get access to XDP and TC PTR_TO_CTX, and pass various data (flags, l4proto, netns_id, etc.) encoded in opts struct passed as pointer to kfunc. For PTR_TO_MEM support, arguments are currently limited to pointer to scalar, or pointer to struct composed of scalars. This is done so that unsafe scenarios (like passing PTR_TO_MEM where PTR_TO_BTF_ID of in-kernel valid structure is expected, which may have pointers) are avoided. Since the argument checking happens basd on argument register type, it is not easy to ascertain what the expected type is. In the future, support for PTR_TO_MEM for kfunc can be extended to serve other usecases. The struct type whose pointer is passed in may have maximum nesting depth of 4, all recursively composed of scalars or struct with scalars. Future commits will add negative tests that check whether these restrictions imposed for kfunc arguments are duly rejected by BPF verifier or not.

Kumar Kartikeya Dwivedi committed 4 years ago

Commit 3363bd01 parent 7f16d2a1 file · +73 −21Browse files

Unified · Split

kernel/bpf/btf.c+73−21
@@ -5576,12 +5576,53 @@ static u32 *reg2btf_ids[__BPF_REG_TYPE_MAX] = { · 5575 unmodified lines
55765576 #endif
55775577 };
55785578
5579+/* Returns true if struct is composed of scalars, 4 levels of nesting allowed */
5580+static bool __btf_type_is_scalar_struct(struct bpf_verifier_log *log,
5581+ const struct btf *btf,
5582+ const struct btf_type *t, int rec)
5583+{
5584+ const struct btf_type *member_type;
5585+ const struct btf_member *member;
5586+ u32 i;
5587+
5588+ if (!btf_type_is_struct(t))
5589+ return false;
5590+
5591+ for_each_member(i, t, member) {
5592+ const struct btf_array *array;
5593+
5594+ member_type = btf_type_skip_modifiers(btf, member->type, NULL);
5595+ if (btf_type_is_struct(member_type)) {
5596+ if (rec >= 3) {
5597+ bpf_log(log, "max struct nesting depth exceeded\n");
5598+ return false;
5599+ }
5600+ if (!__btf_type_is_scalar_struct(log, btf, member_type, rec + 1))
5601+ return false;
5602+ continue;
5603+ }
5604+ if (btf_type_is_array(member_type)) {
5605+ array = btf_type_array(member_type);
5606+ if (!array->nelems)
5607+ return false;
5608+ member_type = btf_type_skip_modifiers(btf, array->type, NULL);
5609+ if (!btf_type_is_scalar(member_type))
5610+ return false;
5611+ continue;
5612+ }
5613+ if (!btf_type_is_scalar(member_type))
5614+ return false;
5615+ }
5616+ return true;
5617+}
5618+
55795619 static int btf_check_func_arg_match(struct bpf_verifier_env *env,
55805620 const struct btf *btf, u32 func_id,
55815621 struct bpf_reg_state *regs,
55825622 bool ptr_to_mem_ok)
55835623 {
55845624 struct bpf_verifier_log *log = &env->log;
5625+ bool is_kfunc = btf_is_kernel(btf);
55855626 const char *func_name, *ref_tname;
55865627 const struct btf_type *t, *ref_t;
55875628 const struct btf_param *args;
@@ -5634,7 +5675,20 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 46 unmodified lines
56345675
56355676 ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
56365677 ref_tname = btf_name_by_offset(btf, ref_t->name_off);
5637− if (btf_is_kernel(btf)) {
5678+ if (btf_get_prog_ctx_type(log, btf, t,
5679+ env->prog->type, i)) {
5680+ /* If function expects ctx type in BTF check that caller
5681+ * is passing PTR_TO_CTX.
5682+ */
5683+ if (reg->type != PTR_TO_CTX) {
5684+ bpf_log(log,
5685+ "arg#%d expected pointer to ctx, but got %s\n",
5686+ i, btf_type_str(t));
5687+ return -EINVAL;
5688+ }
5689+ if (check_ctx_reg(env, reg, regno))
5690+ return -EINVAL;
5691+ } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID || reg2btf_ids[reg->type])) {
56385692 const struct btf_type *reg_ref_t;
56395693 const struct btf *reg_btf;
56405694 const char *reg_ref_tname;
@@ -5650,14 +5704,9 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 9 unmodified lines
56505704 if (reg->type == PTR_TO_BTF_ID) {
56515705 reg_btf = reg->btf;
56525706 reg_ref_id = reg->btf_id;
5653− } else if (reg2btf_ids[reg->type]) {
5707+ } else {
56545708 reg_btf = btf_vmlinux;
56555709 reg_ref_id = *reg2btf_ids[reg->type];
5656− } else {
5657− bpf_log(log, "kernel function %s args#%d expected pointer to %s %s but R%d is not a pointer to btf_id\n",
5658− func_name, i,
5659− btf_type_str(ref_t), ref_tname, regno);
5660− return -EINVAL;
56615710 }
56625711
56635712 reg_ref_t = btf_type_skip_modifiers(reg_btf, reg_ref_id,
@@ -5673,23 +5722,24 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 9 unmodified lines
56735722 reg_ref_tname);
56745723 return -EINVAL;
56755724 }
5676− } else if (btf_get_prog_ctx_type(log, btf, t,
5677− env->prog->type, i)) {
5678− /* If function expects ctx type in BTF check that caller
5679− * is passing PTR_TO_CTX.
5680− */
5681− if (reg->type != PTR_TO_CTX) {
5682− bpf_log(log,
5683− "arg#%d expected pointer to ctx, but got %s\n",
5684− i, btf_type_str(t));
5685− return -EINVAL;
5686− }
5687− if (check_ctx_reg(env, reg, regno))
5688− return -EINVAL;
56895725 } else if (ptr_to_mem_ok) {
56905726 const struct btf_type *resolve_ret;
56915727 u32 type_size;
56925728
5729+ if (is_kfunc) {
5730+ /* Permit pointer to mem, but only when argument
5731+ * type is pointer to scalar, or struct composed
5732+ * (recursively) of scalars.
5733+ */
5734+ if (!btf_type_is_scalar(ref_t) &&
5735+ !__btf_type_is_scalar_struct(log, btf, ref_t, 0)) {
5736+ bpf_log(log,
5737+ "arg#%d pointer type %s %s must point to scalar or struct with scalar\n",
5738+ i, btf_type_str(ref_t), ref_tname);
5739+ return -EINVAL;
5740+ }
5741+ }
5742+
56935743 resolve_ret = btf_resolve_size(btf, ref_t, &type_size);
56945744 if (IS_ERR(resolve_ret)) {
56955745 bpf_log(log,
@@ -5702,6 +5752,8 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, · 6 unmodified lines
57025752 if (check_mem_reg(env, reg, regno, type_size))
57035753 return -EINVAL;
57045754 } else {
5755+ bpf_log(log, "reg type unsupported for arg#%d %sfunction %s#%d\n", i,
5756+ is_kfunc ? "kernel " : "", func_name, func_id);
57055757 return -EINVAL;
57065758 }
57075759 }
@@ -5751,7 +5803,7 @@ int btf_check_kfunc_arg_match(struct bpf_verifier_env *env, · 43 unmodified lines
57515803 const struct btf *btf, u32 func_id,
57525804 struct bpf_reg_state *regs)
57535805 {
5754− return btf_check_func_arg_match(env, btf, func_id, regs, false);
5806+ return btf_check_func_arg_match(env, btf, func_id, regs, true);
57555807 }
57565808
57575809 /* Convert BTF of a function into bpf_reg_state if possible