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: KP Singh <kpsingh@kernel.org> Link: https://lore.kernel.org/r/20250914215141.15144-3-kpsingh@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>pull/1354/merge
parent
603b441623
commit
baefdbdf68
|
|
@ -329,6 +329,7 @@ struct bpf_map {
|
||||||
atomic64_t sleepable_refcnt;
|
atomic64_t sleepable_refcnt;
|
||||||
s64 __percpu *elem_count;
|
s64 __percpu *elem_count;
|
||||||
u64 cookie; /* write-once */
|
u64 cookie; /* write-once */
|
||||||
|
char *excl_prog_sha;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline const char *btf_field_type_name(enum btf_field_type type)
|
static inline const char *btf_field_type_name(enum btf_field_type type)
|
||||||
|
|
|
||||||
|
|
@ -1522,6 +1522,12 @@ union bpf_attr {
|
||||||
* If provided, map_flags should have BPF_F_TOKEN_FD flag set.
|
* If provided, map_flags should have BPF_F_TOKEN_FD flag set.
|
||||||
*/
|
*/
|
||||||
__s32 map_token_fd;
|
__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 */
|
struct { /* anonymous struct used by BPF_MAP_*_ELEM and BPF_MAP_FREEZE commands */
|
||||||
|
|
|
||||||
|
|
@ -860,6 +860,7 @@ static void bpf_map_free(struct bpf_map *map)
|
||||||
* the free of values or special fields allocated from bpf memory
|
* the free of values or special fields allocated from bpf memory
|
||||||
* allocator.
|
* allocator.
|
||||||
*/
|
*/
|
||||||
|
kfree(map->excl_prog_sha);
|
||||||
migrate_disable();
|
migrate_disable();
|
||||||
map->ops->map_free(map);
|
map->ops->map_free(map);
|
||||||
migrate_enable();
|
migrate_enable();
|
||||||
|
|
@ -1338,9 +1339,9 @@ static bool bpf_net_capable(void)
|
||||||
return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
|
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 */
|
/* 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;
|
const struct bpf_map_ops *ops;
|
||||||
struct bpf_token *token = NULL;
|
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;
|
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)
|
if (err)
|
||||||
goto free_map_sec;
|
goto free_map_sec;
|
||||||
|
|
||||||
|
|
@ -6008,7 +6031,7 @@ static int __sys_bpf(enum bpf_cmd cmd, bpfptr_t uattr, unsigned int size)
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case BPF_MAP_CREATE:
|
case BPF_MAP_CREATE:
|
||||||
err = map_create(&attr, uattr.is_kernel);
|
err = map_create(&attr, uattr);
|
||||||
break;
|
break;
|
||||||
case BPF_MAP_LOOKUP_ELEM:
|
case BPF_MAP_LOOKUP_ELEM:
|
||||||
err = map_lookup_elem(&attr);
|
err = map_lookup_elem(&attr);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
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) ||
|
if (btf_record_has_field(map->record, BPF_LIST_HEAD) ||
|
||||||
btf_record_has_field(map->record, BPF_RB_ROOT)) {
|
btf_record_has_field(map->record, BPF_RB_ROOT)) {
|
||||||
if (is_tracing_prog_type(prog_type)) {
|
if (is_tracing_prog_type(prog_type)) {
|
||||||
|
|
|
||||||
|
|
@ -1522,6 +1522,12 @@ union bpf_attr {
|
||||||
* If provided, map_flags should have BPF_F_TOKEN_FD flag set.
|
* If provided, map_flags should have BPF_F_TOKEN_FD flag set.
|
||||||
*/
|
*/
|
||||||
__s32 map_token_fd;
|
__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 */
|
struct { /* anonymous struct used by BPF_MAP_*_ELEM and BPF_MAP_FREEZE commands */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue