Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bpf: Return hashes of maps in BPF_OBJ_GET_INFO_BY_FD

Currently only array maps are supported, but the implementation can be
extended for other maps and objects. The hash is memoized only for
exclusive and frozen maps as their content is stable until the exclusive
program modifies the map.

This is required for BPF signing, enabling a trusted loader program to
verify a map's integrity. The loader retrieves
the map's runtime hash from the kernel and compares it against an
expected hash computed at build time.

Signed-off-by: KP Singh <kpsingh@kernel.org>
Link: https://lore.kernel.org/r/20250914215141.15144-7-kpsingh@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

KP Singh and committed by
Alexei Starovoitov
ea2e6467 6c850cbc

+48 -2
+3
include/linux/bpf.h
··· 7 7 #include <uapi/linux/bpf.h> 8 8 #include <uapi/linux/filter.h> 9 9 10 + #include <crypto/sha2.h> 10 11 #include <linux/workqueue.h> 11 12 #include <linux/file.h> 12 13 #include <linux/percpu.h> ··· 111 110 long (*map_pop_elem)(struct bpf_map *map, void *value); 112 111 long (*map_peek_elem)(struct bpf_map *map, void *value); 113 112 void *(*map_lookup_percpu_elem)(struct bpf_map *map, void *key, u32 cpu); 113 + int (*map_get_hash)(struct bpf_map *map, u32 hash_buf_size, void *hash_buf); 114 114 115 115 /* funcs called by prog_array and perf_event_array map */ 116 116 void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file, ··· 291 289 }; 292 290 293 291 struct bpf_map { 292 + u8 sha[SHA256_DIGEST_SIZE]; 294 293 const struct bpf_map_ops *ops; 295 294 struct bpf_map *inner_map_meta; 296 295 #ifdef CONFIG_SECURITY
+2
include/uapi/linux/bpf.h
··· 6672 6672 __u32 btf_value_type_id; 6673 6673 __u32 btf_vmlinux_id; 6674 6674 __u64 map_extra; 6675 + __aligned_u64 hash; 6676 + __u32 hash_size; 6675 6677 } __attribute__((aligned(8))); 6676 6678 6677 6679 struct bpf_btf_info {
+13
kernel/bpf/arraymap.c
··· 12 12 #include <uapi/linux/btf.h> 13 13 #include <linux/rcupdate_trace.h> 14 14 #include <linux/btf_ids.h> 15 + #include <crypto/sha2.h> 15 16 16 17 #include "map_in_map.h" 17 18 ··· 173 172 return NULL; 174 173 175 174 return array->value + (u64)array->elem_size * (index & array->index_mask); 175 + } 176 + 177 + static int array_map_get_hash(struct bpf_map *map, u32 hash_buf_size, 178 + void *hash_buf) 179 + { 180 + struct bpf_array *array = container_of(map, struct bpf_array, map); 181 + 182 + sha256(array->value, (u64)array->elem_size * array->map.max_entries, 183 + hash_buf); 184 + memcpy(array->map.sha, hash_buf, sizeof(array->map.sha)); 185 + return 0; 176 186 } 177 187 178 188 static int array_map_direct_value_addr(const struct bpf_map *map, u64 *imm, ··· 812 800 .map_mem_usage = array_map_mem_usage, 813 801 .map_btf_id = &array_map_btf_ids[0], 814 802 .iter_seq_info = &iter_seq_info, 803 + .map_get_hash = &array_map_get_hash, 815 804 }; 816 805 817 806 const struct bpf_map_ops percpu_array_map_ops = {
+23
kernel/bpf/syscall.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com 3 3 */ 4 + #include <crypto/sha2.h> 4 5 #include <linux/bpf.h> 5 6 #include <linux/bpf-cgroup.h> 6 7 #include <linux/bpf_trace.h> ··· 5185 5184 info_len = min_t(u32, sizeof(info), info_len); 5186 5185 5187 5186 memset(&info, 0, sizeof(info)); 5187 + if (copy_from_user(&info, uinfo, info_len)) 5188 + return -EFAULT; 5189 + 5188 5190 info.type = map->map_type; 5189 5191 info.id = map->id; 5190 5192 info.key_size = map->key_size; ··· 5210 5206 err = bpf_map_offload_info_fill(&info, map); 5211 5207 if (err) 5212 5208 return err; 5209 + } 5210 + 5211 + if (info.hash) { 5212 + char __user *uhash = u64_to_user_ptr(info.hash); 5213 + 5214 + if (!map->ops->map_get_hash) 5215 + return -EINVAL; 5216 + 5217 + if (info.hash_size != SHA256_DIGEST_SIZE) 5218 + return -EINVAL; 5219 + 5220 + err = map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, map->sha); 5221 + if (err != 0) 5222 + return err; 5223 + 5224 + if (copy_to_user(uhash, map->sha, SHA256_DIGEST_SIZE) != 0) 5225 + return -EFAULT; 5226 + } else if (info.hash_size) { 5227 + return -EINVAL; 5213 5228 } 5214 5229 5215 5230 if (copy_to_user(uinfo, &info, info_len) ||
+2
tools/include/uapi/linux/bpf.h
··· 6672 6672 __u32 btf_value_type_id; 6673 6673 __u32 btf_vmlinux_id; 6674 6674 __u64 map_extra; 6675 + __aligned_u64 hash; 6676 + __u32 hash_size; 6675 6677 } __attribute__((aligned(8))); 6676 6678 6677 6679 struct bpf_btf_info {
+5 -2
tools/testing/selftests/bpf/progs/verifier_map_ptr.c
··· 70 70 : __clobber_all); 71 71 } 72 72 73 + /* The first element of struct bpf_map is a SHA256 hash of 32 bytes, accessing 74 + * into this array is valid. The opts field is now at offset 33. 75 + */ 73 76 SEC("socket") 74 77 __description("bpf_map_ptr: read non-existent field rejected") 75 78 __failure 76 - __msg("cannot access ptr member ops with moff 0 in struct bpf_map with off 1 size 4") 79 + __msg("cannot access ptr member ops with moff 32 in struct bpf_map with off 33 size 4") 77 80 __failure_unpriv 78 81 __msg_unpriv("access is allowed only to CAP_PERFMON and CAP_SYS_ADMIN") 79 82 __flag(BPF_F_ANY_ALIGNMENT) ··· 85 82 asm volatile (" \ 86 83 r6 = 0; \ 87 84 r1 = %[map_array_48b] ll; \ 88 - r6 = *(u32*)(r1 + 1); \ 85 + r6 = *(u32*)(r1 + 33); \ 89 86 r0 = 1; \ 90 87 exit; \ 91 88 " :