]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
bpf: Use function pointers count as struct_ops links count
authorXu Kuohai <xukuohai@huawei.com>
Tue, 12 Nov 2024 14:58:48 +0000 (22:58 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Dec 2024 12:53:25 +0000 (13:53 +0100)
[ Upstream commit 821a3fa32bbe3bc0fa23b3189325d3720a49a24c ]

Only function pointers in a struct_ops structure can be linked to bpf
progs, so set the links count to the function pointers count, instead
of the total members count in the structure.

Suggested-by: Martin KaFai Lau <martin.lau@linux.dev>
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
Link: https://lore.kernel.org/r/20241112145849.3436772-3-xukuohai@huaweicloud.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Stable-dep-of: 7c8ce4ffb684 ("bpf: Add kernel symbol for struct_ops trampoline")
Signed-off-by: Sasha Levin <sashal@kernel.org>
kernel/bpf/bpf_struct_ops.c

index 0d515ec57aa5588dae4a1ba9abf3c63a84fa8411..e085f03ab09915870b5e98bdea214f344ae16edd 100644 (file)
@@ -32,7 +32,7 @@ struct bpf_struct_ops_map {
         * (in kvalue.data).
         */
        struct bpf_link **links;
-       u32 links_cnt;
+       u32 funcs_cnt;
        u32 image_pages_cnt;
        /* image_pages is an array of pages that has all the trampolines
         * that stores the func args before calling the bpf_prog.
@@ -481,11 +481,11 @@ static void bpf_struct_ops_map_put_progs(struct bpf_struct_ops_map *st_map)
 {
        u32 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;
-               }
+       for (i = 0; i < st_map->funcs_cnt; i++) {
+               if (!st_map->links[i])
+                       break;
+               bpf_link_put(st_map->links[i]);
+               st_map->links[i] = NULL;
        }
 }
 
@@ -601,6 +601,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
        int prog_fd, err;
        u32 i, trampoline_start, image_off = 0;
        void *cur_image = NULL, *image = NULL;
+       struct bpf_link **plink;
 
        if (flags)
                return -EINVAL;
@@ -639,6 +640,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
        udata = &uvalue->data;
        kdata = &kvalue->data;
 
+       plink = st_map->links;
        module_type = btf_type_by_id(btf_vmlinux, st_ops_ids[IDX_MODULE_ID]);
        for_each_member(i, t, member) {
                const struct btf_type *mtype, *ptype;
@@ -714,7 +716,7 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
                }
                bpf_link_init(&link->link, BPF_LINK_TYPE_STRUCT_OPS,
                              &bpf_struct_ops_link_lops, prog);
-               st_map->links[i] = &link->link;
+               *plink++ = &link->link;
 
                trampoline_start = image_off;
                err = bpf_struct_ops_prepare_trampoline(tlinks, link,
@@ -895,6 +897,19 @@ static int bpf_struct_ops_map_alloc_check(union bpf_attr *attr)
        return 0;
 }
 
+static u32 count_func_ptrs(const struct btf *btf, const struct btf_type *t)
+{
+       int i;
+       u32 count;
+       const struct btf_member *member;
+
+       count = 0;
+       for_each_member(i, t, member)
+               if (btf_type_resolve_func_ptr(btf, member->type, NULL))
+                       count++;
+       return count;
+}
+
 static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
 {
        const struct bpf_struct_ops_desc *st_ops_desc;
@@ -961,9 +976,9 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
        map = &st_map->map;
 
        st_map->uvalue = bpf_map_area_alloc(vt->size, NUMA_NO_NODE);
-       st_map->links_cnt = btf_type_vlen(t);
+       st_map->funcs_cnt = count_func_ptrs(btf, t);
        st_map->links =
-               bpf_map_area_alloc(st_map->links_cnt * sizeof(struct bpf_links *),
+               bpf_map_area_alloc(st_map->funcs_cnt * sizeof(struct bpf_link *),
                                   NUMA_NO_NODE);
        if (!st_map->uvalue || !st_map->links) {
                ret = -ENOMEM;
@@ -994,7 +1009,7 @@ static u64 bpf_struct_ops_map_mem_usage(const struct bpf_map *map)
        usage = sizeof(*st_map) +
                        vt->size - sizeof(struct bpf_struct_ops_value);
        usage += vt->size;
-       usage += btf_type_vlen(vt) * sizeof(struct bpf_links *);
+       usage += st_map->funcs_cnt * sizeof(struct bpf_link *);
        usage += PAGE_SIZE;
        return usage;
 }