From: Kui-Feng Lee <sinquersw@gmail.com>
To: Martin KaFai Lau <martin.lau@linux.dev>, thinker.li@gmail.com
Cc: kuifeng@meta.com, bpf@vger.kernel.org, ast@kernel.org,
song@kernel.org, kernel-team@meta.com, andrii@kernel.org,
drosen@google.com
Subject: Re: [PATCH bpf-next v16 09/14] bpf: hold module refcnt in bpf_struct_ops map creation and prog verification.
Date: Fri, 19 Jan 2024 11:10:41 -0800 [thread overview]
Message-ID: <16194618-41f7-4729-80a9-7b9a94554ae2@gmail.com> (raw)
In-Reply-To: <a0a382b1-467c-4c28-8882-8f523826178a@linux.dev>
On 1/18/24 14:18, Martin KaFai Lau wrote:
> On 1/17/24 5:49 PM, thinker.li@gmail.com wrote:
>> From: Kui-Feng Lee <thinker.li@gmail.com>
>>
>> To ensure that a module remains accessible whenever a struct_ops
>> object of
>> a struct_ops type provided by the module is still in use.
>>
>> struct bpf_struct_ops_map doesn't hold a refcnt to btf anymore since a
>> module will hold a refcnt to it's btf already. But, struct_ops
>> programs are
>> different. They hold their associated btf, not the module since they need
>> only btf to assure their types (signatures).
>>
>> However, verifier holds the refcnt of the associated module of a
>> struct_ops
>> type temporarily when verify a struct_ops prog. Verifier needs the help
>> from the verifier operators (struct bpf_verifier_ops) provided by the
>> owner
>> module to verify data access of a prog, provide information, and generate
>> code.
>>
>> This patch also add a count of links (links_cnt) to
>> bpf_struct_ops_map. It
>> avoids bpf_struct_ops_map_put_progs() from accessing btf after calling
>> module_put() in bpf_struct_ops_map_free().
>
> Good catch in v16.
>
>>
>> Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
>> ---
>> include/linux/bpf.h | 1 +
>> include/linux/bpf_verifier.h | 1 +
>> kernel/bpf/bpf_struct_ops.c | 31 +++++++++++++++++++++++++------
>> kernel/bpf/verifier.c | 10 ++++++++++
>> 4 files changed, 37 insertions(+), 6 deletions(-)
>>
>> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
>> index 3d1c1014fdb2..a977ed75288c 100644
>> --- a/include/linux/bpf.h
>> +++ b/include/linux/bpf.h
>> @@ -1674,6 +1674,7 @@ struct bpf_struct_ops {
>> int (*update)(void *kdata, void *old_kdata);
>> int (*validate)(void *kdata);
>> void *cfi_stubs;
>> + struct module *owner;
>> const char *name;
>> struct btf_func_model func_models[BPF_STRUCT_OPS_MAX_NR_MEMBERS];
>> };
>> diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
>> index d07d857ca67f..e6cf025c9446 100644
>> --- a/include/linux/bpf_verifier.h
>> +++ b/include/linux/bpf_verifier.h
>> @@ -662,6 +662,7 @@ struct bpf_verifier_env {
>> u32 prev_insn_idx;
>> struct bpf_prog *prog; /* eBPF program being verified */
>> const struct bpf_verifier_ops *ops;
>> + struct module *attach_btf_mod; /* The owner module of
>> prog->aux->attach_btf */
>> struct bpf_verifier_stack_elem *head; /* stack of verifier
>> states to be processed */
>> int stack_size; /* number of states to be processed */
>> bool strict_alignment; /* perform strict pointer
>> alignment checks */
>> diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
>> index 3b8d689ece5d..61486f6595ea 100644
>> --- a/kernel/bpf/bpf_struct_ops.c
>> +++ b/kernel/bpf/bpf_struct_ops.c
>> @@ -40,6 +40,7 @@ struct bpf_struct_ops_map {
>> * (in kvalue.data).
>> */
>> struct bpf_link **links;
>> + u32 links_cnt;
>> /* image is a page that has all the trampolines
>> * that stores the func args before calling the bpf_prog.
>> * A PAGE_SIZE "image" is enough to store all trampoline for
>> @@ -306,10 +307,9 @@ static void
>> *bpf_struct_ops_map_lookup_elem(struct bpf_map *map, void *key)
>> static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map
>> *st_map)
>> {
>> - const struct btf_type *t = st_map->st_ops_desc->type;
>> u32 i;
>> - for (i = 0; i < btf_type_vlen(t); i++) {
>> + for (i = 0; i < st_map->links_cnt; i++) {
>> if (st_map->links[i]) {
>> bpf_link_put(st_map->links[i]);
>> st_map->links[i] = NULL;
>> @@ -641,12 +641,20 @@ static void __bpf_struct_ops_map_free(struct
>> bpf_map *map)
>> bpf_jit_uncharge_modmem(PAGE_SIZE);
>> }
>> bpf_map_area_free(st_map->uvalue);
>> - btf_put(st_map->btf);
>> bpf_map_area_free(st_map);
>> }
>> static void bpf_struct_ops_map_free(struct bpf_map *map)
>> {
>> + struct bpf_struct_ops_map *st_map = (struct bpf_struct_ops_map
>> *)map;
>> +
>> + /* st_ops->owner was acquired during map_alloc to implicitly holds
>> + * the btf's refcnt. The acquire was only done when btf_is_module()
>> + * st_map->btf cannot be NULL here.
>> + */
>> + if (btf_is_module(st_map->btf))
>> + module_put(st_map->st_ops_desc->st_ops->owner);
>> +
>> /* The struct_ops's function may switch to another struct_ops.
>> *
>> * For example, bpf_tcp_cc_x->init() may switch to
>> @@ -682,6 +690,7 @@ static struct bpf_map
>> *bpf_struct_ops_map_alloc(union bpf_attr *attr)
>> size_t st_map_size;
>> struct bpf_struct_ops_map *st_map;
>> const struct btf_type *t, *vt;
>> + struct module *mod = NULL;
>> struct bpf_map *map;
>> struct btf *btf;
>> int ret;
>> @@ -695,11 +704,20 @@ static struct bpf_map
>> *bpf_struct_ops_map_alloc(union bpf_attr *attr)
>> btf_put(btf);
>> return ERR_PTR(-EINVAL);
>> }
>> +
>> + mod = btf_try_get_module(btf);
>
> nit. btf_put(btf) here.
>
>> + if (!mod) {
>> + btf_put(btf);
>> + return ERR_PTR(-EINVAL);
>> + }
>> + /* mod holds a refcnt to btf. We don't need an extra refcnt
>> + * here.
>> + */
>> + btf_put(btf);
>> } else {
>> btf = bpf_get_btf_vmlinux();
>> if (IS_ERR(btf))
>> return ERR_CAST(btf);
>> - btf_get(btf);
>> }
>> st_ops_desc = bpf_struct_ops_find_value(btf,
>> attr->btf_vmlinux_value_type_id);
>> @@ -746,8 +764,9 @@ static struct bpf_map
>> *bpf_struct_ops_map_alloc(union bpf_attr *attr)
>> goto errout_free;
>> }
>> st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE);
>> + st_map->links_cnt = btf_type_vlen(t);
>> st_map->links =
>> - bpf_map_area_alloc(btf_type_vlen(t) * sizeof(struct bpf_links
>> *),
>> + bpf_map_area_alloc(st_map->links_cnt * sizeof(struct
>> bpf_links *),
>> NUMA_NO_NODE);
>> if (!st_map->uvalue || !st_map->links) {
>> ret = -ENOMEM;
>> @@ -763,7 +782,7 @@ static struct bpf_map
>> *bpf_struct_ops_map_alloc(union bpf_attr *attr)
>> errout_free:
>> __bpf_struct_ops_map_free(map);
>> errout:
>> - btf_put(btf);
>> + module_put(mod);
>> return ERR_PTR(ret);
>> }
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index ff41f7736618..60f08f468399 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -20243,6 +20243,14 @@ static int check_struct_ops_btf_id(struct
>> bpf_verifier_env *env)
>> }
>> btf = prog->aux->attach_btf ?: bpf_get_btf_vmlinux();
>> + if (btf_is_module(btf)) {
>> + /* Make sure st_ops is valid through the lifetime of env */
>> + env->attach_btf_mod = btf_try_get_module(btf);
>> + if (!env->attach_btf_mod) {
>> + verbose(env, "owner module of btf is not found\n");
>
> nit. A better message, something like:
>
> verbose(env, "struct_ops module %s is not found\n",
> btf_get_name(btf));
Got it!
>
>> + return -ENOTSUPP;
>> + }
>> + }
>> btf_id = prog->aux->attach_btf_id;
>> st_ops_desc = bpf_struct_ops_find(btf, btf_id);
>> @@ -20968,6 +20976,8 @@ int bpf_check(struct bpf_prog **prog, union
>> bpf_attr *attr, bpfptr_t uattr, __u3
>> env->prog->expected_attach_type = 0;
>> *prog = env->prog;
>> +
>> + module_put(env->attach_btf_mod);
>> err_unlock:
>> if (!is_priv)
>> mutex_unlock(&bpf_verifier_lock);
>
next prev parent reply other threads:[~2024-01-19 19:10 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-18 1:49 [PATCH bpf-next v16 00/14] Registrating struct_ops types from modules thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 01/14] bpf: refactory struct_ops type initialization to a function thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 02/14] bpf: get type information with BTF_ID_LIST thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 03/14] bpf, net: introduce bpf_struct_ops_desc thinker.li
2024-01-18 21:30 ` Martin KaFai Lau
2024-01-19 0:47 ` Kui-Feng Lee
2024-01-18 1:49 ` [PATCH bpf-next v16 04/14] bpf: add struct_ops_tab to btf thinker.li
2024-01-18 21:36 ` Martin KaFai Lau
2024-01-19 1:13 ` Kui-Feng Lee
2024-01-18 1:49 ` [PATCH bpf-next v16 05/14] bpf: make struct_ops_map support btfs other than btf_vmlinux thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 06/14] bpf: pass btf object id in bpf_map_info thinker.li
2024-01-18 21:42 ` Martin KaFai Lau
2024-01-19 21:38 ` Kui-Feng Lee
2024-01-18 1:49 ` [PATCH bpf-next v16 07/14] bpf: lookup struct_ops types from a given module BTF thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 08/14] bpf: pass attached BTF to the bpf_struct_ops subsystem thinker.li
2024-01-18 21:56 ` Martin KaFai Lau
2024-01-19 18:05 ` Kui-Feng Lee
2024-01-19 18:43 ` Kui-Feng Lee
2024-01-18 1:49 ` [PATCH bpf-next v16 09/14] bpf: hold module refcnt in bpf_struct_ops map creation and prog verification thinker.li
2024-01-18 22:18 ` Martin KaFai Lau
2024-01-19 19:10 ` Kui-Feng Lee [this message]
2024-01-18 1:49 ` [PATCH bpf-next v16 10/14] bpf: validate value_type thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 11/14] bpf, net: switch to dynamic registration thinker.li
2024-01-18 22:25 ` Martin KaFai Lau
2024-01-19 19:29 ` Kui-Feng Lee
2024-01-18 1:49 ` [PATCH bpf-next v16 12/14] libbpf: Find correct module BTFs for struct_ops maps and progs thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 13/14] bpf: export btf_ctx_access to modules thinker.li
2024-01-18 1:49 ` [PATCH bpf-next v16 14/14] selftests/bpf: test case for register_bpf_struct_ops() thinker.li
2024-01-18 22:41 ` Martin KaFai Lau
2024-01-19 19:31 ` Kui-Feng Lee
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=16194618-41f7-4729-80a9-7b9a94554ae2@gmail.com \
--to=sinquersw@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=drosen@google.com \
--cc=kernel-team@meta.com \
--cc=kuifeng@meta.com \
--cc=martin.lau@linux.dev \
--cc=song@kernel.org \
--cc=thinker.li@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).