Skip to content

Commit 5ab4bc6

Browse files
etsalAlexei Starovoitov
authored andcommitted
verifier: parse BTF type tags for function arguments
The BTF parsing logic for function arguments goes through the arguments' decl tags, but does not go into their type tags. Add type tag parsing for function arguments. Acked-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com> Link: https://lore.kernel.org/r/20260602004120.17087-3-emil@etsalapatis.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent a0fa68d commit 5ab4bc6

1 file changed

Lines changed: 85 additions & 35 deletions

File tree

kernel/bpf/btf.c

Lines changed: 85 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7802,6 +7802,84 @@ enum btf_arg_tag {
78027802
ARG_TAG_ARENA = BIT_ULL(5),
78037803
};
78047804

7805+
static int btf_scan_decl_tags(struct bpf_verifier_env *env,
7806+
const struct btf *btf,
7807+
const struct btf_type *fn_t,
7808+
u32 arg_idx, bool is_global, u32 *tags)
7809+
{
7810+
int id = btf_named_start_id(btf, false) - 1;
7811+
7812+
/*
7813+
* The 'arg:<tag>' decl_tag takes precedence over the derivation
7814+
* of the register type from the BTF type itself.
7815+
*/
7816+
while ((id = btf_find_next_decl_tag(btf, fn_t, arg_idx, "arg:", id)) > 0) {
7817+
const struct btf_type *tag_t = btf_type_by_id(btf, id);
7818+
const char *tag = __btf_name_by_offset(btf, tag_t->name_off) + 4;
7819+
7820+
/* disallow arg tags in static subprogs */
7821+
if (!is_global) {
7822+
bpf_log(&env->log,
7823+
"arg#%d type tag is not supported in static functions\n",
7824+
arg_idx);
7825+
return -EOPNOTSUPP;
7826+
}
7827+
7828+
if (strcmp(tag, "ctx") == 0) {
7829+
*tags |= ARG_TAG_CTX;
7830+
} else if (strcmp(tag, "trusted") == 0) {
7831+
*tags |= ARG_TAG_TRUSTED;
7832+
} else if (strcmp(tag, "untrusted") == 0) {
7833+
*tags |= ARG_TAG_UNTRUSTED;
7834+
} else if (strcmp(tag, "nonnull") == 0) {
7835+
*tags |= ARG_TAG_NONNULL;
7836+
} else if (strcmp(tag, "nullable") == 0) {
7837+
*tags |= ARG_TAG_NULLABLE;
7838+
} else if (strcmp(tag, "arena") == 0) {
7839+
*tags |= ARG_TAG_ARENA;
7840+
} else {
7841+
bpf_log(&env->log, "arg#%d has unsupported set of tags\n", arg_idx);
7842+
return -EOPNOTSUPP;
7843+
}
7844+
}
7845+
if (id != -ENOENT) {
7846+
bpf_log(&env->log, "arg#%d type tag fetching failure: %d\n", arg_idx, id);
7847+
return id;
7848+
}
7849+
7850+
return 0;
7851+
}
7852+
7853+
static int btf_scan_type_tags(struct bpf_verifier_env *env,
7854+
const struct btf *btf, u32 type_id,
7855+
u32 *tags)
7856+
{
7857+
const struct btf_type *t;
7858+
7859+
/* Find the first pointer type in the chain. */
7860+
t = btf_type_skip_modifiers(btf, type_id, NULL);
7861+
if (!t || !btf_type_is_ptr(t))
7862+
return 0;
7863+
7864+
/* We got a pointer, get all associated type tags. */
7865+
t = btf_type_by_id(btf, t->type);
7866+
while (t && btf_type_is_type_tag(t)) {
7867+
const char *tag = __btf_name_by_offset(btf, t->name_off);
7868+
7869+
if (strcmp(tag, "arena") == 0) {
7870+
*tags |= ARG_TAG_ARENA;
7871+
} else {
7872+
bpf_log(&env->log, "function signature member has unsupported type tag '%s'\n",
7873+
tag);
7874+
return -EOPNOTSUPP;
7875+
}
7876+
7877+
t = btf_type_by_id(btf, t->type);
7878+
}
7879+
7880+
return 0;
7881+
}
7882+
78057883
/* Process BTF of a function to produce high-level expectation of function
78067884
* arguments (like ARG_PTR_TO_CTX, or ARG_PTR_TO_MEM, etc). This information
78077885
* is cached in subprog info for reuse.
@@ -7820,6 +7898,7 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
78207898
struct btf *btf = prog->aux->btf;
78217899
const struct btf_param *args;
78227900
const struct btf_type *t, *ref_t, *fn_t;
7901+
int err;
78237902
u32 i, nargs, btf_id;
78247903
const char *tname;
78257904

@@ -7903,42 +7982,13 @@ int btf_prepare_func_args(struct bpf_verifier_env *env, int subprog)
79037982
*/
79047983
for (i = 0; i < nargs; i++) {
79057984
u32 tags = 0;
7906-
int id = btf_named_start_id(btf, false) - 1;
7907-
7908-
/* 'arg:<tag>' decl_tag takes precedence over derivation of
7909-
* register type from BTF type itself
7910-
*/
7911-
while ((id = btf_find_next_decl_tag(btf, fn_t, i, "arg:", id)) > 0) {
7912-
const struct btf_type *tag_t = btf_type_by_id(btf, id);
7913-
const char *tag = __btf_name_by_offset(btf, tag_t->name_off) + 4;
7914-
7915-
/* disallow arg tags in static subprogs */
7916-
if (!is_global) {
7917-
bpf_log(log, "arg#%d type tag is not supported in static functions\n", i);
7918-
return -EOPNOTSUPP;
7919-
}
7985+
err = btf_scan_decl_tags(env, btf, fn_t, i, is_global, &tags);
7986+
if (err)
7987+
return err;
79207988

7921-
if (strcmp(tag, "ctx") == 0) {
7922-
tags |= ARG_TAG_CTX;
7923-
} else if (strcmp(tag, "trusted") == 0) {
7924-
tags |= ARG_TAG_TRUSTED;
7925-
} else if (strcmp(tag, "untrusted") == 0) {
7926-
tags |= ARG_TAG_UNTRUSTED;
7927-
} else if (strcmp(tag, "nonnull") == 0) {
7928-
tags |= ARG_TAG_NONNULL;
7929-
} else if (strcmp(tag, "nullable") == 0) {
7930-
tags |= ARG_TAG_NULLABLE;
7931-
} else if (strcmp(tag, "arena") == 0) {
7932-
tags |= ARG_TAG_ARENA;
7933-
} else {
7934-
bpf_log(log, "arg#%d has unsupported set of tags\n", i);
7935-
return -EOPNOTSUPP;
7936-
}
7937-
}
7938-
if (id != -ENOENT) {
7939-
bpf_log(log, "arg#%d type tag fetching failure: %d\n", i, id);
7940-
return id;
7941-
}
7989+
err = btf_scan_type_tags(env, btf, args[i].type, &tags);
7990+
if (err)
7991+
return err;
79427992

79437993
t = btf_type_by_id(btf, args[i].type);
79447994
while (btf_type_is_modifier(t))

0 commit comments

Comments
 (0)