summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChenbo Feng <fengc@google.com>2017-10-18 13:00:26 -0700
committerMichael Bestas <mkbestas@lineageos.org>2022-04-19 00:51:16 +0300
commitaa9eba07a784fce6a9f2f21846c07424a442acb0 (patch)
tree49bb8a1c28c69d83147c58a621e26cedf72daa40
parent5dd97a8acaf41266d17eb2aa743f9e6dc6f5ffaf (diff)
UPSTREAM: selinux: bpf: Add addtional check for bpf object file receive
Introduce a bpf object related check when sending and receiving files through unix domain socket as well as binder. It checks if the receiving process have privilege to read/write the bpf map or use the bpf program. This check is necessary because the bpf maps and programs are using a anonymous inode as their shared inode so the normal way of checking the files and sockets when passing between processes cannot work properly on eBPF object. This check only works when the BPF_SYSCALL is configured. Signed-off-by: Chenbo Feng <fengc@google.com> Acked-by: Stephen Smalley <sds@tycho.nsa.gov> Reviewed-by: James Morris <james.l.morris@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net> (cherry-pick from net-next: f66e448cfda021b0bcd884f26709796fe19c7cc1) Bug: 30950746 Change-Id: I5b2cf4ccb4eab7eda91ddd7091d6aa3e7ed9f2cd Signed-off-by: Chatur27 <jasonbright2709@gmail.com>
-rw-r--r--include/linux/bpf.h3
-rw-r--r--kernel/bpf/syscall.c4
-rw-r--r--security/selinux/hooks.c49
3 files changed, 54 insertions, 2 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 7e8326737cd3..a5bf1eb76dc6 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -236,6 +236,9 @@ DECLARE_PER_CPU(int, bpf_prog_active);
void bpf_register_prog_type(struct bpf_prog_type_list *tl);
void bpf_register_map_type(struct bpf_map_type_list *tl);
+extern const struct file_operations bpf_map_fops;
+extern const struct file_operations bpf_prog_fops;
+
struct bpf_prog *bpf_prog_get(u32 ufd);
struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type);
struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 53dbfb4020f2..eaabb1333670 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -199,7 +199,7 @@ static ssize_t bpf_dummy_write(struct file *filp, const char __user *buf,
return -EINVAL;
}
-static const struct file_operations bpf_map_fops = {
+const struct file_operations bpf_map_fops = {
#ifdef CONFIG_PROC_FS
.show_fdinfo = bpf_map_show_fdinfo,
#endif
@@ -748,7 +748,7 @@ static int bpf_prog_release(struct inode *inode, struct file *filp)
return 0;
}
-static const struct file_operations bpf_prog_fops = {
+const struct file_operations bpf_prog_fops = {
.release = bpf_prog_release,
.read = bpf_dummy_read,
.write = bpf_dummy_write,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3c85ed05b889..65adfa63f118 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1681,6 +1681,10 @@ static inline int file_path_has_perm(const struct cred *cred,
return inode_has_perm(cred, file_inode(file), av, &ad);
}
+#ifdef CONFIG_BPF_SYSCALL
+static int bpf_fd_pass(struct file *file, u32 sid);
+#endif
+
/* Check whether a task can use an open file descriptor to
access an inode in a given way. Check access to the
descriptor itself, and then use dentry_has_perm to
@@ -1711,6 +1715,12 @@ static int file_has_perm(const struct cred *cred,
goto out;
}
+#ifdef CONFIG_BPF_SYSCALL
+ rc = bpf_fd_pass(file, cred_sid(cred));
+ if (rc)
+ return rc;
+#endif
+
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
@@ -2034,6 +2044,12 @@ static int selinux_binder_transfer_file(const struct cred *from,
return rc;
}
+#ifdef CONFIG_BPF_SYSCALL
+ rc = bpf_fd_pass(file, sid);
+ if (rc)
+ return rc;
+#endif
+
if (unlikely(IS_PRIVATE(inode)))
return 0;
@@ -5963,6 +5979,39 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
return av;
}
+/* This function will check the file pass through unix socket or binder to see
+ * if it is a bpf related object. And apply correspinding checks on the bpf
+ * object based on the type. The bpf maps and programs, not like other files and
+ * socket, are using a shared anonymous inode inside the kernel as their inode.
+ * So checking that inode cannot identify if the process have privilege to
+ * access the bpf object and that's why we have to add this additional check in
+ * selinux_file_receive and selinux_binder_transfer_files.
+ */
+static int bpf_fd_pass(struct file *file, u32 sid)
+{
+ struct bpf_security_struct *bpfsec;
+ struct bpf_prog *prog;
+ struct bpf_map *map;
+ int ret;
+
+ if (file->f_op == &bpf_map_fops) {
+ map = file->private_data;
+ bpfsec = map->security;
+ ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ bpf_map_fmode_to_av(file->f_mode), NULL);
+ if (ret)
+ return ret;
+ } else if (file->f_op == &bpf_prog_fops) {
+ prog = file->private_data;
+ bpfsec = prog->aux->security;
+ ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ BPF__PROG_RUN, NULL);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
{
u32 sid = current_sid();