xref: /linux-6.15/kernel/bpf/token.c (revision be5498ca)
135f96de0SAndrii Nakryiko #include <linux/bpf.h>
235f96de0SAndrii Nakryiko #include <linux/vmalloc.h>
335f96de0SAndrii Nakryiko #include <linux/file.h>
435f96de0SAndrii Nakryiko #include <linux/fs.h>
535f96de0SAndrii Nakryiko #include <linux/kernel.h>
635f96de0SAndrii Nakryiko #include <linux/idr.h>
735f96de0SAndrii Nakryiko #include <linux/namei.h>
835f96de0SAndrii Nakryiko #include <linux/user_namespace.h>
9f568a3d4SAndrii Nakryiko #include <linux/security.h>
1035f96de0SAndrii Nakryiko 
bpf_ns_capable(struct user_namespace * ns,int cap)1135f96de0SAndrii Nakryiko static bool bpf_ns_capable(struct user_namespace *ns, int cap)
1235f96de0SAndrii Nakryiko {
1335f96de0SAndrii Nakryiko 	return ns_capable(ns, cap) || (cap != CAP_SYS_ADMIN && ns_capable(ns, CAP_SYS_ADMIN));
1435f96de0SAndrii Nakryiko }
1535f96de0SAndrii Nakryiko 
bpf_token_capable(const struct bpf_token * token,int cap)1635f96de0SAndrii Nakryiko bool bpf_token_capable(const struct bpf_token *token, int cap)
1735f96de0SAndrii Nakryiko {
1835f96de0SAndrii Nakryiko 	struct user_namespace *userns;
1935f96de0SAndrii Nakryiko 
2035f96de0SAndrii Nakryiko 	/* BPF token allows ns_capable() level of capabilities */
2135f96de0SAndrii Nakryiko 	userns = token ? token->userns : &init_user_ns;
2235f96de0SAndrii Nakryiko 	if (!bpf_ns_capable(userns, cap))
2335f96de0SAndrii Nakryiko 		return false;
24f568a3d4SAndrii Nakryiko 	if (token && security_bpf_token_capable(token, cap) < 0)
25f568a3d4SAndrii Nakryiko 		return false;
2635f96de0SAndrii Nakryiko 	return true;
2735f96de0SAndrii Nakryiko }
2835f96de0SAndrii Nakryiko 
bpf_token_inc(struct bpf_token * token)2935f96de0SAndrii Nakryiko void bpf_token_inc(struct bpf_token *token)
3035f96de0SAndrii Nakryiko {
3135f96de0SAndrii Nakryiko 	atomic64_inc(&token->refcnt);
3235f96de0SAndrii Nakryiko }
3335f96de0SAndrii Nakryiko 
bpf_token_free(struct bpf_token * token)3435f96de0SAndrii Nakryiko static void bpf_token_free(struct bpf_token *token)
3535f96de0SAndrii Nakryiko {
36f568a3d4SAndrii Nakryiko 	security_bpf_token_free(token);
3735f96de0SAndrii Nakryiko 	put_user_ns(token->userns);
3835f96de0SAndrii Nakryiko 	kfree(token);
3935f96de0SAndrii Nakryiko }
4035f96de0SAndrii Nakryiko 
bpf_token_put_deferred(struct work_struct * work)4135f96de0SAndrii Nakryiko static void bpf_token_put_deferred(struct work_struct *work)
4235f96de0SAndrii Nakryiko {
4335f96de0SAndrii Nakryiko 	struct bpf_token *token = container_of(work, struct bpf_token, work);
4435f96de0SAndrii Nakryiko 
4535f96de0SAndrii Nakryiko 	bpf_token_free(token);
4635f96de0SAndrii Nakryiko }
4735f96de0SAndrii Nakryiko 
bpf_token_put(struct bpf_token * token)4835f96de0SAndrii Nakryiko void bpf_token_put(struct bpf_token *token)
4935f96de0SAndrii Nakryiko {
5035f96de0SAndrii Nakryiko 	if (!token)
5135f96de0SAndrii Nakryiko 		return;
5235f96de0SAndrii Nakryiko 
5335f96de0SAndrii Nakryiko 	if (!atomic64_dec_and_test(&token->refcnt))
5435f96de0SAndrii Nakryiko 		return;
5535f96de0SAndrii Nakryiko 
5635f96de0SAndrii Nakryiko 	INIT_WORK(&token->work, bpf_token_put_deferred);
5735f96de0SAndrii Nakryiko 	schedule_work(&token->work);
5835f96de0SAndrii Nakryiko }
5935f96de0SAndrii Nakryiko 
bpf_token_release(struct inode * inode,struct file * filp)6035f96de0SAndrii Nakryiko static int bpf_token_release(struct inode *inode, struct file *filp)
6135f96de0SAndrii Nakryiko {
6235f96de0SAndrii Nakryiko 	struct bpf_token *token = filp->private_data;
6335f96de0SAndrii Nakryiko 
6435f96de0SAndrii Nakryiko 	bpf_token_put(token);
6535f96de0SAndrii Nakryiko 	return 0;
6635f96de0SAndrii Nakryiko }
6735f96de0SAndrii Nakryiko 
bpf_token_show_fdinfo(struct seq_file * m,struct file * filp)6835f96de0SAndrii Nakryiko static void bpf_token_show_fdinfo(struct seq_file *m, struct file *filp)
6935f96de0SAndrii Nakryiko {
7035f96de0SAndrii Nakryiko 	struct bpf_token *token = filp->private_data;
7135f96de0SAndrii Nakryiko 	u64 mask;
7235f96de0SAndrii Nakryiko 
7335f96de0SAndrii Nakryiko 	BUILD_BUG_ON(__MAX_BPF_CMD >= 64);
746668e818SHaiyue Wang 	mask = BIT_ULL(__MAX_BPF_CMD) - 1;
7535f96de0SAndrii Nakryiko 	if ((token->allowed_cmds & mask) == mask)
7635f96de0SAndrii Nakryiko 		seq_printf(m, "allowed_cmds:\tany\n");
7735f96de0SAndrii Nakryiko 	else
7835f96de0SAndrii Nakryiko 		seq_printf(m, "allowed_cmds:\t0x%llx\n", token->allowed_cmds);
79a177fc2bSAndrii Nakryiko 
80a177fc2bSAndrii Nakryiko 	BUILD_BUG_ON(__MAX_BPF_MAP_TYPE >= 64);
816668e818SHaiyue Wang 	mask = BIT_ULL(__MAX_BPF_MAP_TYPE) - 1;
82a177fc2bSAndrii Nakryiko 	if ((token->allowed_maps & mask) == mask)
83a177fc2bSAndrii Nakryiko 		seq_printf(m, "allowed_maps:\tany\n");
84a177fc2bSAndrii Nakryiko 	else
85a177fc2bSAndrii Nakryiko 		seq_printf(m, "allowed_maps:\t0x%llx\n", token->allowed_maps);
86caf8f28eSAndrii Nakryiko 
87caf8f28eSAndrii Nakryiko 	BUILD_BUG_ON(__MAX_BPF_PROG_TYPE >= 64);
886668e818SHaiyue Wang 	mask = BIT_ULL(__MAX_BPF_PROG_TYPE) - 1;
89caf8f28eSAndrii Nakryiko 	if ((token->allowed_progs & mask) == mask)
90caf8f28eSAndrii Nakryiko 		seq_printf(m, "allowed_progs:\tany\n");
91caf8f28eSAndrii Nakryiko 	else
92caf8f28eSAndrii Nakryiko 		seq_printf(m, "allowed_progs:\t0x%llx\n", token->allowed_progs);
93caf8f28eSAndrii Nakryiko 
94caf8f28eSAndrii Nakryiko 	BUILD_BUG_ON(__MAX_BPF_ATTACH_TYPE >= 64);
956668e818SHaiyue Wang 	mask = BIT_ULL(__MAX_BPF_ATTACH_TYPE) - 1;
96caf8f28eSAndrii Nakryiko 	if ((token->allowed_attachs & mask) == mask)
97caf8f28eSAndrii Nakryiko 		seq_printf(m, "allowed_attachs:\tany\n");
98caf8f28eSAndrii Nakryiko 	else
99caf8f28eSAndrii Nakryiko 		seq_printf(m, "allowed_attachs:\t0x%llx\n", token->allowed_attachs);
10035f96de0SAndrii Nakryiko }
10135f96de0SAndrii Nakryiko 
10235f96de0SAndrii Nakryiko #define BPF_TOKEN_INODE_NAME "bpf-token"
10335f96de0SAndrii Nakryiko 
10435f96de0SAndrii Nakryiko static const struct inode_operations bpf_token_iops = { };
10535f96de0SAndrii Nakryiko 
10635f96de0SAndrii Nakryiko static const struct file_operations bpf_token_fops = {
10735f96de0SAndrii Nakryiko 	.release	= bpf_token_release,
10835f96de0SAndrii Nakryiko 	.show_fdinfo	= bpf_token_show_fdinfo,
10935f96de0SAndrii Nakryiko };
11035f96de0SAndrii Nakryiko 
bpf_token_create(union bpf_attr * attr)11135f96de0SAndrii Nakryiko int bpf_token_create(union bpf_attr *attr)
11235f96de0SAndrii Nakryiko {
11335f96de0SAndrii Nakryiko 	struct bpf_mount_opts *mnt_opts;
11435f96de0SAndrii Nakryiko 	struct bpf_token *token = NULL;
11535f96de0SAndrii Nakryiko 	struct user_namespace *userns;
11635f96de0SAndrii Nakryiko 	struct inode *inode;
11735f96de0SAndrii Nakryiko 	struct file *file;
118*37d3dd66SAl Viro 	CLASS(fd, f)(attr->token_create.bpffs_fd);
11935f96de0SAndrii Nakryiko 	struct path path;
120*37d3dd66SAl Viro 	struct super_block *sb;
12135f96de0SAndrii Nakryiko 	umode_t mode;
12235f96de0SAndrii Nakryiko 	int err, fd;
12335f96de0SAndrii Nakryiko 
124*37d3dd66SAl Viro 	if (fd_empty(f))
12535f96de0SAndrii Nakryiko 		return -EBADF;
12635f96de0SAndrii Nakryiko 
1271da91ea8SAl Viro 	path = fd_file(f)->f_path;
128*37d3dd66SAl Viro 	sb = path.dentry->d_sb;
12935f96de0SAndrii Nakryiko 
130*37d3dd66SAl Viro 	if (path.dentry != sb->s_root)
131*37d3dd66SAl Viro 		return -EINVAL;
132*37d3dd66SAl Viro 	if (sb->s_op != &bpf_super_ops)
133*37d3dd66SAl Viro 		return -EINVAL;
13435f96de0SAndrii Nakryiko 	err = path_permission(&path, MAY_ACCESS);
13535f96de0SAndrii Nakryiko 	if (err)
136*37d3dd66SAl Viro 		return err;
13735f96de0SAndrii Nakryiko 
138*37d3dd66SAl Viro 	userns = sb->s_user_ns;
13935f96de0SAndrii Nakryiko 	/*
14035f96de0SAndrii Nakryiko 	 * Enforce that creators of BPF tokens are in the same user
14135f96de0SAndrii Nakryiko 	 * namespace as the BPF FS instance. This makes reasoning about
14235f96de0SAndrii Nakryiko 	 * permissions a lot easier and we can always relax this later.
14335f96de0SAndrii Nakryiko 	 */
144*37d3dd66SAl Viro 	if (current_user_ns() != userns)
145*37d3dd66SAl Viro 		return -EPERM;
146*37d3dd66SAl Viro 	if (!ns_capable(userns, CAP_BPF))
147*37d3dd66SAl Viro 		return -EPERM;
14835f96de0SAndrii Nakryiko 
14935f96de0SAndrii Nakryiko 	/* Creating BPF token in init_user_ns doesn't make much sense. */
150*37d3dd66SAl Viro 	if (current_user_ns() == &init_user_ns)
151*37d3dd66SAl Viro 		return -EOPNOTSUPP;
15235f96de0SAndrii Nakryiko 
153*37d3dd66SAl Viro 	mnt_opts = sb->s_fs_info;
154aeaa97b0SAndrii Nakryiko 	if (mnt_opts->delegate_cmds == 0 &&
155aeaa97b0SAndrii Nakryiko 	    mnt_opts->delegate_maps == 0 &&
156aeaa97b0SAndrii Nakryiko 	    mnt_opts->delegate_progs == 0 &&
157*37d3dd66SAl Viro 	    mnt_opts->delegate_attachs == 0)
158*37d3dd66SAl Viro 		return -ENOENT; /* no BPF token delegation is set up */
159aeaa97b0SAndrii Nakryiko 
16035f96de0SAndrii Nakryiko 	mode = S_IFREG | ((S_IRUSR | S_IWUSR) & ~current_umask());
161*37d3dd66SAl Viro 	inode = bpf_get_inode(sb, NULL, mode);
162*37d3dd66SAl Viro 	if (IS_ERR(inode))
163*37d3dd66SAl Viro 		return PTR_ERR(inode);
16435f96de0SAndrii Nakryiko 
16535f96de0SAndrii Nakryiko 	inode->i_op = &bpf_token_iops;
16635f96de0SAndrii Nakryiko 	inode->i_fop = &bpf_token_fops;
16735f96de0SAndrii Nakryiko 	clear_nlink(inode); /* make sure it is unlinked */
16835f96de0SAndrii Nakryiko 
16935f96de0SAndrii Nakryiko 	file = alloc_file_pseudo(inode, path.mnt, BPF_TOKEN_INODE_NAME, O_RDWR, &bpf_token_fops);
17035f96de0SAndrii Nakryiko 	if (IS_ERR(file)) {
17135f96de0SAndrii Nakryiko 		iput(inode);
172*37d3dd66SAl Viro 		return PTR_ERR(file);
17335f96de0SAndrii Nakryiko 	}
17435f96de0SAndrii Nakryiko 
17535f96de0SAndrii Nakryiko 	token = kzalloc(sizeof(*token), GFP_USER);
17635f96de0SAndrii Nakryiko 	if (!token) {
17735f96de0SAndrii Nakryiko 		err = -ENOMEM;
17835f96de0SAndrii Nakryiko 		goto out_file;
17935f96de0SAndrii Nakryiko 	}
18035f96de0SAndrii Nakryiko 
18135f96de0SAndrii Nakryiko 	atomic64_set(&token->refcnt, 1);
18235f96de0SAndrii Nakryiko 
18335f96de0SAndrii Nakryiko 	/* remember bpffs owning userns for future ns_capable() checks */
18435f96de0SAndrii Nakryiko 	token->userns = get_user_ns(userns);
18535f96de0SAndrii Nakryiko 
18635f96de0SAndrii Nakryiko 	token->allowed_cmds = mnt_opts->delegate_cmds;
187a177fc2bSAndrii Nakryiko 	token->allowed_maps = mnt_opts->delegate_maps;
188caf8f28eSAndrii Nakryiko 	token->allowed_progs = mnt_opts->delegate_progs;
189caf8f28eSAndrii Nakryiko 	token->allowed_attachs = mnt_opts->delegate_attachs;
19035f96de0SAndrii Nakryiko 
191f568a3d4SAndrii Nakryiko 	err = security_bpf_token_create(token, attr, &path);
192f568a3d4SAndrii Nakryiko 	if (err)
193f568a3d4SAndrii Nakryiko 		goto out_token;
194f568a3d4SAndrii Nakryiko 
19535f96de0SAndrii Nakryiko 	fd = get_unused_fd_flags(O_CLOEXEC);
19635f96de0SAndrii Nakryiko 	if (fd < 0) {
19735f96de0SAndrii Nakryiko 		err = fd;
19835f96de0SAndrii Nakryiko 		goto out_token;
19935f96de0SAndrii Nakryiko 	}
20035f96de0SAndrii Nakryiko 
20135f96de0SAndrii Nakryiko 	file->private_data = token;
20235f96de0SAndrii Nakryiko 	fd_install(fd, file);
20335f96de0SAndrii Nakryiko 
20435f96de0SAndrii Nakryiko 	return fd;
20535f96de0SAndrii Nakryiko 
20635f96de0SAndrii Nakryiko out_token:
20735f96de0SAndrii Nakryiko 	bpf_token_free(token);
20835f96de0SAndrii Nakryiko out_file:
20935f96de0SAndrii Nakryiko 	fput(file);
21035f96de0SAndrii Nakryiko 	return err;
21135f96de0SAndrii Nakryiko }
21235f96de0SAndrii Nakryiko 
bpf_token_get_from_fd(u32 ufd)21335f96de0SAndrii Nakryiko struct bpf_token *bpf_token_get_from_fd(u32 ufd)
21435f96de0SAndrii Nakryiko {
215eb80ee85SAl Viro 	CLASS(fd, f)(ufd);
21635f96de0SAndrii Nakryiko 	struct bpf_token *token;
21735f96de0SAndrii Nakryiko 
218eb80ee85SAl Viro 	if (fd_empty(f))
21935f96de0SAndrii Nakryiko 		return ERR_PTR(-EBADF);
220eb80ee85SAl Viro 	if (fd_file(f)->f_op != &bpf_token_fops)
22135f96de0SAndrii Nakryiko 		return ERR_PTR(-EINVAL);
22235f96de0SAndrii Nakryiko 
2231da91ea8SAl Viro 	token = fd_file(f)->private_data;
22435f96de0SAndrii Nakryiko 	bpf_token_inc(token);
22535f96de0SAndrii Nakryiko 
22635f96de0SAndrii Nakryiko 	return token;
22735f96de0SAndrii Nakryiko }
22835f96de0SAndrii Nakryiko 
bpf_token_allow_cmd(const struct bpf_token * token,enum bpf_cmd cmd)22935f96de0SAndrii Nakryiko bool bpf_token_allow_cmd(const struct bpf_token *token, enum bpf_cmd cmd)
23035f96de0SAndrii Nakryiko {
23135f96de0SAndrii Nakryiko 	if (!token)
23235f96de0SAndrii Nakryiko 		return false;
2336668e818SHaiyue Wang 	if (!(token->allowed_cmds & BIT_ULL(cmd)))
234f568a3d4SAndrii Nakryiko 		return false;
235f568a3d4SAndrii Nakryiko 	return security_bpf_token_cmd(token, cmd) == 0;
23635f96de0SAndrii Nakryiko }
237a177fc2bSAndrii Nakryiko 
bpf_token_allow_map_type(const struct bpf_token * token,enum bpf_map_type type)238a177fc2bSAndrii Nakryiko bool bpf_token_allow_map_type(const struct bpf_token *token, enum bpf_map_type type)
239a177fc2bSAndrii Nakryiko {
240a177fc2bSAndrii Nakryiko 	if (!token || type >= __MAX_BPF_MAP_TYPE)
241a177fc2bSAndrii Nakryiko 		return false;
242a177fc2bSAndrii Nakryiko 
2436668e818SHaiyue Wang 	return token->allowed_maps & BIT_ULL(type);
244a177fc2bSAndrii Nakryiko }
245caf8f28eSAndrii Nakryiko 
bpf_token_allow_prog_type(const struct bpf_token * token,enum bpf_prog_type prog_type,enum bpf_attach_type attach_type)246caf8f28eSAndrii Nakryiko bool bpf_token_allow_prog_type(const struct bpf_token *token,
247caf8f28eSAndrii Nakryiko 			       enum bpf_prog_type prog_type,
248caf8f28eSAndrii Nakryiko 			       enum bpf_attach_type attach_type)
249caf8f28eSAndrii Nakryiko {
250caf8f28eSAndrii Nakryiko 	if (!token || prog_type >= __MAX_BPF_PROG_TYPE || attach_type >= __MAX_BPF_ATTACH_TYPE)
251caf8f28eSAndrii Nakryiko 		return false;
252caf8f28eSAndrii Nakryiko 
2536668e818SHaiyue Wang 	return (token->allowed_progs & BIT_ULL(prog_type)) &&
2546668e818SHaiyue Wang 	       (token->allowed_attachs & BIT_ULL(attach_type));
255caf8f28eSAndrii Nakryiko }
256