[PATCH 2/3] lsm: add the security_mmap_backing_file() hook
Paul Moore <[email protected]>
| Newsgroups | org.kernel.vger.linux-unionfs,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-security-module,org.kernel.vger.selinux,org.ozlabs.lists.linux-erofs |
|---|---|
| Message-ID | <[email protected]> |
Add the security_mmap_backing_file() hook to allow LSMs to properly enforce access controls on mmap() operations on stacked filesystems such as overlayfs. The existing security_mmap_file() hook exists as an access control point for mmap() but on stacked filesystems it only provides a way to enforce access controls on the user visible file. In order to enforce access controls on the underlying backing file, the new security_mmap_backing_file() hook is needed. In addition the LSM hook additions, this patch also constifies the file struct field in the LSM common_audit_data struct to better support LSMs that will likely need to pass a const file struct pointer from the new backing_file_user_path_file() API into the common LSM audit code. Reviewed-by: Amir Goldstein <[email protected]> Signed-off-by: Paul Moore <[email protected]> --- fs/backing-file.c | 8 +++++++- fs/erofs/ishare.c | 6 ++++++ include/linux/lsm_audit.h | 2 +- include/linux/lsm_hook_defs.h | 2 ++ include/linux/security.h | 10 ++++++++++ security/security.c | 25 +++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-) diff --git a/fs/backing-file.c b/fs/backing-file.c index acabeea7efff..cfc7f6611313 100644 --- a/fs/backing-file.c +++ b/fs/backing-file.c @@ -13,6 +13,7 @@ #include <linux/splice.h> #include <linux/uio.h> #include <linux/mm.h> +#include <linux/security.h> #include "internal.h" @@ -338,8 +339,13 @@ int backing_file_mmap(struct file *file, struct vm_area_struct *vma, vma_set_file(vma, file); - scoped_with_creds(ctx->cred) + scoped_with_creds(ctx->cred) { + ret = security_mmap_backing_file(vma, file, user_file); + if (ret) + return ret; + ret = vfs_mmap(vma->vm_file, vma); + } if (ctx->accessed) ctx->accessed(user_file); diff --git a/fs/erofs/ishare.c b/fs/erofs/ishare.c index 17a4941d4518..d66c3a935d83 100644 --- a/fs/erofs/ishare.c +++ b/fs/erofs/ishare.c @@ -150,8 +150,14 @@ static ssize_t erofs_ishare_file_read_iter(struct kiocb *iocb, static int erofs_ishare_mmap(struct file *file, struct vm_area_struct *vma) { struct file *realfile = file->private_data; + int err; vma_set_file(vma, realfile); + + err = security_mmap_backing_file(vma, realfile, file); + if (err) + return err; + return generic_file_readonly_mmap(file, vma); } diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 382c56a97bba..584db296e43b 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -94,7 +94,7 @@ struct common_audit_data { #endif char *kmod_name; struct lsm_ioctlop_audit *op; - struct file *file; + const struct file *file; struct lsm_ibpkey_audit *ibpkey; struct lsm_ibendport_audit *ibendport; int reason; diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h index 8c42b4bde09c..4150c50a0482 100644 --- a/include/linux/lsm_hook_defs.h +++ b/include/linux/lsm_hook_defs.h @@ -198,6 +198,8 @@ LSM_HOOK(int, 0, file_ioctl_compat, struct file *file, unsigned int cmd, LSM_HOOK(int, 0, mmap_addr, unsigned long addr) LSM_HOOK(int, 0, mmap_file, struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) +LSM_HOOK(int, 0, mmap_backing_file, struct vm_area_struct *vma, + struct file *backing_file, struct file *user_file) LSM_HOOK(int, 0, file_mprotect, struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot) LSM_HOOK(int, 0, file_lock, struct file *file, unsigned int cmd) diff --git a/include/linux/security.h b/include/linux/security.h index 83a646d72f6f..4017361d8cba 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -476,6 +476,9 @@ int security_file_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg); int security_mmap_file(struct file *file, unsigned long prot, unsigned long flags); +int security_mmap_backing_file(struct vm_area_struct *vma, + struct file *backing_file, + struct file *user_file); int security_mmap_addr(unsigned long addr); int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, unsigned long prot); @@ -1159,6 +1162,13 @@ static inline int security_mmap_file(struct file *file, unsigned long prot, return 0; } +static inline int security_mmap_backing_file(struct vm_area_struct *vma, + struct file *backing_file, + struct file *user_file) +{ + return 0; +} + static inline int security_mmap_addr(unsigned long addr) { return cap_mmap_addr(addr); diff --git a/security/security.c b/security/security.c index 67af9228c4e9..8d10b184ce25 100644 --- a/security/security.c +++ b/security/security.c @@ -2505,6 +2505,31 @@ int security_mmap_file(struct file *file, unsigned long prot, flags); } +/** + * security_mmap_backing_file - Check if mmap'ing a backing file is allowed + * @vma: the vm_area_struct for the mmap'd region + * @backing_file: the backing file being mmap'd + * @user_file: the user file being mmap'd + * + * Check permissions for a mmap operation on a stacked filesystem. This hook + * is called after the security_mmap_file() and is responsible for authorizing + * the mmap on @backing_file. It is important to note that the mmap operation + * on @user_file has already been authorized and the @vma->vm_file has been + * set to @backing_file. + * + * Return: Returns 0 if permission is granted. + */ +int security_mmap_backing_file(struct vm_area_struct *vma, + struct file *backing_file, + struct file *user_file) +{ + /* recommended by the stackable filesystem devs */ + if (WARN_ON_ONCE(!(backing_file->f_mode & FMODE_BACKING))) + return -EIO; + + return call_int_hook(mmap_backing_file, vma, backing_file, user_file); +} + /** * security_mmap_addr() - Check if mmap'ing an address is allowed * @addr: address -- 2.53.0