@@ -6142,18 +6142,13 @@ static bool __btf_type_is_scalar_struct(struct bpf_verifier_log *log,
return true;
}
-static bool is_kfunc_arg_mem_size(const struct btf *btf,
- const struct btf_param *arg,
- const struct bpf_reg_state *reg)
+static bool btf_param_match_suffix(const struct btf *btf,
+ const struct btf_param *arg,
+ const char *suffix)
{
- int len, sfx_len = sizeof("__sz") - 1;
- const struct btf_type *t;
+ int len, sfx_len = strlen(suffix);
const char *param_name;
- t = btf_type_skip_modifiers(btf, arg->type, NULL);
- if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE)
- return false;
-
/* In the future, this can be ported to use BTF tagging */
param_name = btf_name_by_offset(btf, arg->name_off);
if (str_is_empty(param_name))
@@ -6162,12 +6157,25 @@ static bool is_kfunc_arg_mem_size(const struct btf *btf,
if (len < sfx_len)
return false;
param_name += len - sfx_len;
- if (strncmp(param_name, "__sz", sfx_len))
+ if (strncmp(param_name, suffix, sfx_len))
return false;
return true;
}
+static bool is_kfunc_arg_mem_size(const struct btf *btf,
+ const struct btf_param *arg,
+ const struct bpf_reg_state *reg)
+{
+ const struct btf_type *t;
+
+ t = btf_type_skip_modifiers(btf, arg->type, NULL);
+ if (!btf_type_is_scalar(t) || reg->type != SCALAR_VALUE)
+ return false;
+
+ return btf_param_match_suffix(btf, arg, "__sz");
+}
+
static int btf_check_func_arg_match(struct bpf_verifier_env *env,
const struct btf *btf, u32 func_id,
struct bpf_reg_state *regs,
@@ -6302,8 +6310,12 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
i, btf_type_str(t));
return -EINVAL;
}
- } else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
- (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
+ } else if (is_kfunc && ((reg->type == PTR_TO_BTF_ID ||
+ (reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type))) ||
+ (btf_param_match_suffix(btf, &args[i], "__maybe_null") &&
+ (reg->type == PTR_TO_BTF_ID_OR_NULL ||
+ (reg2btf_ids[base_type(reg->type)] &&
+ type_flag(reg->type) == PTR_MAYBE_NULL))))) {
const struct btf_type *reg_ref_t;
const struct btf *reg_btf;
const char *reg_ref_tname;
@@ -6316,7 +6328,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
return -EINVAL;
}
- if (reg->type == PTR_TO_BTF_ID) {
+ if (base_type(reg->type) == PTR_TO_BTF_ID) {
reg_btf = reg->btf;
reg_ref_id = reg->btf_id;
/* Ensure only one argument is referenced PTR_TO_BTF_ID */
@@ -6354,6 +6366,10 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
if (is_kfunc) {
bool arg_mem_size = i + 1 < nargs && is_kfunc_arg_mem_size(btf, &args[i + 1], ®s[regno + 1]);
bool arg_dynptr = !strcmp(ref_tname, "bpf_dynptr_kern");
+ bool arg_null_ok = btf_param_match_suffix(btf, &args[i],
+ "__maybe_null") &&
+ reg->type == SCALAR_VALUE &&
+ tnum_equals_const(reg->var_off, 0);
/* Permit pointer to mem, but only when argument
* type is pointer to scalar, or struct composed
@@ -6363,7 +6379,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
*/
if (!btf_type_is_scalar(ref_t) &&
!__btf_type_is_scalar_struct(log, btf, ref_t, 0) &&
- !arg_dynptr &&
+ !arg_dynptr && !arg_null_ok &&
(arg_mem_size ? !btf_type_is_void(ref_t) : 1)) {
bpf_log(log,
"arg#%d pointer type %s %s must point to %sscalar, or struct with scalar\n",
@@ -6371,6 +6387,10 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
return -EINVAL;
}
+ /* kfunc accepts NULL pointer. */
+ if (arg_null_ok)
+ continue;
+
/* Assume initialized dynptr. */
if (arg_dynptr) {
if (!is_dynptr_reg_valid_init(env, reg,
Since kfuncs don't have a prototype defined, the BTF code has to infer the information in a different way. For example, naming a parameter with the __sz suffix is currently the way to declare such parameter as a memory size. Another feature not available without a prototype was flagging an argument as PTR_MAYBE_NULL, meaning that the function is trusted to correctly handle a NULL pointer. Similarly to the __sz suffix, introduce the __maybe_null suffix to have an equivalent feature of setting the PTR_MAYBE_NULL flag. Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com> Cc: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> --- kernel/bpf/btf.c | 48 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 14 deletions(-)