]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
libbpf: Support exclusive map creation
authorKP Singh <kpsingh@kernel.org>
Sun, 14 Sep 2025 21:51:33 +0000 (23:51 +0200)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 19 Sep 2025 02:11:42 +0000 (19:11 -0700)
Implement setters and getters that allow map to be registered as
exclusive to the specified program. The registration should be done
before the exclusive program is loaded.

Signed-off-by: KP Singh <kpsingh@kernel.org>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20250914215141.15144-5-kpsingh@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/lib/bpf/bpf.c
tools/lib/bpf/bpf.h
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf.h
tools/lib/bpf/libbpf.map

index ab40dbf9f020fb04addaa45bcddf9ac5dc80eea5..19ad7bcf0c2ff3c2609b90010aa7fc5dbb4be25f 100644 (file)
@@ -172,7 +172,7 @@ int bpf_map_create(enum bpf_map_type map_type,
                   __u32 max_entries,
                   const struct bpf_map_create_opts *opts)
 {
-       const size_t attr_sz = offsetofend(union bpf_attr, map_token_fd);
+       const size_t attr_sz = offsetofend(union bpf_attr, excl_prog_hash_size);
        union bpf_attr attr;
        int fd;
 
@@ -203,6 +203,8 @@ int bpf_map_create(enum bpf_map_type map_type,
        attr.map_ifindex = OPTS_GET(opts, map_ifindex, 0);
 
        attr.map_token_fd = OPTS_GET(opts, token_fd, 0);
+       attr.excl_prog_hash = ptr_to_u64(OPTS_GET(opts, excl_prog_hash, NULL));
+       attr.excl_prog_hash_size = OPTS_GET(opts, excl_prog_hash_size, 0);
 
        fd = sys_bpf_fd(BPF_MAP_CREATE, &attr, attr_sz);
        return libbpf_err_errno(fd);
index 7252150e7ad35759f2486b66c550d7d61719b4cd..e983a3e40d61204dabf6ce1d21bea6d08636ff8a 100644 (file)
@@ -54,9 +54,12 @@ struct bpf_map_create_opts {
        __s32 value_type_btf_obj_fd;
 
        __u32 token_fd;
+
+       const void *excl_prog_hash;
+       __u32 excl_prog_hash_size;
        size_t :0;
 };
-#define bpf_map_create_opts__last_field token_fd
+#define bpf_map_create_opts__last_field excl_prog_hash_size
 
 LIBBPF_API int bpf_map_create(enum bpf_map_type map_type,
                              const char *map_name,
index a39640bd544812fc5710d2b025217ac5129f4a0c..5161c2b398753dd91429fd63014e99d920c1f8ba 100644 (file)
@@ -499,6 +499,7 @@ struct bpf_program {
        __u32 line_info_rec_size;
        __u32 line_info_cnt;
        __u32 prog_flags;
+       __u8  hash[SHA256_DIGEST_LENGTH];
 };
 
 struct bpf_struct_ops {
@@ -578,6 +579,7 @@ struct bpf_map {
        bool autocreate;
        bool autoattach;
        __u64 map_extra;
+       struct bpf_program *excl_prog;
 };
 
 enum extern_type {
@@ -4488,6 +4490,44 @@ bpf_object__section_to_libbpf_map_type(const struct bpf_object *obj, int shndx)
        }
 }
 
+static int bpf_prog_compute_hash(struct bpf_program *prog)
+{
+       struct bpf_insn *purged;
+       int i, err;
+
+       purged = calloc(prog->insns_cnt, BPF_INSN_SZ);
+       if (!purged)
+               return -ENOMEM;
+
+       /* If relocations have been done, the map_fd needs to be
+        * discarded for the digest calculation.
+        */
+       for (i = 0; i < prog->insns_cnt; i++) {
+               purged[i] = prog->insns[i];
+               if (purged[i].code == (BPF_LD | BPF_IMM | BPF_DW) &&
+                   (purged[i].src_reg == BPF_PSEUDO_MAP_FD ||
+                    purged[i].src_reg == BPF_PSEUDO_MAP_VALUE)) {
+                       purged[i].imm = 0;
+                       i++;
+                       if (i >= prog->insns_cnt ||
+                           prog->insns[i].code != 0 ||
+                           prog->insns[i].dst_reg != 0 ||
+                           prog->insns[i].src_reg != 0 ||
+                           prog->insns[i].off != 0) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       purged[i] = prog->insns[i];
+                       purged[i].imm = 0;
+               }
+       }
+       err = libbpf_sha256(purged, prog->insns_cnt * sizeof(struct bpf_insn),
+                           prog->hash, SHA256_DIGEST_LENGTH);
+out:
+       free(purged);
+       return err;
+}
+
 static int bpf_program__record_reloc(struct bpf_program *prog,
                                     struct reloc_desc *reloc_desc,
                                     __u32 insn_idx, const char *sym_name,
@@ -5237,6 +5277,14 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
        create_attr.token_fd = obj->token_fd;
        if (obj->token_fd)
                create_attr.map_flags |= BPF_F_TOKEN_FD;
+       if (map->excl_prog) {
+               err = bpf_prog_compute_hash(map->excl_prog);
+               if (err)
+                       return err;
+
+               create_attr.excl_prog_hash = map->excl_prog->hash;
+               create_attr.excl_prog_hash_size = SHA256_DIGEST_LENGTH;
+       }
 
        if (bpf_map__is_struct_ops(map)) {
                create_attr.btf_vmlinux_value_type_id = map->btf_vmlinux_value_type_id;
@@ -10527,6 +10575,27 @@ int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd)
        return 0;
 }
 
+int bpf_map__set_exclusive_program(struct bpf_map *map, struct bpf_program *prog)
+{
+       if (map_is_created(map)) {
+               pr_warn("exclusive programs must be set before map creation\n");
+               return libbpf_err(-EINVAL);
+       }
+
+       if (map->obj != prog->obj) {
+               pr_warn("excl_prog and map must be from the same bpf object\n");
+               return libbpf_err(-EINVAL);
+       }
+
+       map->excl_prog = prog;
+       return 0;
+}
+
+struct bpf_program *bpf_map__exclusive_program(struct bpf_map *map)
+{
+       return map->excl_prog;
+}
+
 static struct bpf_map *
 __bpf_map__iter(const struct bpf_map *m, const struct bpf_object *obj, int i)
 {
index 2e91148d9b44d15ddf77e2c70f94d32927673348..e978bc093c39145d8087ab98d3fe767b75a78097 100644 (file)
@@ -1291,6 +1291,28 @@ LIBBPF_API int bpf_map__lookup_and_delete_elem(const struct bpf_map *map,
  */
 LIBBPF_API int bpf_map__get_next_key(const struct bpf_map *map,
                                     const void *cur_key, void *next_key, size_t key_sz);
+/**
+ * @brief **bpf_map__set_exclusive_program()** sets a map to be exclusive to the
+ * specified program. This must be called *before* the map is created.
+ *
+ * @param map BPF map to make exclusive.
+ * @param prog BPF program to be the exclusive user of the map. Must belong
+ * to the same bpf_object as the map.
+ * @return 0 on success; a negative error code otherwise.
+ *
+ * This function must be called after the BPF object is opened but before
+ * it is loaded. Once the object is loaded, only the specified program
+ * will be able to access the map's contents.
+ */
+LIBBPF_API int bpf_map__set_exclusive_program(struct bpf_map *map, struct bpf_program *prog);
+
+/**
+ * @brief **bpf_map__exclusive_program()** returns the exclusive program
+ * that is registered with the map (if any).
+ * @param map BPF map to which the exclusive program is registered.
+ * @return the registered exclusive program.
+ */
+LIBBPF_API struct bpf_program *bpf_map__exclusive_program(struct bpf_map *map);
 
 struct bpf_xdp_set_link_opts {
        size_t sz;
index d7bd463e7017e75a878daec998fd4f0910bda047..8ed8749907d472c9e8da781be4ee79c7199324db 100644 (file)
@@ -448,4 +448,7 @@ LIBBPF_1.6.0 {
 } LIBBPF_1.5.0;
 
 LIBBPF_1.7.0 {
+       global:
+               bpf_map__set_exclusive_program;
+               bpf_map__exclusive_program;
 } LIBBPF_1.6.0;