Commit baefdbdf authored by KP Singh's avatar KP Singh Committed by Alexei Starovoitov
Browse files

bpf: Implement exclusive map creation



Exclusive maps allow maps to only be accessed by program with a
program with a matching hash which is specified in the excl_prog_hash
attr.

For the signing use-case, this allows the trusted loader program
to load the map and verify the integrity

Signed-off-by: default avatarKP Singh <kpsingh@kernel.org>
Link: https://lore.kernel.org/r/20250914215141.15144-3-kpsingh@kernel.org


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 603b4416
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -329,6 +329,7 @@ struct bpf_map {
	atomic64_t sleepable_refcnt;
	s64 __percpu *elem_count;
	u64 cookie; /* write-once */
	char *excl_prog_sha;
};

static inline const char *btf_field_type_name(enum btf_field_type type)
+6 −0
Original line number Diff line number Diff line
@@ -1522,6 +1522,12 @@ union bpf_attr {
		 * If provided, map_flags should have BPF_F_TOKEN_FD flag set.
		 */
		__s32	map_token_fd;

		/* Hash of the program that has exclusive access to the map.
		 */
		__aligned_u64 excl_prog_hash;
		/* Size of the passed excl_prog_hash. */
		__u32 excl_prog_hash_size;
	};

	struct { /* anonymous struct used by BPF_MAP_*_ELEM and BPF_MAP_FREEZE commands */
+27 −4
Original line number Diff line number Diff line
@@ -860,6 +860,7 @@ static void bpf_map_free(struct bpf_map *map)
	 * the free of values or special fields allocated from bpf memory
	 * allocator.
	 */
	kfree(map->excl_prog_sha);
	migrate_disable();
	map->ops->map_free(map);
	migrate_enable();
@@ -1338,9 +1339,9 @@ static bool bpf_net_capable(void)
	return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
}

#define BPF_MAP_CREATE_LAST_FIELD map_token_fd
#define BPF_MAP_CREATE_LAST_FIELD excl_prog_hash_size
/* called via syscall */
static int map_create(union bpf_attr *attr, bool kernel)
static int map_create(union bpf_attr *attr, bpfptr_t uattr)
{
	const struct bpf_map_ops *ops;
	struct bpf_token *token = NULL;
@@ -1534,7 +1535,29 @@ static int map_create(union bpf_attr *attr, bool kernel)
			attr->btf_vmlinux_value_type_id;
	}

	err = security_bpf_map_create(map, attr, token, kernel);
	if (attr->excl_prog_hash) {
		bpfptr_t uprog_hash = make_bpfptr(attr->excl_prog_hash, uattr.is_kernel);

		if (attr->excl_prog_hash_size != SHA256_DIGEST_SIZE) {
			err = -EINVAL;
			goto free_map;
		}

		map->excl_prog_sha = kzalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
		if (!map->excl_prog_sha) {
			err = -ENOMEM;
			goto free_map;
		}

		if (copy_from_bpfptr(map->excl_prog_sha, uprog_hash, SHA256_DIGEST_SIZE)) {
			err = -EFAULT;
			goto free_map;
		}
	} else if (attr->excl_prog_hash_size) {
		return -EINVAL;
	}

	err = security_bpf_map_create(map, attr, token, uattr.is_kernel);
	if (err)
		goto free_map_sec;

@@ -6008,7 +6031,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size)

	switch (cmd) {
	case BPF_MAP_CREATE:
		err = map_create(&attr, uattr.is_kernel);
		err = map_create(&attr, uattr);
		break;
	case BPF_MAP_LOOKUP_ELEM:
		err = map_lookup_elem(&attr);
+6 −0
Original line number Diff line number Diff line
@@ -20407,6 +20407,12 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
{
	enum bpf_prog_type prog_type = resolve_prog_type(prog);
	if (map->excl_prog_sha &&
	    memcmp(map->excl_prog_sha, prog->digest, SHA256_DIGEST_SIZE)) {
		verbose(env, "program's hash doesn't match map's excl_prog_hash\n");
		return -EACCES;
	}
	if (btf_record_has_field(map->record, BPF_LIST_HEAD) ||
	    btf_record_has_field(map->record, BPF_RB_ROOT)) {
		if (is_tracing_prog_type(prog_type)) {
+6 −0
Original line number Diff line number Diff line
@@ -1522,6 +1522,12 @@ union bpf_attr {
		 * If provided, map_flags should have BPF_F_TOKEN_FD flag set.
		 */
		__s32	map_token_fd;

		/* Hash of the program that has exclusive access to the map.
		 */
		__aligned_u64 excl_prog_hash;
		/* Size of the passed excl_prog_hash. */
		__u32 excl_prog_hash_size;
	};

	struct { /* anonymous struct used by BPF_MAP_*_ELEM and BPF_MAP_FREEZE commands */