xref: /linux/kernel/bpf/token.c (revision 6668e818)
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