135f96de0SAndrii Nakryiko #include <linux/bpf.h>
235f96de0SAndrii Nakryiko #include <linux/vmalloc.h>
335f96de0SAndrii Nakryiko #include <linux/fdtable.h>
435f96de0SAndrii Nakryiko #include <linux/file.h>
535f96de0SAndrii Nakryiko #include <linux/fs.h>
635f96de0SAndrii Nakryiko #include <linux/kernel.h>
735f96de0SAndrii Nakryiko #include <linux/idr.h>
835f96de0SAndrii Nakryiko #include <linux/namei.h>
935f96de0SAndrii Nakryiko #include <linux/user_namespace.h>
10f568a3d4SAndrii Nakryiko #include <linux/security.h>
1135f96de0SAndrii Nakryiko
bpf_ns_capable(struct user_namespace * ns,int cap)1235f96de0SAndrii Nakryiko static bool bpf_ns_capable(struct user_namespace *ns, int cap)
1335f96de0SAndrii Nakryiko {
1435f96de0SAndrii Nakryiko return ns_capable(ns, cap) || (cap != CAP_SYS_ADMIN && ns_capable(ns, CAP_SYS_ADMIN));
1535f96de0SAndrii Nakryiko }
1635f96de0SAndrii Nakryiko
bpf_token_capable(const struct bpf_token * token,int cap)1735f96de0SAndrii Nakryiko bool bpf_token_capable(const struct bpf_token *token, int cap)
1835f96de0SAndrii Nakryiko {
1935f96de0SAndrii Nakryiko struct user_namespace *userns;
2035f96de0SAndrii Nakryiko
2135f96de0SAndrii Nakryiko /* BPF token allows ns_capable() level of capabilities */
2235f96de0SAndrii Nakryiko userns = token ? token->userns : &init_user_ns;
2335f96de0SAndrii Nakryiko if (!bpf_ns_capable(userns, cap))
2435f96de0SAndrii Nakryiko return false;
25f568a3d4SAndrii Nakryiko if (token && security_bpf_token_capable(token, cap) < 0)
26f568a3d4SAndrii Nakryiko return false;
2735f96de0SAndrii Nakryiko return true;
2835f96de0SAndrii Nakryiko }
2935f96de0SAndrii Nakryiko
bpf_token_inc(struct bpf_token * token)3035f96de0SAndrii Nakryiko void bpf_token_inc(struct bpf_token *token)
3135f96de0SAndrii Nakryiko {
3235f96de0SAndrii Nakryiko atomic64_inc(&token->refcnt);
3335f96de0SAndrii Nakryiko }
3435f96de0SAndrii Nakryiko
bpf_token_free(struct bpf_token * token)3535f96de0SAndrii Nakryiko static void bpf_token_free(struct bpf_token *token)
3635f96de0SAndrii Nakryiko {
37f568a3d4SAndrii Nakryiko security_bpf_token_free(token);
3835f96de0SAndrii Nakryiko put_user_ns(token->userns);
3935f96de0SAndrii Nakryiko kfree(token);
4035f96de0SAndrii Nakryiko }
4135f96de0SAndrii Nakryiko
bpf_token_put_deferred(struct work_struct * work)4235f96de0SAndrii Nakryiko static void bpf_token_put_deferred(struct work_struct *work)
4335f96de0SAndrii Nakryiko {
4435f96de0SAndrii Nakryiko struct bpf_token *token = container_of(work, struct bpf_token, work);
4535f96de0SAndrii Nakryiko
4635f96de0SAndrii Nakryiko bpf_token_free(token);
4735f96de0SAndrii Nakryiko }
4835f96de0SAndrii Nakryiko
bpf_token_put(struct bpf_token * token)4935f96de0SAndrii Nakryiko void bpf_token_put(struct bpf_token *token)
5035f96de0SAndrii Nakryiko {
5135f96de0SAndrii Nakryiko if (!token)
5235f96de0SAndrii Nakryiko return;
5335f96de0SAndrii Nakryiko
5435f96de0SAndrii Nakryiko if (!atomic64_dec_and_test(&token->refcnt))
5535f96de0SAndrii Nakryiko return;
5635f96de0SAndrii Nakryiko
5735f96de0SAndrii Nakryiko INIT_WORK(&token->work, bpf_token_put_deferred);
5835f96de0SAndrii Nakryiko schedule_work(&token->work);
5935f96de0SAndrii Nakryiko }
6035f96de0SAndrii Nakryiko
bpf_token_release(struct inode * inode,struct file * filp)6135f96de0SAndrii Nakryiko static int bpf_token_release(struct inode *inode, struct file *filp)
6235f96de0SAndrii Nakryiko {
6335f96de0SAndrii Nakryiko struct bpf_token *token = filp->private_data;
6435f96de0SAndrii Nakryiko
6535f96de0SAndrii Nakryiko bpf_token_put(token);
6635f96de0SAndrii Nakryiko return 0;
6735f96de0SAndrii Nakryiko }
6835f96de0SAndrii Nakryiko
bpf_token_show_fdinfo(struct seq_file * m,struct file * filp)6935f96de0SAndrii Nakryiko static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp)
7035f96de0SAndrii Nakryiko {
7135f96de0SAndrii Nakryiko struct bpf_token *token = filp->private_data;
7235f96de0SAndrii Nakryiko u64 mask;
7335f96de0SAndrii Nakryiko
7435f96de0SAndrii Nakryiko BUILD_BUG_ON(__MAX_BPF_CMD >= 64);
75*6668e818SHaiyue Wang mask = BIT_ULL(__MAX_BPF_CMD) - 1;
7635f96de0SAndrii Nakryiko if ((token->allowed_cmds & mask) == mask)
7735f96de0SAndrii Nakryiko seq_printf(m, "allowed_cmds:\tany\n");
7835f96de0SAndrii Nakryiko else
7935f96de0SAndrii Nakryiko seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds);
80a177fc2bSAndrii Nakryiko
81a177fc2bSAndrii Nakryiko BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64);
82*6668e818SHaiyue Wang mask = BIT_ULL(__MAX_BPF_MAP_TYPE) - 1;
83a177fc2bSAndrii Nakryiko if ((token->allowed_maps & mask) == mask)
84a177fc2bSAndrii Nakryiko seq_printf(m, "allowed_maps:\tany\n");
85a177fc2bSAndrii Nakryiko else
86a177fc2bSAndrii Nakryiko seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps);
87caf8f28eSAndrii Nakryiko
88caf8f28eSAndrii Nakryiko BUILD_BUG_ON(__MAX_BPF_PROG_TYPE >= 64);
89*6668e818SHaiyue Wang mask = BIT_ULL(__MAX_BPF_PROG_TYPE) - 1;
90caf8f28eSAndrii Nakryiko if ((token->allowed_progs & mask) == mask)
91caf8f28eSAndrii Nakryiko seq_printf(m, "allowed_progs:\tany\n");
92caf8f28eSAndrii Nakryiko else
93caf8f28eSAndrii Nakryiko seq_printf(m, "allowed_progs:\t0x%llx\n", token->allowed_progs);
94caf8f28eSAndrii Nakryiko
95caf8f28eSAndrii Nakryiko BUILD_BUG_ON(__MAX_BPF_ATTACH_TYPE >= 64);
96*6668e818SHaiyue Wang mask = BIT_ULL(__MAX_BPF_ATTACH_TYPE) - 1;
97caf8f28eSAndrii Nakryiko if ((token->allowed_attachs & mask) == mask)
98caf8f28eSAndrii Nakryiko seq_printf(m, "allowed_attachs:\tany\n");
99caf8f28eSAndrii Nakryiko else
100caf8f28eSAndrii Nakryiko seq_printf(m, "allowed_attachs:\t0x%llx\n", token->allowed_attachs);
10135f96de0SAndrii Nakryiko }
10235f96de0SAndrii Nakryiko
10335f96de0SAndrii Nakryiko #define BPF_TOKEN_INODE_NAME "bpf-token"
10435f96de0SAndrii Nakryiko
10535f96de0SAndrii Nakryiko static const struct inode_operations bpf_token_iops = { };
10635f96de0SAndrii Nakryiko
10735f96de0SAndrii Nakryiko static const struct file_operations bpf_token_fops = {
10835f96de0SAndrii Nakryiko .release = bpf_token_release,
10935f96de0SAndrii Nakryiko .show_fdinfo = bpf_token_show_fdinfo,
11035f96de0SAndrii Nakryiko };
11135f96de0SAndrii Nakryiko
bpf_token_create(union bpf_attr * attr)11235f96de0SAndrii Nakryiko int bpf_token_create(union bpf_attr *attr)
11335f96de0SAndrii Nakryiko {
11435f96de0SAndrii Nakryiko struct bpf_mount_opts *mnt_opts;
11535f96de0SAndrii Nakryiko struct bpf_token *token = NULL;
11635f96de0SAndrii Nakryiko struct user_namespace *userns;
11735f96de0SAndrii Nakryiko struct inode *inode;
11835f96de0SAndrii Nakryiko struct file *file;
11935f96de0SAndrii Nakryiko struct path path;
12035f96de0SAndrii Nakryiko struct fd f;
12135f96de0SAndrii Nakryiko umode_t mode;
12235f96de0SAndrii Nakryiko int err, fd;
12335f96de0SAndrii Nakryiko
12435f96de0SAndrii Nakryiko f = fdget(attr->token_create.bpffs_fd);
12535f96de0SAndrii Nakryiko if (!f.file)
12635f96de0SAndrii Nakryiko return -EBADF;
12735f96de0SAndrii Nakryiko
12835f96de0SAndrii Nakryiko path = f.file->f_path;
12935f96de0SAndrii Nakryiko path_get(&path);
13035f96de0SAndrii Nakryiko fdput(f);
13135f96de0SAndrii Nakryiko
13235f96de0SAndrii Nakryiko if (path.dentry != path.mnt->mnt_sb->s_root) {
13335f96de0SAndrii Nakryiko err = -EINVAL;
13435f96de0SAndrii Nakryiko goto out_path;
13535f96de0SAndrii Nakryiko }
13635f96de0SAndrii Nakryiko if (path.mnt->mnt_sb->s_op != &bpf_super_ops) {
13735f96de0SAndrii Nakryiko err = -EINVAL;
13835f96de0SAndrii Nakryiko goto out_path;
13935f96de0SAndrii Nakryiko }
14035f96de0SAndrii Nakryiko err = path_permission(&path, MAY_ACCESS);
14135f96de0SAndrii Nakryiko if (err)
14235f96de0SAndrii Nakryiko goto out_path;
14335f96de0SAndrii Nakryiko
14435f96de0SAndrii Nakryiko userns = path.dentry->d_sb->s_user_ns;
14535f96de0SAndrii Nakryiko /*
14635f96de0SAndrii Nakryiko * Enforce that creators of BPF tokens are in the same user
14735f96de0SAndrii Nakryiko * namespace as the BPF FS instance. This makes reasoning about
14835f96de0SAndrii Nakryiko * permissions a lot easier and we can always relax this later.
14935f96de0SAndrii Nakryiko */
15035f96de0SAndrii Nakryiko if (current_user_ns() != userns) {
15135f96de0SAndrii Nakryiko err = -EPERM;
15235f96de0SAndrii Nakryiko goto out_path;
15335f96de0SAndrii Nakryiko }
15435f96de0SAndrii Nakryiko if (!ns_capable(userns, CAP_BPF)) {
15535f96de0SAndrii Nakryiko err = -EPERM;
15635f96de0SAndrii Nakryiko goto out_path;
15735f96de0SAndrii Nakryiko }
15835f96de0SAndrii Nakryiko
15935f96de0SAndrii Nakryiko /* Creating BPF token in init_user_ns doesn't make much sense. */
16035f96de0SAndrii Nakryiko if (current_user_ns() == &init_user_ns) {
16135f96de0SAndrii Nakryiko err = -EOPNOTSUPP;
16235f96de0SAndrii Nakryiko goto out_path;
16335f96de0SAndrii Nakryiko }
16435f96de0SAndrii Nakryiko
165aeaa97b0SAndrii Nakryiko mnt_opts = path.dentry->d_sb->s_fs_info;
166aeaa97b0SAndrii Nakryiko if (mnt_opts->delegate_cmds == 0 &&
167aeaa97b0SAndrii Nakryiko mnt_opts->delegate_maps == 0 &&
168aeaa97b0SAndrii Nakryiko mnt_opts->delegate_progs == 0 &&
169aeaa97b0SAndrii Nakryiko mnt_opts->delegate_attachs == 0) {
170aeaa97b0SAndrii Nakryiko err = -ENOENT; /* no BPF token delegation is set up */
171aeaa97b0SAndrii Nakryiko goto out_path;
172aeaa97b0SAndrii Nakryiko }
173aeaa97b0SAndrii Nakryiko
17435f96de0SAndrii Nakryiko mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask());
17535f96de0SAndrii Nakryiko inode = bpf_get_inode(path.mnt->mnt_sb, NULL, mode);
17635f96de0SAndrii Nakryiko if (IS_ERR(inode)) {
17735f96de0SAndrii Nakryiko err = PTR_ERR(inode);
17835f96de0SAndrii Nakryiko goto out_path;
17935f96de0SAndrii Nakryiko }
18035f96de0SAndrii Nakryiko
18135f96de0SAndrii Nakryiko inode->i_op = &bpf_token_iops;
18235f96de0SAndrii Nakryiko inode->i_fop = &bpf_token_fops;
18335f96de0SAndrii Nakryiko clear_nlink(inode); /* make sure it is unlinked */
18435f96de0SAndrii Nakryiko
18535f96de0SAndrii Nakryiko file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops);
18635f96de0SAndrii Nakryiko if (IS_ERR(file)) {
18735f96de0SAndrii Nakryiko iput(inode);
18835f96de0SAndrii Nakryiko err = PTR_ERR(file);
18935f96de0SAndrii Nakryiko goto out_path;
19035f96de0SAndrii Nakryiko }
19135f96de0SAndrii Nakryiko
19235f96de0SAndrii Nakryiko token = kzalloc(sizeof(*token), GFP_USER);
19335f96de0SAndrii Nakryiko if (!token) {
19435f96de0SAndrii Nakryiko err = -ENOMEM;
19535f96de0SAndrii Nakryiko goto out_file;
19635f96de0SAndrii Nakryiko }
19735f96de0SAndrii Nakryiko
19835f96de0SAndrii Nakryiko atomic64_set(&token->refcnt, 1);
19935f96de0SAndrii Nakryiko
20035f96de0SAndrii Nakryiko /* remember bpffs owning userns for future ns_capable() checks */
20135f96de0SAndrii Nakryiko token->userns = get_user_ns(userns);
20235f96de0SAndrii Nakryiko
20335f96de0SAndrii Nakryiko token->allowed_cmds = mnt_opts->delegate_cmds;
204a177fc2bSAndrii Nakryiko token->allowed_maps = mnt_opts->delegate_maps;
205caf8f28eSAndrii Nakryiko token->allowed_progs = mnt_opts->delegate_progs;
206caf8f28eSAndrii Nakryiko token->allowed_attachs = mnt_opts->delegate_attachs;
20735f96de0SAndrii Nakryiko
208f568a3d4SAndrii Nakryiko err = security_bpf_token_create(token, attr, &path);
209f568a3d4SAndrii Nakryiko if (err)
210f568a3d4SAndrii Nakryiko goto out_token;
211f568a3d4SAndrii Nakryiko
21235f96de0SAndrii Nakryiko fd = get_unused_fd_flags(O_CLOEXEC);
21335f96de0SAndrii Nakryiko if (fd < 0) {
21435f96de0SAndrii Nakryiko err = fd;
21535f96de0SAndrii Nakryiko goto out_token;
21635f96de0SAndrii Nakryiko }
21735f96de0SAndrii Nakryiko
21835f96de0SAndrii Nakryiko file->private_data = token;
21935f96de0SAndrii Nakryiko fd_install(fd, file);
22035f96de0SAndrii Nakryiko
22135f96de0SAndrii Nakryiko path_put(&path);
22235f96de0SAndrii Nakryiko return fd;
22335f96de0SAndrii Nakryiko
22435f96de0SAndrii Nakryiko out_token:
22535f96de0SAndrii Nakryiko bpf_token_free(token);
22635f96de0SAndrii Nakryiko out_file:
22735f96de0SAndrii Nakryiko fput(file);
22835f96de0SAndrii Nakryiko out_path:
22935f96de0SAndrii Nakryiko path_put(&path);
23035f96de0SAndrii Nakryiko return err;
23135f96de0SAndrii Nakryiko }
23235f96de0SAndrii Nakryiko
bpf_token_get_from_fd(u32 ufd)23335f96de0SAndrii Nakryiko struct bpf_token *bpf_token_get_from_fd(u32 ufd)
23435f96de0SAndrii Nakryiko {
23535f96de0SAndrii Nakryiko struct fd f = fdget(ufd);
23635f96de0SAndrii Nakryiko struct bpf_token *token;
23735f96de0SAndrii Nakryiko
23835f96de0SAndrii Nakryiko if (!f.file)
23935f96de0SAndrii Nakryiko return ERR_PTR(-EBADF);
24035f96de0SAndrii Nakryiko if (f.file->f_op != &bpf_token_fops) {
24135f96de0SAndrii Nakryiko fdput(f);
24235f96de0SAndrii Nakryiko return ERR_PTR(-EINVAL);
24335f96de0SAndrii Nakryiko }
24435f96de0SAndrii Nakryiko
24535f96de0SAndrii Nakryiko token = f.file->private_data;
24635f96de0SAndrii Nakryiko bpf_token_inc(token);
24735f96de0SAndrii Nakryiko fdput(f);
24835f96de0SAndrii Nakryiko
24935f96de0SAndrii Nakryiko return token;
25035f96de0SAndrii Nakryiko }
25135f96de0SAndrii Nakryiko
bpf_token_allow_cmd(const struct bpf_token * token,enum bpf_cmd cmd)25235f96de0SAndrii Nakryiko bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd)
25335f96de0SAndrii Nakryiko {
25435f96de0SAndrii Nakryiko if (!token)
25535f96de0SAndrii Nakryiko return false;
256*6668e818SHaiyue Wang if (!(token->allowed_cmds & BIT_ULL(cmd)))
257f568a3d4SAndrii Nakryiko return false;
258f568a3d4SAndrii Nakryiko return security_bpf_token_cmd(token, cmd) == 0;
25935f96de0SAndrii Nakryiko }
260a177fc2bSAndrii Nakryiko
bpf_token_allow_map_type(const struct bpf_token * token,enum bpf_map_type type)261a177fc2bSAndrii Nakryiko bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type)
262a177fc2bSAndrii Nakryiko {
263a177fc2bSAndrii Nakryiko if (!token || type >= __MAX_BPF_MAP_TYPE)
264a177fc2bSAndrii Nakryiko return false;
265a177fc2bSAndrii Nakryiko
266*6668e818SHaiyue Wang return token->allowed_maps & BIT_ULL(type);
267a177fc2bSAndrii Nakryiko }
268caf8f28eSAndrii Nakryiko
bpf_token_allow_prog_type(const struct bpf_token * token,enum bpf_prog_type prog_type,enum bpf_attach_type attach_type)269caf8f28eSAndrii Nakryiko bool bpf_token_allow_prog_type(const struct bpf_token *token,
270caf8f28eSAndrii Nakryiko enum bpf_prog_type prog_type,
271caf8f28eSAndrii Nakryiko enum bpf_attach_type attach_type)
272caf8f28eSAndrii Nakryiko {
273caf8f28eSAndrii Nakryiko if (!token || prog_type >= __MAX_BPF_PROG_TYPE || attach_type >= __MAX_BPF_ATTACH_TYPE)
274caf8f28eSAndrii Nakryiko return false;
275caf8f28eSAndrii Nakryiko
276*6668e818SHaiyue Wang return (token->allowed_progs & BIT_ULL(prog_type)) &&
277*6668e818SHaiyue Wang (token->allowed_attachs & BIT_ULL(attach_type));
278caf8f28eSAndrii Nakryiko }
279