From: Hou Tao <houtao1@xxxxxxxxxx> Introduce an internal map flag BPF_F_DYNPTR_IN_KEY to support dynptr in map key. Add the corresponding helper bpf_map_has_dynptr_key() to check whether the support of dynptr-key is enabled. The reason for an internal map flag is twofolds: 1) user doesn't need to set the map flag explicitly map_create() will use the presence of bpf_dynptr in map key as an indicator of enabling dynptr key. 2) avoid adding new arguments for ->map_alloc_check() and ->map_alloc() map_create() needs to pass the supported status of dynptr key to ->map_alloc_check (e.g., check the maximum length of dynptr data size) and ->map_alloc (e.g., check whether dynptr key fits current map type). Adding new arguments for these callbacks to achieve that will introduce too much churns. Therefore, the patch uses the topmost bit of map_flags as the internal map flag. map_create() checks whether the internal flag is set in the beginning and bpf_map_get_info_by_fd() clears the internal flag before returns the map flags to userspace. Signed-off-by: Hou Tao <houtao1@xxxxxxxxxx> --- include/linux/bpf.h | 17 +++++++++++++++++ kernel/bpf/syscall.c | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index ed58d5dd6b34b..ee02a5d313c56 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -258,6 +258,14 @@ struct bpf_list_node_kern { void *owner; } __attribute__((aligned(8))); +/* Internal map flags */ +enum { + /* map key supports bpf_dynptr */ + BPF_INT_F_DYNPTR_IN_KEY = (1U << 31), +}; + +#define BPF_INT_F_MASK (1U << 31) + struct bpf_map { const struct bpf_map_ops *ops; struct bpf_map *inner_map_meta; @@ -269,6 +277,10 @@ struct bpf_map { u32 value_size; u32 max_entries; u64 map_extra; /* any per-map-type extra fields */ + /* The topmost bit of map_flags is used as an internal map flag + * (aka BPF_INT_F_DYNPTR_IN_KEY) and it can't be set through bpf + * syscall. + */ u32 map_flags; u32 id; /* BTF record for special fields in map value. bpf_dynptr is disallowed @@ -317,6 +329,11 @@ struct bpf_map { s64 __percpu *elem_count; }; +static inline bool bpf_map_has_dynptr_key(const struct bpf_map *map) +{ + return map->map_flags & BPF_INT_F_DYNPTR_IN_KEY; +} + static inline const char *btf_field_type_name(enum btf_field_type type) { switch (type) { diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index d57bfb30463fa..07c67ad1a6a07 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -1378,6 +1378,8 @@ static int map_create(union bpf_attr *attr) if (err) return -EINVAL; + if (attr->map_flags & BPF_INT_F_MASK) + return -EINVAL; /* check BPF_F_TOKEN_FD flag, remember if it's set, and then clear it * to avoid per-map type checks tripping on unknown flag */ @@ -5057,7 +5059,7 @@ static int bpf_map_get_info_by_fd(struct file *file, info.key_size = map->key_size; info.value_size = map->value_size; info.max_entries = map->max_entries; - info.map_flags = map->map_flags; + info.map_flags = map->map_flags & ~BPF_INT_F_MASK; info.map_extra = map->map_extra; memcpy(info.name, map->name, sizeof(map->name)); -- 2.29.2