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