mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Revert BPF token-related functionality
This patch includes the following revert (one conflicting BPF FS patch and three token patch sets, represented by merge commits): - revert0f5d5454c7"Merge branch 'bpf-fs-mount-options-parsing-follow-ups'"; - revert750e785796"bpf: Support uid and gid when mounting bpffs"; - revert733763285a"Merge branch 'bpf-token-support-in-libbpf-s-bpf-object'"; - revertc35919dcce"Merge branch 'bpf-token-and-bpf-fs-based-delegation'". Link: https://lore.kernel.org/bpf/CAHk-=wg7JuFYwGy=GOMbRCtOL+jwSQsdUaBsRWkDVYbxipbM5A@mail.gmail.com Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
This commit is contained in:
@@ -110,7 +110,7 @@ lirc_mode2_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_get_prandom_u32:
|
case BPF_FUNC_get_prandom_u32:
|
||||||
return &bpf_get_prandom_u32_proto;
|
return &bpf_get_prandom_u32_proto;
|
||||||
case BPF_FUNC_trace_printk:
|
case BPF_FUNC_trace_printk:
|
||||||
if (bpf_token_capable(prog->aux->token, CAP_PERFMON))
|
if (perfmon_capable())
|
||||||
return bpf_get_trace_printk_proto();
|
return bpf_get_trace_printk_proto();
|
||||||
fallthrough;
|
fallthrough;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+10
-75
@@ -52,10 +52,6 @@ struct module;
|
|||||||
struct bpf_func_state;
|
struct bpf_func_state;
|
||||||
struct ftrace_ops;
|
struct ftrace_ops;
|
||||||
struct cgroup;
|
struct cgroup;
|
||||||
struct bpf_token;
|
|
||||||
struct user_namespace;
|
|
||||||
struct super_block;
|
|
||||||
struct inode;
|
|
||||||
|
|
||||||
extern struct idr btf_idr;
|
extern struct idr btf_idr;
|
||||||
extern spinlock_t btf_idr_lock;
|
extern spinlock_t btf_idr_lock;
|
||||||
@@ -1488,7 +1484,6 @@ struct bpf_prog_aux {
|
|||||||
#ifdef CONFIG_SECURITY
|
#ifdef CONFIG_SECURITY
|
||||||
void *security;
|
void *security;
|
||||||
#endif
|
#endif
|
||||||
struct bpf_token *token;
|
|
||||||
struct bpf_prog_offload *offload;
|
struct bpf_prog_offload *offload;
|
||||||
struct btf *btf;
|
struct btf *btf;
|
||||||
struct bpf_func_info *func_info;
|
struct bpf_func_info *func_info;
|
||||||
@@ -1613,31 +1608,6 @@ struct bpf_link_primer {
|
|||||||
u32 id;
|
u32 id;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bpf_mount_opts {
|
|
||||||
kuid_t uid;
|
|
||||||
kgid_t gid;
|
|
||||||
umode_t mode;
|
|
||||||
|
|
||||||
/* BPF token-related delegation options */
|
|
||||||
u64 delegate_cmds;
|
|
||||||
u64 delegate_maps;
|
|
||||||
u64 delegate_progs;
|
|
||||||
u64 delegate_attachs;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bpf_token {
|
|
||||||
struct work_struct work;
|
|
||||||
atomic64_t refcnt;
|
|
||||||
struct user_namespace *userns;
|
|
||||||
u64 allowed_cmds;
|
|
||||||
u64 allowed_maps;
|
|
||||||
u64 allowed_progs;
|
|
||||||
u64 allowed_attachs;
|
|
||||||
#ifdef CONFIG_SECURITY
|
|
||||||
void *security;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct bpf_struct_ops_value;
|
struct bpf_struct_ops_value;
|
||||||
struct btf_member;
|
struct btf_member;
|
||||||
|
|
||||||
@@ -2097,7 +2067,6 @@ static inline void bpf_enable_instrumentation(void)
|
|||||||
migrate_enable();
|
migrate_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern const struct super_operations bpf_super_ops;
|
|
||||||
extern const struct file_operations bpf_map_fops;
|
extern const struct file_operations bpf_map_fops;
|
||||||
extern const struct file_operations bpf_prog_fops;
|
extern const struct file_operations bpf_prog_fops;
|
||||||
extern const struct file_operations bpf_iter_fops;
|
extern const struct file_operations bpf_iter_fops;
|
||||||
@@ -2232,26 +2201,24 @@ static inline void bpf_map_dec_elem_count(struct bpf_map *map)
|
|||||||
|
|
||||||
extern int sysctl_unprivileged_bpf_disabled;
|
extern int sysctl_unprivileged_bpf_disabled;
|
||||||
|
|
||||||
bool bpf_token_capable(const struct bpf_token *token, int cap);
|
static inline bool bpf_allow_ptr_leaks(void)
|
||||||
|
|
||||||
static inline bool bpf_allow_ptr_leaks(const struct bpf_token *token)
|
|
||||||
{
|
{
|
||||||
return bpf_token_capable(token, CAP_PERFMON);
|
return perfmon_capable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool bpf_allow_uninit_stack(const struct bpf_token *token)
|
static inline bool bpf_allow_uninit_stack(void)
|
||||||
{
|
{
|
||||||
return bpf_token_capable(token, CAP_PERFMON);
|
return perfmon_capable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool bpf_bypass_spec_v1(const struct bpf_token *token)
|
static inline bool bpf_bypass_spec_v1(void)
|
||||||
{
|
{
|
||||||
return cpu_mitigations_off() || bpf_token_capable(token, CAP_PERFMON);
|
return cpu_mitigations_off() || perfmon_capable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool bpf_bypass_spec_v4(const struct bpf_token *token)
|
static inline bool bpf_bypass_spec_v4(void)
|
||||||
{
|
{
|
||||||
return cpu_mitigations_off() || bpf_token_capable(token, CAP_PERFMON);
|
return cpu_mitigations_off() || perfmon_capable();
|
||||||
}
|
}
|
||||||
|
|
||||||
int bpf_map_new_fd(struct bpf_map *map, int flags);
|
int bpf_map_new_fd(struct bpf_map *map, int flags);
|
||||||
@@ -2268,21 +2235,8 @@ int bpf_link_new_fd(struct bpf_link *link);
|
|||||||
struct bpf_link *bpf_link_get_from_fd(u32 ufd);
|
struct bpf_link *bpf_link_get_from_fd(u32 ufd);
|
||||||
struct bpf_link *bpf_link_get_curr_or_next(u32 *id);
|
struct bpf_link *bpf_link_get_curr_or_next(u32 *id);
|
||||||
|
|
||||||
void bpf_token_inc(struct bpf_token *token);
|
|
||||||
void bpf_token_put(struct bpf_token *token);
|
|
||||||
int bpf_token_create(union bpf_attr *attr);
|
|
||||||
struct bpf_token *bpf_token_get_from_fd(u32 ufd);
|
|
||||||
|
|
||||||
bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd);
|
|
||||||
bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type);
|
|
||||||
bool bpf_token_allow_prog_type(const struct bpf_token *token,
|
|
||||||
enum bpf_prog_type prog_type,
|
|
||||||
enum bpf_attach_type attach_type);
|
|
||||||
|
|
||||||
int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname);
|
int bpf_obj_pin_user(u32 ufd, int path_fd, const char __user *pathname);
|
||||||
int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags);
|
int bpf_obj_get_user(int path_fd, const char __user *pathname, int flags);
|
||||||
struct inode *bpf_get_inode(struct super_block *sb, const struct inode *dir,
|
|
||||||
umode_t mode);
|
|
||||||
|
|
||||||
#define BPF_ITER_FUNC_PREFIX "bpf_iter_"
|
#define BPF_ITER_FUNC_PREFIX "bpf_iter_"
|
||||||
#define DEFINE_BPF_ITER_FUNC(target, args...) \
|
#define DEFINE_BPF_ITER_FUNC(target, args...) \
|
||||||
@@ -2526,8 +2480,7 @@ const char *btf_find_decl_tag_value(const struct btf *btf, const struct btf_type
|
|||||||
struct bpf_prog *bpf_prog_by_id(u32 id);
|
struct bpf_prog *bpf_prog_by_id(u32 id);
|
||||||
struct bpf_link *bpf_link_by_id(u32 id);
|
struct bpf_link *bpf_link_by_id(u32 id);
|
||||||
|
|
||||||
const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id,
|
const struct bpf_func_proto *bpf_base_func_proto(enum bpf_func_id func_id);
|
||||||
const struct bpf_prog *prog);
|
|
||||||
void bpf_task_storage_free(struct task_struct *task);
|
void bpf_task_storage_free(struct task_struct *task);
|
||||||
void bpf_cgrp_storage_free(struct cgroup *cgroup);
|
void bpf_cgrp_storage_free(struct cgroup *cgroup);
|
||||||
bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog);
|
bool bpf_prog_has_kfunc_call(const struct bpf_prog *prog);
|
||||||
@@ -2646,24 +2599,6 @@ static inline int bpf_obj_get_user(const char __user *pathname, int flags)
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool bpf_token_capable(const struct bpf_token *token, int cap)
|
|
||||||
{
|
|
||||||
return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void bpf_token_inc(struct bpf_token *token)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void bpf_token_put(struct bpf_token *token)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct bpf_token *bpf_token_get_from_fd(u32 ufd)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-EOPNOTSUPP);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __dev_flush(void)
|
static inline void __dev_flush(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -2787,7 +2722,7 @@ static inline int btf_struct_access(struct bpf_verifier_log *log,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline const struct bpf_func_proto *
|
static inline const struct bpf_func_proto *
|
||||||
bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
bpf_base_func_proto(enum bpf_func_id func_id)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1139,7 +1139,7 @@ static inline bool bpf_jit_blinding_enabled(struct bpf_prog *prog)
|
|||||||
return false;
|
return false;
|
||||||
if (!bpf_jit_harden)
|
if (!bpf_jit_harden)
|
||||||
return false;
|
return false;
|
||||||
if (bpf_jit_harden == 1 && bpf_token_capable(prog->aux->token, CAP_BPF))
|
if (bpf_jit_harden == 1 && bpf_capable())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -398,17 +398,10 @@ LSM_HOOK(void, LSM_RET_VOID, audit_rule_free, void *lsmrule)
|
|||||||
LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size)
|
LSM_HOOK(int, 0, bpf, int cmd, union bpf_attr *attr, unsigned int size)
|
||||||
LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode)
|
LSM_HOOK(int, 0, bpf_map, struct bpf_map *map, fmode_t fmode)
|
||||||
LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog)
|
LSM_HOOK(int, 0, bpf_prog, struct bpf_prog *prog)
|
||||||
LSM_HOOK(int, 0, bpf_map_create, struct bpf_map *map, union bpf_attr *attr,
|
LSM_HOOK(int, 0, bpf_map_alloc_security, struct bpf_map *map)
|
||||||
struct bpf_token *token)
|
LSM_HOOK(void, LSM_RET_VOID, bpf_map_free_security, struct bpf_map *map)
|
||||||
LSM_HOOK(void, LSM_RET_VOID, bpf_map_free, struct bpf_map *map)
|
LSM_HOOK(int, 0, bpf_prog_alloc_security, struct bpf_prog_aux *aux)
|
||||||
LSM_HOOK(int, 0, bpf_prog_load, struct bpf_prog *prog, union bpf_attr *attr,
|
LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free_security, struct bpf_prog_aux *aux)
|
||||||
struct bpf_token *token)
|
|
||||||
LSM_HOOK(void, LSM_RET_VOID, bpf_prog_free, struct bpf_prog *prog)
|
|
||||||
LSM_HOOK(int, 0, bpf_token_create, struct bpf_token *token, union bpf_attr *attr,
|
|
||||||
struct path *path)
|
|
||||||
LSM_HOOK(void, LSM_RET_VOID, bpf_token_free, struct bpf_token *token)
|
|
||||||
LSM_HOOK(int, 0, bpf_token_cmd, const struct bpf_token *token, enum bpf_cmd cmd)
|
|
||||||
LSM_HOOK(int, 0, bpf_token_capable, const struct bpf_token *token, int cap)
|
|
||||||
#endif /* CONFIG_BPF_SYSCALL */
|
#endif /* CONFIG_BPF_SYSCALL */
|
||||||
|
|
||||||
LSM_HOOK(int, 0, locked_down, enum lockdown_reason what)
|
LSM_HOOK(int, 0, locked_down, enum lockdown_reason what)
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/sockptr.h>
|
#include <linux/sockptr.h>
|
||||||
#include <linux/bpf.h>
|
|
||||||
|
|
||||||
struct linux_binprm;
|
struct linux_binprm;
|
||||||
struct cred;
|
struct cred;
|
||||||
@@ -2021,22 +2020,15 @@ static inline void securityfs_remove(struct dentry *dentry)
|
|||||||
union bpf_attr;
|
union bpf_attr;
|
||||||
struct bpf_map;
|
struct bpf_map;
|
||||||
struct bpf_prog;
|
struct bpf_prog;
|
||||||
struct bpf_token;
|
struct bpf_prog_aux;
|
||||||
#ifdef CONFIG_SECURITY
|
#ifdef CONFIG_SECURITY
|
||||||
extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
|
extern int security_bpf(int cmd, union bpf_attr *attr, unsigned int size);
|
||||||
extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
|
extern int security_bpf_map(struct bpf_map *map, fmode_t fmode);
|
||||||
extern int security_bpf_prog(struct bpf_prog *prog);
|
extern int security_bpf_prog(struct bpf_prog *prog);
|
||||||
extern int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
|
extern int security_bpf_map_alloc(struct bpf_map *map);
|
||||||
struct bpf_token *token);
|
|
||||||
extern void security_bpf_map_free(struct bpf_map *map);
|
extern void security_bpf_map_free(struct bpf_map *map);
|
||||||
extern int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
|
extern int security_bpf_prog_alloc(struct bpf_prog_aux *aux);
|
||||||
struct bpf_token *token);
|
extern void security_bpf_prog_free(struct bpf_prog_aux *aux);
|
||||||
extern void security_bpf_prog_free(struct bpf_prog *prog);
|
|
||||||
extern int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
|
|
||||||
struct path *path);
|
|
||||||
extern void security_bpf_token_free(struct bpf_token *token);
|
|
||||||
extern int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd);
|
|
||||||
extern int security_bpf_token_capable(const struct bpf_token *token, int cap);
|
|
||||||
#else
|
#else
|
||||||
static inline int security_bpf(int cmd, union bpf_attr *attr,
|
static inline int security_bpf(int cmd, union bpf_attr *attr,
|
||||||
unsigned int size)
|
unsigned int size)
|
||||||
@@ -2054,8 +2046,7 @@ static inline int security_bpf_prog(struct bpf_prog *prog)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int security_bpf_map_create(struct bpf_map *map, union bpf_attr *attr,
|
static inline int security_bpf_map_alloc(struct bpf_map *map)
|
||||||
struct bpf_token *token)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2063,33 +2054,13 @@ static inline int security_bpf_map_create(struct bpf_map *map, union bpf_attr *a
|
|||||||
static inline void security_bpf_map_free(struct bpf_map *map)
|
static inline void security_bpf_map_free(struct bpf_map *map)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
static inline int security_bpf_prog_load(struct bpf_prog *prog, union bpf_attr *attr,
|
static inline int security_bpf_prog_alloc(struct bpf_prog_aux *aux)
|
||||||
struct bpf_token *token)
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void security_bpf_prog_free(struct bpf_prog *prog)
|
static inline void security_bpf_prog_free(struct bpf_prog_aux *aux)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
static inline int security_bpf_token_create(struct bpf_token *token, union bpf_attr *attr,
|
|
||||||
struct path *path)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void security_bpf_token_free(struct bpf_token *token)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
static inline int security_bpf_token_cmd(const struct bpf_token *token, enum bpf_cmd cmd)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int security_bpf_token_capable(const struct bpf_token *token, int cap)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_SECURITY */
|
#endif /* CONFIG_SECURITY */
|
||||||
#endif /* CONFIG_BPF_SYSCALL */
|
#endif /* CONFIG_BPF_SYSCALL */
|
||||||
|
|
||||||
|
|||||||
@@ -847,36 +847,6 @@ union bpf_iter_link_info {
|
|||||||
* Returns zero on success. On error, -1 is returned and *errno*
|
* Returns zero on success. On error, -1 is returned and *errno*
|
||||||
* is set appropriately.
|
* is set appropriately.
|
||||||
*
|
*
|
||||||
* BPF_TOKEN_CREATE
|
|
||||||
* Description
|
|
||||||
* Create BPF token with embedded information about what
|
|
||||||
* BPF-related functionality it allows:
|
|
||||||
* - a set of allowed bpf() syscall commands;
|
|
||||||
* - a set of allowed BPF map types to be created with
|
|
||||||
* BPF_MAP_CREATE command, if BPF_MAP_CREATE itself is allowed;
|
|
||||||
* - a set of allowed BPF program types and BPF program attach
|
|
||||||
* types to be loaded with BPF_PROG_LOAD command, if
|
|
||||||
* BPF_PROG_LOAD itself is allowed.
|
|
||||||
*
|
|
||||||
* BPF token is created (derived) from an instance of BPF FS,
|
|
||||||
* assuming it has necessary delegation mount options specified.
|
|
||||||
* This BPF token can be passed as an extra parameter to various
|
|
||||||
* bpf() syscall commands to grant BPF subsystem functionality to
|
|
||||||
* unprivileged processes.
|
|
||||||
*
|
|
||||||
* When created, BPF token is "associated" with the owning
|
|
||||||
* user namespace of BPF FS instance (super block) that it was
|
|
||||||
* derived from, and subsequent BPF operations performed with
|
|
||||||
* BPF token would be performing capabilities checks (i.e.,
|
|
||||||
* CAP_BPF, CAP_PERFMON, CAP_NET_ADMIN, CAP_SYS_ADMIN) within
|
|
||||||
* that user namespace. Without BPF token, such capabilities
|
|
||||||
* have to be granted in init user namespace, making bpf()
|
|
||||||
* syscall incompatible with user namespace, for the most part.
|
|
||||||
*
|
|
||||||
* Return
|
|
||||||
* A new file descriptor (a nonnegative integer), or -1 if an
|
|
||||||
* error occurred (in which case, *errno* is set appropriately).
|
|
||||||
*
|
|
||||||
* NOTES
|
* NOTES
|
||||||
* eBPF objects (maps and programs) can be shared between processes.
|
* eBPF objects (maps and programs) can be shared between processes.
|
||||||
*
|
*
|
||||||
@@ -931,8 +901,6 @@ enum bpf_cmd {
|
|||||||
BPF_ITER_CREATE,
|
BPF_ITER_CREATE,
|
||||||
BPF_LINK_DETACH,
|
BPF_LINK_DETACH,
|
||||||
BPF_PROG_BIND_MAP,
|
BPF_PROG_BIND_MAP,
|
||||||
BPF_TOKEN_CREATE,
|
|
||||||
__MAX_BPF_CMD,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_map_type {
|
enum bpf_map_type {
|
||||||
@@ -983,7 +951,6 @@ enum bpf_map_type {
|
|||||||
BPF_MAP_TYPE_BLOOM_FILTER,
|
BPF_MAP_TYPE_BLOOM_FILTER,
|
||||||
BPF_MAP_TYPE_USER_RINGBUF,
|
BPF_MAP_TYPE_USER_RINGBUF,
|
||||||
BPF_MAP_TYPE_CGRP_STORAGE,
|
BPF_MAP_TYPE_CGRP_STORAGE,
|
||||||
__MAX_BPF_MAP_TYPE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Note that tracing related programs such as
|
/* Note that tracing related programs such as
|
||||||
@@ -1028,7 +995,6 @@ enum bpf_prog_type {
|
|||||||
BPF_PROG_TYPE_SK_LOOKUP,
|
BPF_PROG_TYPE_SK_LOOKUP,
|
||||||
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
|
||||||
BPF_PROG_TYPE_NETFILTER,
|
BPF_PROG_TYPE_NETFILTER,
|
||||||
__MAX_BPF_PROG_TYPE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bpf_attach_type {
|
enum bpf_attach_type {
|
||||||
@@ -1437,7 +1403,6 @@ union bpf_attr {
|
|||||||
* to using 5 hash functions).
|
* to using 5 hash functions).
|
||||||
*/
|
*/
|
||||||
__u64 map_extra;
|
__u64 map_extra;
|
||||||
__u32 map_token_fd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
|
||||||
@@ -1507,7 +1472,6 @@ union bpf_attr {
|
|||||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||||
*/
|
*/
|
||||||
__u32 log_true_size;
|
__u32 log_true_size;
|
||||||
__u32 prog_token_fd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
struct { /* anonymous struct used by BPF_OBJ_* commands */
|
||||||
@@ -1620,7 +1584,6 @@ union bpf_attr {
|
|||||||
* truncated), or smaller (if log buffer wasn't filled completely).
|
* truncated), or smaller (if log buffer wasn't filled completely).
|
||||||
*/
|
*/
|
||||||
__u32 btf_log_true_size;
|
__u32 btf_log_true_size;
|
||||||
__u32 btf_token_fd;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@@ -1751,11 +1714,6 @@ union bpf_attr {
|
|||||||
__u32 flags; /* extra flags */
|
__u32 flags; /* extra flags */
|
||||||
} prog_bind_map;
|
} prog_bind_map;
|
||||||
|
|
||||||
struct { /* struct used by BPF_TOKEN_CREATE command */
|
|
||||||
__u32 flags;
|
|
||||||
__u32 bpffs_fd;
|
|
||||||
} token_create;
|
|
||||||
|
|
||||||
} __attribute__((aligned(8)));
|
} __attribute__((aligned(8)));
|
||||||
|
|
||||||
/* The description below is an attempt at providing documentation to eBPF
|
/* The description below is an attempt at providing documentation to eBPF
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@ cflags-nogcse-$(CONFIG_X86)$(CONFIG_CC_IS_GCC) := -fno-gcse
|
|||||||
endif
|
endif
|
||||||
CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy)
|
CFLAGS_core.o += $(call cc-disable-warning, override-init) $(cflags-nogcse-yy)
|
||||||
|
|
||||||
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o
|
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o
|
||||||
obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o
|
obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o
|
||||||
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o
|
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o
|
||||||
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
|
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
|
|||||||
bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
|
bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
|
||||||
int numa_node = bpf_map_attr_numa_node(attr);
|
int numa_node = bpf_map_attr_numa_node(attr);
|
||||||
u32 elem_size, index_mask, max_entries;
|
u32 elem_size, index_mask, max_entries;
|
||||||
bool bypass_spec_v1 = bpf_bypass_spec_v1(NULL);
|
bool bypass_spec_v1 = bpf_bypass_spec_v1();
|
||||||
u64 array_size, mask64;
|
u64 array_size, mask64;
|
||||||
struct bpf_array *array;
|
struct bpf_array *array;
|
||||||
|
|
||||||
|
|||||||
+5
-10
@@ -260,15 +260,9 @@ bpf_lsm_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
BTF_SET_START(sleepable_lsm_hooks)
|
BTF_SET_START(sleepable_lsm_hooks)
|
||||||
BTF_ID(func, bpf_lsm_bpf)
|
BTF_ID(func, bpf_lsm_bpf)
|
||||||
BTF_ID(func, bpf_lsm_bpf_map)
|
BTF_ID(func, bpf_lsm_bpf_map)
|
||||||
BTF_ID(func, bpf_lsm_bpf_map_create)
|
BTF_ID(func, bpf_lsm_bpf_map_alloc_security)
|
||||||
BTF_ID(func, bpf_lsm_bpf_map_free)
|
BTF_ID(func, bpf_lsm_bpf_map_free_security)
|
||||||
BTF_ID(func, bpf_lsm_bpf_prog)
|
BTF_ID(func, bpf_lsm_bpf_prog)
|
||||||
BTF_ID(func, bpf_lsm_bpf_prog_load)
|
|
||||||
BTF_ID(func, bpf_lsm_bpf_prog_free)
|
|
||||||
BTF_ID(func, bpf_lsm_bpf_token_create)
|
|
||||||
BTF_ID(func, bpf_lsm_bpf_token_free)
|
|
||||||
BTF_ID(func, bpf_lsm_bpf_token_cmd)
|
|
||||||
BTF_ID(func, bpf_lsm_bpf_token_capable)
|
|
||||||
BTF_ID(func, bpf_lsm_bprm_check_security)
|
BTF_ID(func, bpf_lsm_bprm_check_security)
|
||||||
BTF_ID(func, bpf_lsm_bprm_committed_creds)
|
BTF_ID(func, bpf_lsm_bprm_committed_creds)
|
||||||
BTF_ID(func, bpf_lsm_bprm_committing_creds)
|
BTF_ID(func, bpf_lsm_bprm_committing_creds)
|
||||||
@@ -363,8 +357,9 @@ BTF_ID(func, bpf_lsm_userns_create)
|
|||||||
BTF_SET_END(sleepable_lsm_hooks)
|
BTF_SET_END(sleepable_lsm_hooks)
|
||||||
|
|
||||||
BTF_SET_START(untrusted_lsm_hooks)
|
BTF_SET_START(untrusted_lsm_hooks)
|
||||||
BTF_ID(func, bpf_lsm_bpf_map_free)
|
BTF_ID(func, bpf_lsm_bpf_map_free_security)
|
||||||
BTF_ID(func, bpf_lsm_bpf_prog_free)
|
BTF_ID(func, bpf_lsm_bpf_prog_alloc_security)
|
||||||
|
BTF_ID(func, bpf_lsm_bpf_prog_free_security)
|
||||||
BTF_ID(func, bpf_lsm_file_alloc_security)
|
BTF_ID(func, bpf_lsm_file_alloc_security)
|
||||||
BTF_ID(func, bpf_lsm_file_free_security)
|
BTF_ID(func, bpf_lsm_file_free_security)
|
||||||
#ifdef CONFIG_SECURITY_NETWORK
|
#ifdef CONFIG_SECURITY_NETWORK
|
||||||
|
|||||||
+3
-3
@@ -1630,7 +1630,7 @@ cgroup_dev_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_perf_event_output:
|
case BPF_FUNC_perf_event_output:
|
||||||
return &bpf_event_output_data_proto;
|
return &bpf_event_output_data_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2191,7 +2191,7 @@ sysctl_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_perf_event_output:
|
case BPF_FUNC_perf_event_output:
|
||||||
return &bpf_event_output_data_proto;
|
return &bpf_event_output_data_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2348,7 +2348,7 @@ cg_sockopt_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_perf_event_output:
|
case BPF_FUNC_perf_event_output:
|
||||||
return &bpf_event_output_data_proto;
|
return &bpf_event_output_data_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -682,7 +682,7 @@ static bool bpf_prog_kallsyms_candidate(const struct bpf_prog *fp)
|
|||||||
void bpf_prog_kallsyms_add(struct bpf_prog *fp)
|
void bpf_prog_kallsyms_add(struct bpf_prog *fp)
|
||||||
{
|
{
|
||||||
if (!bpf_prog_kallsyms_candidate(fp) ||
|
if (!bpf_prog_kallsyms_candidate(fp) ||
|
||||||
!bpf_token_capable(fp->aux->token, CAP_BPF))
|
!bpf_capable())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bpf_prog_ksym_set_addr(fp);
|
bpf_prog_ksym_set_addr(fp);
|
||||||
@@ -2779,7 +2779,6 @@ void bpf_prog_free(struct bpf_prog *fp)
|
|||||||
|
|
||||||
if (aux->dst_prog)
|
if (aux->dst_prog)
|
||||||
bpf_prog_put(aux->dst_prog);
|
bpf_prog_put(aux->dst_prog);
|
||||||
bpf_token_put(aux->token);
|
|
||||||
INIT_WORK(&aux->work, bpf_prog_free_deferred);
|
INIT_WORK(&aux->work, bpf_prog_free_deferred);
|
||||||
schedule_work(&aux->work);
|
schedule_work(&aux->work);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1679,7 +1679,7 @@ const struct bpf_func_proto bpf_probe_read_kernel_str_proto __weak;
|
|||||||
const struct bpf_func_proto bpf_task_pt_regs_proto __weak;
|
const struct bpf_func_proto bpf_task_pt_regs_proto __weak;
|
||||||
|
|
||||||
const struct bpf_func_proto *
|
const struct bpf_func_proto *
|
||||||
bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
bpf_base_func_proto(enum bpf_func_id func_id)
|
||||||
{
|
{
|
||||||
switch (func_id) {
|
switch (func_id) {
|
||||||
case BPF_FUNC_map_lookup_elem:
|
case BPF_FUNC_map_lookup_elem:
|
||||||
@@ -1730,7 +1730,7 @@ bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bpf_token_capable(prog->aux->token, CAP_BPF))
|
if (!bpf_capable())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
switch (func_id) {
|
switch (func_id) {
|
||||||
@@ -1788,7 +1788,7 @@ bpf_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bpf_token_capable(prog->aux->token, CAP_PERFMON))
|
if (!perfmon_capable())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
switch (func_id) {
|
switch (func_id) {
|
||||||
|
|||||||
+15
-309
@@ -20,7 +20,6 @@
|
|||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include <linux/bpf_trace.h>
|
#include <linux/bpf_trace.h>
|
||||||
#include <linux/kstrtox.h>
|
|
||||||
#include "preload/bpf_preload.h"
|
#include "preload/bpf_preload.h"
|
||||||
|
|
||||||
enum bpf_type {
|
enum bpf_type {
|
||||||
@@ -99,9 +98,9 @@ static const struct inode_operations bpf_prog_iops = { };
|
|||||||
static const struct inode_operations bpf_map_iops = { };
|
static const struct inode_operations bpf_map_iops = { };
|
||||||
static const struct inode_operations bpf_link_iops = { };
|
static const struct inode_operations bpf_link_iops = { };
|
||||||
|
|
||||||
struct inode *bpf_get_inode(struct super_block *sb,
|
static struct inode *bpf_get_inode(struct super_block *sb,
|
||||||
const struct inode *dir,
|
const struct inode *dir,
|
||||||
umode_t mode)
|
umode_t mode)
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
|
||||||
@@ -595,183 +594,15 @@ struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type typ
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bpf_prog_get_type_path);
|
EXPORT_SYMBOL(bpf_prog_get_type_path);
|
||||||
|
|
||||||
struct bpffs_btf_enums {
|
|
||||||
const struct btf *btf;
|
|
||||||
const struct btf_type *cmd_t;
|
|
||||||
const struct btf_type *map_t;
|
|
||||||
const struct btf_type *prog_t;
|
|
||||||
const struct btf_type *attach_t;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int find_bpffs_btf_enums(struct bpffs_btf_enums *info)
|
|
||||||
{
|
|
||||||
const struct btf *btf;
|
|
||||||
const struct btf_type *t;
|
|
||||||
const char *name;
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
memset(info, 0, sizeof(*info));
|
|
||||||
|
|
||||||
btf = bpf_get_btf_vmlinux();
|
|
||||||
if (IS_ERR(btf))
|
|
||||||
return PTR_ERR(btf);
|
|
||||||
if (!btf)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
info->btf = btf;
|
|
||||||
|
|
||||||
for (i = 1, n = btf_nr_types(btf); i < n; i++) {
|
|
||||||
t = btf_type_by_id(btf, i);
|
|
||||||
if (!btf_type_is_enum(t))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
name = btf_name_by_offset(btf, t->name_off);
|
|
||||||
if (!name)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strcmp(name, "bpf_cmd") == 0)
|
|
||||||
info->cmd_t = t;
|
|
||||||
else if (strcmp(name, "bpf_map_type") == 0)
|
|
||||||
info->map_t = t;
|
|
||||||
else if (strcmp(name, "bpf_prog_type") == 0)
|
|
||||||
info->prog_t = t;
|
|
||||||
else if (strcmp(name, "bpf_attach_type") == 0)
|
|
||||||
info->attach_t = t;
|
|
||||||
else
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (info->cmd_t && info->map_t && info->prog_t && info->attach_t)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ESRCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool find_btf_enum_const(const struct btf *btf, const struct btf_type *enum_t,
|
|
||||||
const char *prefix, const char *str, int *value)
|
|
||||||
{
|
|
||||||
const struct btf_enum *e;
|
|
||||||
const char *name;
|
|
||||||
int i, n, pfx_len = strlen(prefix);
|
|
||||||
|
|
||||||
*value = 0;
|
|
||||||
|
|
||||||
if (!btf || !enum_t)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (i = 0, n = btf_vlen(enum_t); i < n; i++) {
|
|
||||||
e = &btf_enum(enum_t)[i];
|
|
||||||
|
|
||||||
name = btf_name_by_offset(btf, e->name_off);
|
|
||||||
if (!name || strncasecmp(name, prefix, pfx_len) != 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* match symbolic name case insensitive and ignoring prefix */
|
|
||||||
if (strcasecmp(name + pfx_len, str) == 0) {
|
|
||||||
*value = e->val;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void seq_print_delegate_opts(struct seq_file *m,
|
|
||||||
const char *opt_name,
|
|
||||||
const struct btf *btf,
|
|
||||||
const struct btf_type *enum_t,
|
|
||||||
const char *prefix,
|
|
||||||
u64 delegate_msk, u64 any_msk)
|
|
||||||
{
|
|
||||||
const struct btf_enum *e;
|
|
||||||
bool first = true;
|
|
||||||
const char *name;
|
|
||||||
u64 msk;
|
|
||||||
int i, n, pfx_len = strlen(prefix);
|
|
||||||
|
|
||||||
delegate_msk &= any_msk; /* clear unknown bits */
|
|
||||||
|
|
||||||
if (delegate_msk == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
seq_printf(m, ",%s", opt_name);
|
|
||||||
if (delegate_msk == any_msk) {
|
|
||||||
seq_printf(m, "=any");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btf && enum_t) {
|
|
||||||
for (i = 0, n = btf_vlen(enum_t); i < n; i++) {
|
|
||||||
e = &btf_enum(enum_t)[i];
|
|
||||||
name = btf_name_by_offset(btf, e->name_off);
|
|
||||||
if (!name || strncasecmp(name, prefix, pfx_len) != 0)
|
|
||||||
continue;
|
|
||||||
msk = 1ULL << e->val;
|
|
||||||
if (delegate_msk & msk) {
|
|
||||||
/* emit lower-case name without prefix */
|
|
||||||
seq_printf(m, "%c", first ? '=' : ':');
|
|
||||||
name += pfx_len;
|
|
||||||
while (*name) {
|
|
||||||
seq_printf(m, "%c", tolower(*name));
|
|
||||||
name++;
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate_msk &= ~msk;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (delegate_msk)
|
|
||||||
seq_printf(m, "%c0x%llx", first ? '=' : ':', delegate_msk);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Display the mount options in /proc/mounts.
|
* Display the mount options in /proc/mounts.
|
||||||
*/
|
*/
|
||||||
static int bpf_show_options(struct seq_file *m, struct dentry *root)
|
static int bpf_show_options(struct seq_file *m, struct dentry *root)
|
||||||
{
|
{
|
||||||
struct bpf_mount_opts *opts = root->d_sb->s_fs_info;
|
umode_t mode = d_inode(root)->i_mode & S_IALLUGO & ~S_ISVTX;
|
||||||
struct inode *inode = d_inode(root);
|
|
||||||
umode_t mode = inode->i_mode & S_IALLUGO & ~S_ISVTX;
|
|
||||||
u64 mask;
|
|
||||||
|
|
||||||
if (!uid_eq(inode->i_uid, GLOBAL_ROOT_UID))
|
|
||||||
seq_printf(m, ",uid=%u",
|
|
||||||
from_kuid_munged(&init_user_ns, inode->i_uid));
|
|
||||||
if (!gid_eq(inode->i_gid, GLOBAL_ROOT_GID))
|
|
||||||
seq_printf(m, ",gid=%u",
|
|
||||||
from_kgid_munged(&init_user_ns, inode->i_gid));
|
|
||||||
if (mode != S_IRWXUGO)
|
if (mode != S_IRWXUGO)
|
||||||
seq_printf(m, ",mode=%o", mode);
|
seq_printf(m, ",mode=%o", mode);
|
||||||
|
|
||||||
if (opts->delegate_cmds || opts->delegate_maps ||
|
|
||||||
opts->delegate_progs || opts->delegate_attachs) {
|
|
||||||
struct bpffs_btf_enums info;
|
|
||||||
|
|
||||||
/* ignore errors, fallback to hex */
|
|
||||||
(void)find_bpffs_btf_enums(&info);
|
|
||||||
|
|
||||||
mask = (1ULL << __MAX_BPF_CMD) - 1;
|
|
||||||
seq_print_delegate_opts(m, "delegate_cmds",
|
|
||||||
info.btf, info.cmd_t, "BPF_",
|
|
||||||
opts->delegate_cmds, mask);
|
|
||||||
|
|
||||||
mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
|
|
||||||
seq_print_delegate_opts(m, "delegate_maps",
|
|
||||||
info.btf, info.map_t, "BPF_MAP_TYPE_",
|
|
||||||
opts->delegate_maps, mask);
|
|
||||||
|
|
||||||
mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
|
|
||||||
seq_print_delegate_opts(m, "delegate_progs",
|
|
||||||
info.btf, info.prog_t, "BPF_PROG_TYPE_",
|
|
||||||
opts->delegate_progs, mask);
|
|
||||||
|
|
||||||
mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
|
|
||||||
seq_print_delegate_opts(m, "delegate_attachs",
|
|
||||||
info.btf, info.attach_t, "BPF_",
|
|
||||||
opts->delegate_attachs, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -786,7 +617,7 @@ static void bpf_free_inode(struct inode *inode)
|
|||||||
free_inode_nonrcu(inode);
|
free_inode_nonrcu(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct super_operations bpf_super_ops = {
|
static const struct super_operations bpf_super_ops = {
|
||||||
.statfs = simple_statfs,
|
.statfs = simple_statfs,
|
||||||
.drop_inode = generic_delete_inode,
|
.drop_inode = generic_delete_inode,
|
||||||
.show_options = bpf_show_options,
|
.show_options = bpf_show_options,
|
||||||
@@ -794,33 +625,23 @@ const struct super_operations bpf_super_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
OPT_UID,
|
|
||||||
OPT_GID,
|
|
||||||
OPT_MODE,
|
OPT_MODE,
|
||||||
OPT_DELEGATE_CMDS,
|
|
||||||
OPT_DELEGATE_MAPS,
|
|
||||||
OPT_DELEGATE_PROGS,
|
|
||||||
OPT_DELEGATE_ATTACHS,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct fs_parameter_spec bpf_fs_parameters[] = {
|
static const struct fs_parameter_spec bpf_fs_parameters[] = {
|
||||||
fsparam_u32 ("uid", OPT_UID),
|
|
||||||
fsparam_u32 ("gid", OPT_GID),
|
|
||||||
fsparam_u32oct ("mode", OPT_MODE),
|
fsparam_u32oct ("mode", OPT_MODE),
|
||||||
fsparam_string ("delegate_cmds", OPT_DELEGATE_CMDS),
|
|
||||||
fsparam_string ("delegate_maps", OPT_DELEGATE_MAPS),
|
|
||||||
fsparam_string ("delegate_progs", OPT_DELEGATE_PROGS),
|
|
||||||
fsparam_string ("delegate_attachs", OPT_DELEGATE_ATTACHS),
|
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct bpf_mount_opts {
|
||||||
|
umode_t mode;
|
||||||
|
};
|
||||||
|
|
||||||
static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||||
{
|
{
|
||||||
struct bpf_mount_opts *opts = fc->s_fs_info;
|
struct bpf_mount_opts *opts = fc->fs_private;
|
||||||
struct fs_parse_result result;
|
struct fs_parse_result result;
|
||||||
kuid_t uid;
|
int opt;
|
||||||
kgid_t gid;
|
|
||||||
int opt, err;
|
|
||||||
|
|
||||||
opt = fs_parse(fc, bpf_fs_parameters, param, &result);
|
opt = fs_parse(fc, bpf_fs_parameters, param, &result);
|
||||||
if (opt < 0) {
|
if (opt < 0) {
|
||||||
@@ -841,104 +662,12 @@ static int bpf_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case OPT_UID:
|
|
||||||
uid = make_kuid(current_user_ns(), result.uint_32);
|
|
||||||
if (!uid_valid(uid))
|
|
||||||
goto bad_value;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The requested uid must be representable in the
|
|
||||||
* filesystem's idmapping.
|
|
||||||
*/
|
|
||||||
if (!kuid_has_mapping(fc->user_ns, uid))
|
|
||||||
goto bad_value;
|
|
||||||
|
|
||||||
opts->uid = uid;
|
|
||||||
break;
|
|
||||||
case OPT_GID:
|
|
||||||
gid = make_kgid(current_user_ns(), result.uint_32);
|
|
||||||
if (!gid_valid(gid))
|
|
||||||
goto bad_value;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The requested gid must be representable in the
|
|
||||||
* filesystem's idmapping.
|
|
||||||
*/
|
|
||||||
if (!kgid_has_mapping(fc->user_ns, gid))
|
|
||||||
goto bad_value;
|
|
||||||
|
|
||||||
opts->gid = gid;
|
|
||||||
break;
|
|
||||||
case OPT_MODE:
|
case OPT_MODE:
|
||||||
opts->mode = result.uint_32 & S_IALLUGO;
|
opts->mode = result.uint_32 & S_IALLUGO;
|
||||||
break;
|
break;
|
||||||
case OPT_DELEGATE_CMDS:
|
|
||||||
case OPT_DELEGATE_MAPS:
|
|
||||||
case OPT_DELEGATE_PROGS:
|
|
||||||
case OPT_DELEGATE_ATTACHS: {
|
|
||||||
struct bpffs_btf_enums info;
|
|
||||||
const struct btf_type *enum_t;
|
|
||||||
const char *enum_pfx;
|
|
||||||
u64 *delegate_msk, msk = 0;
|
|
||||||
char *p;
|
|
||||||
int val;
|
|
||||||
|
|
||||||
/* ignore errors, fallback to hex */
|
|
||||||
(void)find_bpffs_btf_enums(&info);
|
|
||||||
|
|
||||||
switch (opt) {
|
|
||||||
case OPT_DELEGATE_CMDS:
|
|
||||||
delegate_msk = &opts->delegate_cmds;
|
|
||||||
enum_t = info.cmd_t;
|
|
||||||
enum_pfx = "BPF_";
|
|
||||||
break;
|
|
||||||
case OPT_DELEGATE_MAPS:
|
|
||||||
delegate_msk = &opts->delegate_maps;
|
|
||||||
enum_t = info.map_t;
|
|
||||||
enum_pfx = "BPF_MAP_TYPE_";
|
|
||||||
break;
|
|
||||||
case OPT_DELEGATE_PROGS:
|
|
||||||
delegate_msk = &opts->delegate_progs;
|
|
||||||
enum_t = info.prog_t;
|
|
||||||
enum_pfx = "BPF_PROG_TYPE_";
|
|
||||||
break;
|
|
||||||
case OPT_DELEGATE_ATTACHS:
|
|
||||||
delegate_msk = &opts->delegate_attachs;
|
|
||||||
enum_t = info.attach_t;
|
|
||||||
enum_pfx = "BPF_";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((p = strsep(¶m->string, ":"))) {
|
|
||||||
if (strcmp(p, "any") == 0) {
|
|
||||||
msk |= ~0ULL;
|
|
||||||
} else if (find_btf_enum_const(info.btf, enum_t, enum_pfx, p, &val)) {
|
|
||||||
msk |= 1ULL << val;
|
|
||||||
} else {
|
|
||||||
err = kstrtou64(p, 0, &msk);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setting delegation mount options requires privileges */
|
|
||||||
if (msk && !capable(CAP_SYS_ADMIN))
|
|
||||||
return -EPERM;
|
|
||||||
|
|
||||||
*delegate_msk |= msk;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
/* ignore unknown mount options */
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bad_value:
|
|
||||||
return invalfc(fc, "Bad value for '%s'", param->key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bpf_preload_ops *bpf_preload_ops;
|
struct bpf_preload_ops *bpf_preload_ops;
|
||||||
@@ -1010,14 +739,10 @@ out:
|
|||||||
static int bpf_fill_super(struct super_block *sb, struct fs_context *fc)
|
static int bpf_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||||
{
|
{
|
||||||
static const struct tree_descr bpf_rfiles[] = { { "" } };
|
static const struct tree_descr bpf_rfiles[] = { { "" } };
|
||||||
struct bpf_mount_opts *opts = sb->s_fs_info;
|
struct bpf_mount_opts *opts = fc->fs_private;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Mounting an instance of BPF FS requires privileges */
|
|
||||||
if (fc->user_ns != &init_user_ns && !capable(CAP_SYS_ADMIN))
|
|
||||||
return -EPERM;
|
|
||||||
|
|
||||||
ret = simple_fill_super(sb, BPF_FS_MAGIC, bpf_rfiles);
|
ret = simple_fill_super(sb, BPF_FS_MAGIC, bpf_rfiles);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1025,8 +750,6 @@ static int bpf_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||||||
sb->s_op = &bpf_super_ops;
|
sb->s_op = &bpf_super_ops;
|
||||||
|
|
||||||
inode = sb->s_root->d_inode;
|
inode = sb->s_root->d_inode;
|
||||||
inode->i_uid = opts->uid;
|
|
||||||
inode->i_gid = opts->gid;
|
|
||||||
inode->i_op = &bpf_dir_iops;
|
inode->i_op = &bpf_dir_iops;
|
||||||
inode->i_mode &= ~S_IALLUGO;
|
inode->i_mode &= ~S_IALLUGO;
|
||||||
populate_bpffs(sb->s_root);
|
populate_bpffs(sb->s_root);
|
||||||
@@ -1041,7 +764,7 @@ static int bpf_get_tree(struct fs_context *fc)
|
|||||||
|
|
||||||
static void bpf_free_fc(struct fs_context *fc)
|
static void bpf_free_fc(struct fs_context *fc)
|
||||||
{
|
{
|
||||||
kfree(fc->s_fs_info);
|
kfree(fc->fs_private);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct fs_context_operations bpf_context_ops = {
|
static const struct fs_context_operations bpf_context_ops = {
|
||||||
@@ -1062,35 +785,18 @@ static int bpf_init_fs_context(struct fs_context *fc)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
opts->mode = S_IRWXUGO;
|
opts->mode = S_IRWXUGO;
|
||||||
opts->uid = current_fsuid();
|
|
||||||
opts->gid = current_fsgid();
|
|
||||||
|
|
||||||
/* start out with no BPF token delegation enabled */
|
fc->fs_private = opts;
|
||||||
opts->delegate_cmds = 0;
|
|
||||||
opts->delegate_maps = 0;
|
|
||||||
opts->delegate_progs = 0;
|
|
||||||
opts->delegate_attachs = 0;
|
|
||||||
|
|
||||||
fc->s_fs_info = opts;
|
|
||||||
fc->ops = &bpf_context_ops;
|
fc->ops = &bpf_context_ops;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bpf_kill_super(struct super_block *sb)
|
|
||||||
{
|
|
||||||
struct bpf_mount_opts *opts = sb->s_fs_info;
|
|
||||||
|
|
||||||
kill_litter_super(sb);
|
|
||||||
kfree(opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct file_system_type bpf_fs_type = {
|
static struct file_system_type bpf_fs_type = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "bpf",
|
.name = "bpf",
|
||||||
.init_fs_context = bpf_init_fs_context,
|
.init_fs_context = bpf_init_fs_context,
|
||||||
.parameters = bpf_fs_parameters,
|
.parameters = bpf_fs_parameters,
|
||||||
.kill_sb = bpf_kill_super,
|
.kill_sb = kill_litter_super,
|
||||||
.fs_flags = FS_USERNS_MOUNT,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init bpf_init(void)
|
static int __init bpf_init(void)
|
||||||
|
|||||||
+56
-159
@@ -1011,8 +1011,8 @@ int map_check_no_btf(const struct bpf_map *map,
|
|||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
|
static int map_check_btf(struct bpf_map *map, const struct btf *btf,
|
||||||
const struct btf *btf, u32 btf_key_id, u32 btf_value_id)
|
u32 btf_key_id, u32 btf_value_id)
|
||||||
{
|
{
|
||||||
const struct btf_type *key_type, *value_type;
|
const struct btf_type *key_type, *value_type;
|
||||||
u32 key_size, value_size;
|
u32 key_size, value_size;
|
||||||
@@ -1040,7 +1040,7 @@ static int map_check_btf(struct bpf_map *map, struct bpf_token *token,
|
|||||||
if (!IS_ERR_OR_NULL(map->record)) {
|
if (!IS_ERR_OR_NULL(map->record)) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!bpf_token_capable(token, CAP_BPF)) {
|
if (!bpf_capable()) {
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
goto free_map_tab;
|
goto free_map_tab;
|
||||||
}
|
}
|
||||||
@@ -1123,17 +1123,11 @@ free_map_tab:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bpf_net_capable(void)
|
#define BPF_MAP_CREATE_LAST_FIELD map_extra
|
||||||
{
|
|
||||||
return capable(CAP_NET_ADMIN) || capable(CAP_SYS_ADMIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BPF_MAP_CREATE_LAST_FIELD map_token_fd
|
|
||||||
/* called via syscall */
|
/* called via syscall */
|
||||||
static int map_create(union bpf_attr *attr)
|
static int map_create(union bpf_attr *attr)
|
||||||
{
|
{
|
||||||
const struct bpf_map_ops *ops;
|
const struct bpf_map_ops *ops;
|
||||||
struct bpf_token *token = NULL;
|
|
||||||
int numa_node = bpf_map_attr_numa_node(attr);
|
int numa_node = bpf_map_attr_numa_node(attr);
|
||||||
u32 map_type = attr->map_type;
|
u32 map_type = attr->map_type;
|
||||||
struct bpf_map *map;
|
struct bpf_map *map;
|
||||||
@@ -1184,32 +1178,14 @@ static int map_create(union bpf_attr *attr)
|
|||||||
if (!ops->map_mem_usage)
|
if (!ops->map_mem_usage)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (attr->map_token_fd) {
|
|
||||||
token = bpf_token_get_from_fd(attr->map_token_fd);
|
|
||||||
if (IS_ERR(token))
|
|
||||||
return PTR_ERR(token);
|
|
||||||
|
|
||||||
/* if current token doesn't grant map creation permissions,
|
|
||||||
* then we can't use this token, so ignore it and rely on
|
|
||||||
* system-wide capabilities checks
|
|
||||||
*/
|
|
||||||
if (!bpf_token_allow_cmd(token, BPF_MAP_CREATE) ||
|
|
||||||
!bpf_token_allow_map_type(token, attr->map_type)) {
|
|
||||||
bpf_token_put(token);
|
|
||||||
token = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = -EPERM;
|
|
||||||
|
|
||||||
/* Intent here is for unprivileged_bpf_disabled to block BPF map
|
/* Intent here is for unprivileged_bpf_disabled to block BPF map
|
||||||
* creation for unprivileged users; other actions depend
|
* creation for unprivileged users; other actions depend
|
||||||
* on fd availability and access to bpffs, so are dependent on
|
* on fd availability and access to bpffs, so are dependent on
|
||||||
* object creation success. Even with unprivileged BPF disabled,
|
* object creation success. Even with unprivileged BPF disabled,
|
||||||
* capability checks are still carried out.
|
* capability checks are still carried out.
|
||||||
*/
|
*/
|
||||||
if (sysctl_unprivileged_bpf_disabled && !bpf_token_capable(token, CAP_BPF))
|
if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
|
|
||||||
/* check privileged map type permissions */
|
/* check privileged map type permissions */
|
||||||
switch (map_type) {
|
switch (map_type) {
|
||||||
@@ -1242,27 +1218,25 @@ static int map_create(union bpf_attr *attr)
|
|||||||
case BPF_MAP_TYPE_LRU_PERCPU_HASH:
|
case BPF_MAP_TYPE_LRU_PERCPU_HASH:
|
||||||
case BPF_MAP_TYPE_STRUCT_OPS:
|
case BPF_MAP_TYPE_STRUCT_OPS:
|
||||||
case BPF_MAP_TYPE_CPUMAP:
|
case BPF_MAP_TYPE_CPUMAP:
|
||||||
if (!bpf_token_capable(token, CAP_BPF))
|
if (!bpf_capable())
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
break;
|
break;
|
||||||
case BPF_MAP_TYPE_SOCKMAP:
|
case BPF_MAP_TYPE_SOCKMAP:
|
||||||
case BPF_MAP_TYPE_SOCKHASH:
|
case BPF_MAP_TYPE_SOCKHASH:
|
||||||
case BPF_MAP_TYPE_DEVMAP:
|
case BPF_MAP_TYPE_DEVMAP:
|
||||||
case BPF_MAP_TYPE_DEVMAP_HASH:
|
case BPF_MAP_TYPE_DEVMAP_HASH:
|
||||||
case BPF_MAP_TYPE_XSKMAP:
|
case BPF_MAP_TYPE_XSKMAP:
|
||||||
if (!bpf_token_capable(token, CAP_NET_ADMIN))
|
if (!capable(CAP_NET_ADMIN))
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN(1, "unsupported map type %d", map_type);
|
WARN(1, "unsupported map type %d", map_type);
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
||||||
map = ops->map_alloc(attr);
|
map = ops->map_alloc(attr);
|
||||||
if (IS_ERR(map)) {
|
if (IS_ERR(map))
|
||||||
err = PTR_ERR(map);
|
return PTR_ERR(map);
|
||||||
goto put_token;
|
|
||||||
}
|
|
||||||
map->ops = ops;
|
map->ops = ops;
|
||||||
map->map_type = map_type;
|
map->map_type = map_type;
|
||||||
|
|
||||||
@@ -1299,7 +1273,7 @@ static int map_create(union bpf_attr *attr)
|
|||||||
map->btf = btf;
|
map->btf = btf;
|
||||||
|
|
||||||
if (attr->btf_value_type_id) {
|
if (attr->btf_value_type_id) {
|
||||||
err = map_check_btf(map, token, btf, attr->btf_key_type_id,
|
err = map_check_btf(map, btf, attr->btf_key_type_id,
|
||||||
attr->btf_value_type_id);
|
attr->btf_value_type_id);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_map;
|
goto free_map;
|
||||||
@@ -1311,16 +1285,15 @@ static int map_create(union bpf_attr *attr)
|
|||||||
attr->btf_vmlinux_value_type_id;
|
attr->btf_vmlinux_value_type_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = security_bpf_map_create(map, attr, token);
|
err = security_bpf_map_alloc(map);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_map_sec;
|
goto free_map;
|
||||||
|
|
||||||
err = bpf_map_alloc_id(map);
|
err = bpf_map_alloc_id(map);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_map_sec;
|
goto free_map_sec;
|
||||||
|
|
||||||
bpf_map_save_memcg(map);
|
bpf_map_save_memcg(map);
|
||||||
bpf_token_put(token);
|
|
||||||
|
|
||||||
err = bpf_map_new_fd(map, f_flags);
|
err = bpf_map_new_fd(map, f_flags);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
@@ -1341,8 +1314,6 @@ free_map_sec:
|
|||||||
free_map:
|
free_map:
|
||||||
btf_put(map->btf);
|
btf_put(map->btf);
|
||||||
map->ops->map_free(map);
|
map->ops->map_free(map);
|
||||||
put_token:
|
|
||||||
bpf_token_put(token);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2173,7 +2144,7 @@ static void __bpf_prog_put_rcu(struct rcu_head *rcu)
|
|||||||
kvfree(aux->func_info);
|
kvfree(aux->func_info);
|
||||||
kfree(aux->func_info_aux);
|
kfree(aux->func_info_aux);
|
||||||
free_uid(aux->user);
|
free_uid(aux->user);
|
||||||
security_bpf_prog_free(aux->prog);
|
security_bpf_prog_free(aux);
|
||||||
bpf_prog_free(aux->prog);
|
bpf_prog_free(aux->prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2619,15 +2590,13 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* last field in 'union bpf_attr' used by this command */
|
/* last field in 'union bpf_attr' used by this command */
|
||||||
#define BPF_PROG_LOAD_LAST_FIELD prog_token_fd
|
#define BPF_PROG_LOAD_LAST_FIELD log_true_size
|
||||||
|
|
||||||
static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
||||||
{
|
{
|
||||||
enum bpf_prog_type type = attr->prog_type;
|
enum bpf_prog_type type = attr->prog_type;
|
||||||
struct bpf_prog *prog, *dst_prog = NULL;
|
struct bpf_prog *prog, *dst_prog = NULL;
|
||||||
struct btf *attach_btf = NULL;
|
struct btf *attach_btf = NULL;
|
||||||
struct bpf_token *token = NULL;
|
|
||||||
bool bpf_cap;
|
|
||||||
int err;
|
int err;
|
||||||
char license[128];
|
char license[128];
|
||||||
|
|
||||||
@@ -2644,31 +2613,10 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
BPF_F_TEST_REG_INVARIANTS))
|
BPF_F_TEST_REG_INVARIANTS))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
bpf_prog_load_fixup_attach_type(attr);
|
|
||||||
|
|
||||||
if (attr->prog_token_fd) {
|
|
||||||
token = bpf_token_get_from_fd(attr->prog_token_fd);
|
|
||||||
if (IS_ERR(token))
|
|
||||||
return PTR_ERR(token);
|
|
||||||
/* if current token doesn't grant prog loading permissions,
|
|
||||||
* then we can't use this token, so ignore it and rely on
|
|
||||||
* system-wide capabilities checks
|
|
||||||
*/
|
|
||||||
if (!bpf_token_allow_cmd(token, BPF_PROG_LOAD) ||
|
|
||||||
!bpf_token_allow_prog_type(token, attr->prog_type,
|
|
||||||
attr->expected_attach_type)) {
|
|
||||||
bpf_token_put(token);
|
|
||||||
token = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bpf_cap = bpf_token_capable(token, CAP_BPF);
|
|
||||||
err = -EPERM;
|
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
|
if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) &&
|
||||||
(attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
|
(attr->prog_flags & BPF_F_ANY_ALIGNMENT) &&
|
||||||
!bpf_cap)
|
!bpf_capable())
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
|
|
||||||
/* Intent here is for unprivileged_bpf_disabled to block BPF program
|
/* Intent here is for unprivileged_bpf_disabled to block BPF program
|
||||||
* creation for unprivileged users; other actions depend
|
* creation for unprivileged users; other actions depend
|
||||||
@@ -2677,23 +2625,21 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
* capability checks are still carried out for these
|
* capability checks are still carried out for these
|
||||||
* and other operations.
|
* and other operations.
|
||||||
*/
|
*/
|
||||||
if (sysctl_unprivileged_bpf_disabled && !bpf_cap)
|
if (sysctl_unprivileged_bpf_disabled && !bpf_capable())
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
|
|
||||||
if (attr->insn_cnt == 0 ||
|
if (attr->insn_cnt == 0 ||
|
||||||
attr->insn_cnt > (bpf_cap ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) {
|
attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS))
|
||||||
err = -E2BIG;
|
return -E2BIG;
|
||||||
goto put_token;
|
|
||||||
}
|
|
||||||
if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
|
if (type != BPF_PROG_TYPE_SOCKET_FILTER &&
|
||||||
type != BPF_PROG_TYPE_CGROUP_SKB &&
|
type != BPF_PROG_TYPE_CGROUP_SKB &&
|
||||||
!bpf_cap)
|
!bpf_capable())
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
|
|
||||||
if (is_net_admin_prog_type(type) && !bpf_token_capable(token, CAP_NET_ADMIN))
|
if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN))
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
if (is_perfmon_prog_type(type) && !bpf_token_capable(token, CAP_PERFMON))
|
if (is_perfmon_prog_type(type) && !perfmon_capable())
|
||||||
goto put_token;
|
return -EPERM;
|
||||||
|
|
||||||
/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
|
/* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog
|
||||||
* or btf, we need to check which one it is
|
* or btf, we need to check which one it is
|
||||||
@@ -2703,33 +2649,27 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
if (IS_ERR(dst_prog)) {
|
if (IS_ERR(dst_prog)) {
|
||||||
dst_prog = NULL;
|
dst_prog = NULL;
|
||||||
attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
|
attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd);
|
||||||
if (IS_ERR(attach_btf)) {
|
if (IS_ERR(attach_btf))
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
goto put_token;
|
|
||||||
}
|
|
||||||
if (!btf_is_kernel(attach_btf)) {
|
if (!btf_is_kernel(attach_btf)) {
|
||||||
/* attaching through specifying bpf_prog's BTF
|
/* attaching through specifying bpf_prog's BTF
|
||||||
* objects directly might be supported eventually
|
* objects directly might be supported eventually
|
||||||
*/
|
*/
|
||||||
btf_put(attach_btf);
|
btf_put(attach_btf);
|
||||||
err = -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
goto put_token;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (attr->attach_btf_id) {
|
} else if (attr->attach_btf_id) {
|
||||||
/* fall back to vmlinux BTF, if BTF type ID is specified */
|
/* fall back to vmlinux BTF, if BTF type ID is specified */
|
||||||
attach_btf = bpf_get_btf_vmlinux();
|
attach_btf = bpf_get_btf_vmlinux();
|
||||||
if (IS_ERR(attach_btf)) {
|
if (IS_ERR(attach_btf))
|
||||||
err = PTR_ERR(attach_btf);
|
return PTR_ERR(attach_btf);
|
||||||
goto put_token;
|
if (!attach_btf)
|
||||||
}
|
return -EINVAL;
|
||||||
if (!attach_btf) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto put_token;
|
|
||||||
}
|
|
||||||
btf_get(attach_btf);
|
btf_get(attach_btf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bpf_prog_load_fixup_attach_type(attr);
|
||||||
if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
|
if (bpf_prog_load_check_attach(type, attr->expected_attach_type,
|
||||||
attach_btf, attr->attach_btf_id,
|
attach_btf, attr->attach_btf_id,
|
||||||
dst_prog)) {
|
dst_prog)) {
|
||||||
@@ -2737,8 +2677,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
bpf_prog_put(dst_prog);
|
bpf_prog_put(dst_prog);
|
||||||
if (attach_btf)
|
if (attach_btf)
|
||||||
btf_put(attach_btf);
|
btf_put(attach_btf);
|
||||||
err = -EINVAL;
|
return -EINVAL;
|
||||||
goto put_token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* plain bpf_prog allocation */
|
/* plain bpf_prog allocation */
|
||||||
@@ -2748,8 +2687,7 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
bpf_prog_put(dst_prog);
|
bpf_prog_put(dst_prog);
|
||||||
if (attach_btf)
|
if (attach_btf)
|
||||||
btf_put(attach_btf);
|
btf_put(attach_btf);
|
||||||
err = -EINVAL;
|
return -ENOMEM;
|
||||||
goto put_token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prog->expected_attach_type = attr->expected_attach_type;
|
prog->expected_attach_type = attr->expected_attach_type;
|
||||||
@@ -2760,9 +2698,9 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
|
prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE;
|
||||||
prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
|
prog->aux->xdp_has_frags = attr->prog_flags & BPF_F_XDP_HAS_FRAGS;
|
||||||
|
|
||||||
/* move token into prog->aux, reuse taken refcnt */
|
err = security_bpf_prog_alloc(prog->aux);
|
||||||
prog->aux->token = token;
|
if (err)
|
||||||
token = NULL;
|
goto free_prog;
|
||||||
|
|
||||||
prog->aux->user = get_current_user();
|
prog->aux->user = get_current_user();
|
||||||
prog->len = attr->insn_cnt;
|
prog->len = attr->insn_cnt;
|
||||||
@@ -2771,12 +2709,12 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
if (copy_from_bpfptr(prog->insns,
|
if (copy_from_bpfptr(prog->insns,
|
||||||
make_bpfptr(attr->insns, uattr.is_kernel),
|
make_bpfptr(attr->insns, uattr.is_kernel),
|
||||||
bpf_prog_insn_size(prog)) != 0)
|
bpf_prog_insn_size(prog)) != 0)
|
||||||
goto free_prog;
|
goto free_prog_sec;
|
||||||
/* copy eBPF program license from user space */
|
/* copy eBPF program license from user space */
|
||||||
if (strncpy_from_bpfptr(license,
|
if (strncpy_from_bpfptr(license,
|
||||||
make_bpfptr(attr->license, uattr.is_kernel),
|
make_bpfptr(attr->license, uattr.is_kernel),
|
||||||
sizeof(license) - 1) < 0)
|
sizeof(license) - 1) < 0)
|
||||||
goto free_prog;
|
goto free_prog_sec;
|
||||||
license[sizeof(license) - 1] = 0;
|
license[sizeof(license) - 1] = 0;
|
||||||
|
|
||||||
/* eBPF programs must be GPL compatible to use GPL-ed functions */
|
/* eBPF programs must be GPL compatible to use GPL-ed functions */
|
||||||
@@ -2790,29 +2728,25 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
|
|||||||
if (bpf_prog_is_dev_bound(prog->aux)) {
|
if (bpf_prog_is_dev_bound(prog->aux)) {
|
||||||
err = bpf_prog_dev_bound_init(prog, attr);
|
err = bpf_prog_dev_bound_init(prog, attr);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_prog;
|
goto free_prog_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == BPF_PROG_TYPE_EXT && dst_prog &&
|
if (type == BPF_PROG_TYPE_EXT && dst_prog &&
|
||||||
bpf_prog_is_dev_bound(dst_prog->aux)) {
|
bpf_prog_is_dev_bound(dst_prog->aux)) {
|
||||||
err = bpf_prog_dev_bound_inherit(prog, dst_prog);
|
err = bpf_prog_dev_bound_inherit(prog, dst_prog);
|
||||||
if (err)
|
if (err)
|
||||||
goto free_prog;
|
goto free_prog_sec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find program type: socket_filter vs tracing_filter */
|
/* find program type: socket_filter vs tracing_filter */
|
||||||
err = find_prog_type(type, prog);
|
err = find_prog_type(type, prog);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto free_prog;
|
goto free_prog_sec;
|
||||||
|
|
||||||
prog->aux->load_time = ktime_get_boottime_ns();
|
prog->aux->load_time = ktime_get_boottime_ns();
|
||||||
err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
|
err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name,
|
||||||
sizeof(attr->prog_name));
|
sizeof(attr->prog_name));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto free_prog;
|
|
||||||
|
|
||||||
err = security_bpf_prog_load(prog, attr, token);
|
|
||||||
if (err)
|
|
||||||
goto free_prog_sec;
|
goto free_prog_sec;
|
||||||
|
|
||||||
/* run eBPF verifier */
|
/* run eBPF verifier */
|
||||||
@@ -2858,16 +2792,13 @@ free_used_maps:
|
|||||||
*/
|
*/
|
||||||
__bpf_prog_put_noref(prog, prog->aux->real_func_cnt);
|
__bpf_prog_put_noref(prog, prog->aux->real_func_cnt);
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
free_prog_sec:
|
free_prog_sec:
|
||||||
security_bpf_prog_free(prog);
|
|
||||||
free_prog:
|
|
||||||
free_uid(prog->aux->user);
|
free_uid(prog->aux->user);
|
||||||
|
security_bpf_prog_free(prog->aux);
|
||||||
|
free_prog:
|
||||||
if (prog->aux->attach_btf)
|
if (prog->aux->attach_btf)
|
||||||
btf_put(prog->aux->attach_btf);
|
btf_put(prog->aux->attach_btf);
|
||||||
bpf_prog_free(prog);
|
bpf_prog_free(prog);
|
||||||
put_token:
|
|
||||||
bpf_token_put(token);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3857,7 +3788,7 @@ static int bpf_prog_attach_check_attach_type(const struct bpf_prog *prog,
|
|||||||
case BPF_PROG_TYPE_SK_LOOKUP:
|
case BPF_PROG_TYPE_SK_LOOKUP:
|
||||||
return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
|
return attach_type == prog->expected_attach_type ? 0 : -EINVAL;
|
||||||
case BPF_PROG_TYPE_CGROUP_SKB:
|
case BPF_PROG_TYPE_CGROUP_SKB:
|
||||||
if (!bpf_token_capable(prog->aux->token, CAP_NET_ADMIN))
|
if (!capable(CAP_NET_ADMIN))
|
||||||
/* cg-skb progs can be loaded by unpriv user.
|
/* cg-skb progs can be loaded by unpriv user.
|
||||||
* check permissions at attach time.
|
* check permissions at attach time.
|
||||||
*/
|
*/
|
||||||
@@ -4060,7 +3991,7 @@ static int bpf_prog_detach(const union bpf_attr *attr)
|
|||||||
static int bpf_prog_query(const union bpf_attr *attr,
|
static int bpf_prog_query(const union bpf_attr *attr,
|
||||||
union bpf_attr __user *uattr)
|
union bpf_attr __user *uattr)
|
||||||
{
|
{
|
||||||
if (!bpf_net_capable())
|
if (!capable(CAP_NET_ADMIN))
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (CHECK_ATTR(BPF_PROG_QUERY))
|
if (CHECK_ATTR(BPF_PROG_QUERY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -4828,31 +4759,15 @@ static int bpf_obj_get_info_by_fd(const union bpf_attr *attr,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BPF_BTF_LOAD_LAST_FIELD btf_token_fd
|
#define BPF_BTF_LOAD_LAST_FIELD btf_log_true_size
|
||||||
|
|
||||||
static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size)
|
static int bpf_btf_load(const union bpf_attr *attr, bpfptr_t uattr, __u32 uattr_size)
|
||||||
{
|
{
|
||||||
struct bpf_token *token = NULL;
|
|
||||||
|
|
||||||
if (CHECK_ATTR(BPF_BTF_LOAD))
|
if (CHECK_ATTR(BPF_BTF_LOAD))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (attr->btf_token_fd) {
|
if (!bpf_capable())
|
||||||
token = bpf_token_get_from_fd(attr->btf_token_fd);
|
|
||||||
if (IS_ERR(token))
|
|
||||||
return PTR_ERR(token);
|
|
||||||
if (!bpf_token_allow_cmd(token, BPF_BTF_LOAD)) {
|
|
||||||
bpf_token_put(token);
|
|
||||||
token = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bpf_token_capable(token, CAP_BPF)) {
|
|
||||||
bpf_token_put(token);
|
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
|
||||||
|
|
||||||
bpf_token_put(token);
|
|
||||||
|
|
||||||
return btf_new_fd(attr, uattr, uattr_size);
|
return btf_new_fd(attr, uattr, uattr_size);
|
||||||
}
|
}
|
||||||
@@ -5470,20 +5385,6 @@ out_prog_put:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BPF_TOKEN_CREATE_LAST_FIELD token_create.bpffs_fd
|
|
||||||
|
|
||||||
static int token_create(union bpf_attr *attr)
|
|
||||||
{
|
|
||||||
if (CHECK_ATTR(BPF_TOKEN_CREATE))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* no flags are supported yet */
|
|
||||||
if (attr->token_create.flags)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
return bpf_token_create(attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
|
static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
|
||||||
{
|
{
|
||||||
union bpf_attr attr;
|
union bpf_attr attr;
|
||||||
@@ -5617,9 +5518,6 @@ static int __sys_bpf(int cmd, bpfptr_t uattr, unsigned int size)
|
|||||||
case BPF_PROG_BIND_MAP:
|
case BPF_PROG_BIND_MAP:
|
||||||
err = bpf_prog_bind_map(&attr);
|
err = bpf_prog_bind_map(&attr);
|
||||||
break;
|
break;
|
||||||
case BPF_TOKEN_CREATE:
|
|
||||||
err = token_create(&attr);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
break;
|
break;
|
||||||
@@ -5726,7 +5624,7 @@ static const struct bpf_func_proto bpf_sys_bpf_proto = {
|
|||||||
const struct bpf_func_proto * __weak
|
const struct bpf_func_proto * __weak
|
||||||
tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
tracing_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
||||||
{
|
{
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
BPF_CALL_1(bpf_sys_close, u32, fd)
|
BPF_CALL_1(bpf_sys_close, u32, fd)
|
||||||
@@ -5776,8 +5674,7 @@ syscall_prog_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
{
|
{
|
||||||
switch (func_id) {
|
switch (func_id) {
|
||||||
case BPF_FUNC_sys_bpf:
|
case BPF_FUNC_sys_bpf:
|
||||||
return !bpf_token_capable(prog->aux->token, CAP_PERFMON)
|
return !perfmon_capable() ? NULL : &bpf_sys_bpf_proto;
|
||||||
? NULL : &bpf_sys_bpf_proto;
|
|
||||||
case BPF_FUNC_btf_find_by_name_kind:
|
case BPF_FUNC_btf_find_by_name_kind:
|
||||||
return &bpf_btf_find_by_name_kind_proto;
|
return &bpf_btf_find_by_name_kind_proto;
|
||||||
case BPF_FUNC_sys_close:
|
case BPF_FUNC_sys_close:
|
||||||
|
|||||||
@@ -1,271 +0,0 @@
|
|||||||
#include <linux/bpf.h>
|
|
||||||
#include <linux/vmalloc.h>
|
|
||||||
#include <linux/fdtable.h>
|
|
||||||
#include <linux/file.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/idr.h>
|
|
||||||
#include <linux/namei.h>
|
|
||||||
#include <linux/user_namespace.h>
|
|
||||||
#include <linux/security.h>
|
|
||||||
|
|
||||||
bool bpf_token_capable(const struct bpf_token *token, int cap)
|
|
||||||
{
|
|
||||||
/* BPF token allows ns_capable() level of capabilities, but only if
|
|
||||||
* token's userns is *exactly* the same as current user's userns
|
|
||||||
*/
|
|
||||||
if (token && current_user_ns() == token->userns) {
|
|
||||||
if (ns_capable(token->userns, cap) ||
|
|
||||||
(cap != CAP_SYS_ADMIN && ns_capable(token->userns, CAP_SYS_ADMIN)))
|
|
||||||
return security_bpf_token_capable(token, cap) == 0;
|
|
||||||
}
|
|
||||||
/* otherwise fallback to capable() checks */
|
|
||||||
return capable(cap) || (cap != CAP_SYS_ADMIN && capable(CAP_SYS_ADMIN));
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpf_token_inc(struct bpf_token *token)
|
|
||||||
{
|
|
||||||
atomic64_inc(&token->refcnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bpf_token_free(struct bpf_token *token)
|
|
||||||
{
|
|
||||||
security_bpf_token_free(token);
|
|
||||||
put_user_ns(token->userns);
|
|
||||||
kvfree(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bpf_token_put_deferred(struct work_struct *work)
|
|
||||||
{
|
|
||||||
struct bpf_token *token = container_of(work, struct bpf_token, work);
|
|
||||||
|
|
||||||
bpf_token_free(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bpf_token_put(struct bpf_token *token)
|
|
||||||
{
|
|
||||||
if (!token)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!atomic64_dec_and_test(&token->refcnt))
|
|
||||||
return;
|
|
||||||
|
|
||||||
INIT_WORK(&token->work, bpf_token_put_deferred);
|
|
||||||
schedule_work(&token->work);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int bpf_token_release(struct inode *inode, struct file *filp)
|
|
||||||
{
|
|
||||||
struct bpf_token *token = filp->private_data;
|
|
||||||
|
|
||||||
bpf_token_put(token);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp)
|
|
||||||
{
|
|
||||||
struct bpf_token *token = filp->private_data;
|
|
||||||
u64 mask;
|
|
||||||
|
|
||||||
BUILD_BUG_ON(__MAX_BPF_CMD >= 64);
|
|
||||||
mask = (1ULL << __MAX_BPF_CMD) - 1;
|
|
||||||
if ((token->allowed_cmds & mask) == mask)
|
|
||||||
seq_printf(m, "allowed_cmds:\tany\n");
|
|
||||||
else
|
|
||||||
seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds);
|
|
||||||
|
|
||||||
BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64);
|
|
||||||
mask = (1ULL << __MAX_BPF_MAP_TYPE) - 1;
|
|
||||||
if ((token->allowed_maps & mask) == mask)
|
|
||||||
seq_printf(m, "allowed_maps:\tany\n");
|
|
||||||
else
|
|
||||||
seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps);
|
|
||||||
|
|
||||||
BUILD_BUG_ON(__MAX_BPF_PROG_TYPE >= 64);
|
|
||||||
mask = (1ULL << __MAX_BPF_PROG_TYPE) - 1;
|
|
||||||
if ((token->allowed_progs & mask) == mask)
|
|
||||||
seq_printf(m, "allowed_progs:\tany\n");
|
|
||||||
else
|
|
||||||
seq_printf(m, "allowed_progs:\t0x%llx\n", token->allowed_progs);
|
|
||||||
|
|
||||||
BUILD_BUG_ON(__MAX_BPF_ATTACH_TYPE >= 64);
|
|
||||||
mask = (1ULL << __MAX_BPF_ATTACH_TYPE) - 1;
|
|
||||||
if ((token->allowed_attachs & mask) == mask)
|
|
||||||
seq_printf(m, "allowed_attachs:\tany\n");
|
|
||||||
else
|
|
||||||
seq_printf(m, "allowed_attachs:\t0x%llx\n", token->allowed_attachs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BPF_TOKEN_INODE_NAME "bpf-token"
|
|
||||||
|
|
||||||
static const struct inode_operations bpf_token_iops = { };
|
|
||||||
|
|
||||||
static const struct file_operations bpf_token_fops = {
|
|
||||||
.release = bpf_token_release,
|
|
||||||
.show_fdinfo = bpf_token_show_fdinfo,
|
|
||||||
};
|
|
||||||
|
|
||||||
int bpf_token_create(union bpf_attr *attr)
|
|
||||||
{
|
|
||||||
struct bpf_mount_opts *mnt_opts;
|
|
||||||
struct bpf_token *token = NULL;
|
|
||||||
struct user_namespace *userns;
|
|
||||||
struct inode *inode;
|
|
||||||
struct file *file;
|
|
||||||
struct path path;
|
|
||||||
struct fd f;
|
|
||||||
umode_t mode;
|
|
||||||
int err, fd;
|
|
||||||
|
|
||||||
f = fdget(attr->token_create.bpffs_fd);
|
|
||||||
if (!f.file)
|
|
||||||
return -EBADF;
|
|
||||||
|
|
||||||
path = f.file->f_path;
|
|
||||||
path_get(&path);
|
|
||||||
fdput(f);
|
|
||||||
|
|
||||||
if (path.dentry != path.mnt->mnt_sb->s_root) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
if (path.mnt->mnt_sb->s_op != &bpf_super_ops) {
|
|
||||||
err = -EINVAL;
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
err = path_permission(&path, MAY_ACCESS);
|
|
||||||
if (err)
|
|
||||||
goto out_path;
|
|
||||||
|
|
||||||
userns = path.dentry->d_sb->s_user_ns;
|
|
||||||
/*
|
|
||||||
* Enforce that creators of BPF tokens are in the same user
|
|
||||||
* namespace as the BPF FS instance. This makes reasoning about
|
|
||||||
* permissions a lot easier and we can always relax this later.
|
|
||||||
*/
|
|
||||||
if (current_user_ns() != userns) {
|
|
||||||
err = -EPERM;
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
if (!ns_capable(userns, CAP_BPF)) {
|
|
||||||
err = -EPERM;
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
mnt_opts = path.dentry->d_sb->s_fs_info;
|
|
||||||
if (mnt_opts->delegate_cmds == 0 &&
|
|
||||||
mnt_opts->delegate_maps == 0 &&
|
|
||||||
mnt_opts->delegate_progs == 0 &&
|
|
||||||
mnt_opts->delegate_attachs == 0) {
|
|
||||||
err = -ENOENT; /* no BPF token delegation is set up */
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask());
|
|
||||||
inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode);
|
|
||||||
if (IS_ERR(inode)) {
|
|
||||||
err = PTR_ERR(inode);
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
inode->i_op = &bpf_token_iops;
|
|
||||||
inode->i_fop = &bpf_token_fops;
|
|
||||||
clear_nlink(inode); /* make sure it is unlinked */
|
|
||||||
|
|
||||||
file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops);
|
|
||||||
if (IS_ERR(file)) {
|
|
||||||
iput(inode);
|
|
||||||
err = PTR_ERR(file);
|
|
||||||
goto out_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
token = kvzalloc(sizeof(*token), GFP_USER);
|
|
||||||
if (!token) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto out_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic64_set(&token->refcnt, 1);
|
|
||||||
|
|
||||||
/* remember bpffs owning userns for future ns_capable() checks */
|
|
||||||
token->userns = get_user_ns(userns);
|
|
||||||
|
|
||||||
token->allowed_cmds = mnt_opts->delegate_cmds;
|
|
||||||
token->allowed_maps = mnt_opts->delegate_maps;
|
|
||||||
token->allowed_progs = mnt_opts->delegate_progs;
|
|
||||||
token->allowed_attachs = mnt_opts->delegate_attachs;
|
|
||||||
|
|
||||||
err = security_bpf_token_create(token, attr, &path);
|
|
||||||
if (err)
|
|
||||||
goto out_token;
|
|
||||||
|
|
||||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
|
||||||
if (fd < 0) {
|
|
||||||
err = fd;
|
|
||||||
goto out_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
file->private_data = token;
|
|
||||||
fd_install(fd, file);
|
|
||||||
|
|
||||||
path_put(&path);
|
|
||||||
return fd;
|
|
||||||
|
|
||||||
out_token:
|
|
||||||
bpf_token_free(token);
|
|
||||||
out_file:
|
|
||||||
fput(file);
|
|
||||||
out_path:
|
|
||||||
path_put(&path);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct bpf_token *bpf_token_get_from_fd(u32 ufd)
|
|
||||||
{
|
|
||||||
struct fd f = fdget(ufd);
|
|
||||||
struct bpf_token *token;
|
|
||||||
|
|
||||||
if (!f.file)
|
|
||||||
return ERR_PTR(-EBADF);
|
|
||||||
if (f.file->f_op != &bpf_token_fops) {
|
|
||||||
fdput(f);
|
|
||||||
return ERR_PTR(-EINVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
token = f.file->private_data;
|
|
||||||
bpf_token_inc(token);
|
|
||||||
fdput(f);
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd)
|
|
||||||
{
|
|
||||||
/* BPF token can be used only within exactly the same userns in which
|
|
||||||
* it was created
|
|
||||||
*/
|
|
||||||
if (!token || current_user_ns() != token->userns)
|
|
||||||
return false;
|
|
||||||
if (!(token->allowed_cmds & (1ULL << cmd)))
|
|
||||||
return false;
|
|
||||||
return security_bpf_token_cmd(token, cmd) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type)
|
|
||||||
{
|
|
||||||
if (!token || type >= __MAX_BPF_MAP_TYPE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return token->allowed_maps & (1ULL << type);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bpf_token_allow_prog_type(const struct bpf_token *token,
|
|
||||||
enum bpf_prog_type prog_type,
|
|
||||||
enum bpf_attach_type attach_type)
|
|
||||||
{
|
|
||||||
if (!token || prog_type >= __MAX_BPF_PROG_TYPE || attach_type >= __MAX_BPF_ATTACH_TYPE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (token->allowed_progs & (1ULL << prog_type)) &&
|
|
||||||
(token->allowed_attachs & (1ULL << attach_type));
|
|
||||||
}
|
|
||||||
@@ -20594,12 +20594,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
|
|||||||
env->prog = *prog;
|
env->prog = *prog;
|
||||||
env->ops = bpf_verifier_ops[env->prog->type];
|
env->ops = bpf_verifier_ops[env->prog->type];
|
||||||
env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
|
env->fd_array = make_bpfptr(attr->fd_array, uattr.is_kernel);
|
||||||
|
is_priv = bpf_capable();
|
||||||
env->allow_ptr_leaks = bpf_allow_ptr_leaks(env->prog->aux->token);
|
|
||||||
env->allow_uninit_stack = bpf_allow_uninit_stack(env->prog->aux->token);
|
|
||||||
env->bypass_spec_v1 = bpf_bypass_spec_v1(env->prog->aux->token);
|
|
||||||
env->bypass_spec_v4 = bpf_bypass_spec_v4(env->prog->aux->token);
|
|
||||||
env->bpf_capable = is_priv = bpf_token_capable(env->prog->aux->token, CAP_BPF);
|
|
||||||
|
|
||||||
bpf_get_btf_vmlinux();
|
bpf_get_btf_vmlinux();
|
||||||
|
|
||||||
@@ -20631,6 +20626,12 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
|
|||||||
if (attr->prog_flags & BPF_F_ANY_ALIGNMENT)
|
if (attr->prog_flags & BPF_F_ANY_ALIGNMENT)
|
||||||
env->strict_alignment = false;
|
env->strict_alignment = false;
|
||||||
|
|
||||||
|
env->allow_ptr_leaks = bpf_allow_ptr_leaks();
|
||||||
|
env->allow_uninit_stack = bpf_allow_uninit_stack();
|
||||||
|
env->bypass_spec_v1 = bpf_bypass_spec_v1();
|
||||||
|
env->bypass_spec_v4 = bpf_bypass_spec_v4();
|
||||||
|
env->bpf_capable = bpf_capable();
|
||||||
|
|
||||||
if (is_priv)
|
if (is_priv)
|
||||||
env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ;
|
env->test_state_freq = attr->prog_flags & BPF_F_TEST_STATE_FREQ;
|
||||||
env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS;
|
env->test_reg_invariants = attr->prog_flags & BPF_F_TEST_REG_INVARIANTS;
|
||||||
|
|||||||
@@ -1629,7 +1629,7 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_trace_vprintk:
|
case BPF_FUNC_trace_vprintk:
|
||||||
return bpf_get_trace_vprintk_proto();
|
return bpf_get_trace_vprintk_proto();
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-18
@@ -87,7 +87,7 @@
|
|||||||
#include "dev.h"
|
#include "dev.h"
|
||||||
|
|
||||||
static const struct bpf_func_proto *
|
static const struct bpf_func_proto *
|
||||||
bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog);
|
bpf_sk_base_func_proto(enum bpf_func_id func_id);
|
||||||
|
|
||||||
int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len)
|
int copy_bpf_fprog_from_user(struct sock_fprog *dst, sockptr_t src, int len)
|
||||||
{
|
{
|
||||||
@@ -7862,7 +7862,7 @@ sock_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_ktime_get_coarse_ns:
|
case BPF_FUNC_ktime_get_coarse_ns:
|
||||||
return &bpf_ktime_get_coarse_ns_proto;
|
return &bpf_ktime_get_coarse_ns_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7955,7 +7955,7 @@ sock_addr_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7974,7 +7974,7 @@ sk_filter_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_perf_event_output:
|
case BPF_FUNC_perf_event_output:
|
||||||
return &bpf_skb_event_output_proto;
|
return &bpf_skb_event_output_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8161,7 +8161,7 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8220,7 +8220,7 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)
|
#if IS_MODULE(CONFIG_NF_CONNTRACK) && IS_ENABLED(CONFIG_DEBUG_INFO_BTF_MODULES)
|
||||||
@@ -8281,7 +8281,7 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
return &bpf_tcp_sock_proto;
|
return &bpf_tcp_sock_proto;
|
||||||
#endif /* CONFIG_INET */
|
#endif /* CONFIG_INET */
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8323,7 +8323,7 @@ sk_msg_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
return &bpf_get_cgroup_classid_curr_proto;
|
return &bpf_get_cgroup_classid_curr_proto;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8367,7 +8367,7 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
return &bpf_skc_lookup_tcp_proto;
|
return &bpf_skc_lookup_tcp_proto;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8378,7 +8378,7 @@ flow_dissector_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_skb_load_bytes:
|
case BPF_FUNC_skb_load_bytes:
|
||||||
return &bpf_flow_dissector_load_bytes_proto;
|
return &bpf_flow_dissector_load_bytes_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8405,7 +8405,7 @@ lwt_out_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_skb_under_cgroup:
|
case BPF_FUNC_skb_under_cgroup:
|
||||||
return &bpf_skb_under_cgroup_proto;
|
return &bpf_skb_under_cgroup_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8580,7 +8580,7 @@ static bool cg_skb_is_valid_access(int off, int size,
|
|||||||
return false;
|
return false;
|
||||||
case bpf_ctx_range(struct __sk_buff, data):
|
case bpf_ctx_range(struct __sk_buff, data):
|
||||||
case bpf_ctx_range(struct __sk_buff, data_end):
|
case bpf_ctx_range(struct __sk_buff, data_end):
|
||||||
if (!bpf_token_capable(prog->aux->token, CAP_BPF))
|
if (!bpf_capable())
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -8592,7 +8592,7 @@ static bool cg_skb_is_valid_access(int off, int size,
|
|||||||
case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]):
|
case bpf_ctx_range_till(struct __sk_buff, cb[0], cb[4]):
|
||||||
break;
|
break;
|
||||||
case bpf_ctx_range(struct __sk_buff, tstamp):
|
case bpf_ctx_range(struct __sk_buff, tstamp):
|
||||||
if (!bpf_token_capable(prog->aux->token, CAP_BPF))
|
if (!bpf_capable())
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -11236,7 +11236,7 @@ sk_reuseport_func_proto(enum bpf_func_id func_id,
|
|||||||
case BPF_FUNC_ktime_get_coarse_ns:
|
case BPF_FUNC_ktime_get_coarse_ns:
|
||||||
return &bpf_ktime_get_coarse_ns_proto;
|
return &bpf_ktime_get_coarse_ns_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11418,7 +11418,7 @@ sk_lookup_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_sk_release:
|
case BPF_FUNC_sk_release:
|
||||||
return &bpf_sk_release_proto;
|
return &bpf_sk_release_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_sk_base_func_proto(func_id, prog);
|
return bpf_sk_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11752,7 +11752,7 @@ const struct bpf_func_proto bpf_sock_from_file_proto = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct bpf_func_proto *
|
static const struct bpf_func_proto *
|
||||||
bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
bpf_sk_base_func_proto(enum bpf_func_id func_id)
|
||||||
{
|
{
|
||||||
const struct bpf_func_proto *func;
|
const struct bpf_func_proto *func;
|
||||||
|
|
||||||
@@ -11781,10 +11781,10 @@ bpf_sk_base_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
|||||||
case BPF_FUNC_ktime_get_coarse_ns:
|
case BPF_FUNC_ktime_get_coarse_ns:
|
||||||
return &bpf_ktime_get_coarse_ns_proto;
|
return &bpf_ktime_get_coarse_ns_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bpf_token_capable(prog->aux->token, CAP_PERFMON))
|
if (!perfmon_capable())
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return func;
|
return func;
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ bpf_tcp_ca_get_func_proto(enum bpf_func_id func_id,
|
|||||||
case BPF_FUNC_ktime_get_coarse_ns:
|
case BPF_FUNC_ktime_get_coarse_ns:
|
||||||
return &bpf_ktime_get_coarse_ns_proto;
|
return &bpf_ktime_get_coarse_ns_proto;
|
||||||
default:
|
default:
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ static bool nf_is_valid_access(int off, int size, enum bpf_access_type type,
|
|||||||
static const struct bpf_func_proto *
|
static const struct bpf_func_proto *
|
||||||
bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
||||||
{
|
{
|
||||||
return bpf_base_func_proto(func_id, prog);
|
return bpf_base_func_proto(func_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct bpf_verifier_ops netfilter_verifier_ops = {
|
const struct bpf_verifier_ops netfilter_verifier_ops = {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user