[PATCH v1 13/14] mm/mshare: Enforce mshare'd region permissions

From: Khalid Aziz
Date: Mon Apr 11 2022 - 12:09:37 EST


When a process creates an mshare region, it specifies permissions
allowed for others to access this region as well as permissions
for the file to be created in msharefs that allows other processes
to get information on mshare'd region. Ensure those permissions
are enforced for other tasks accessing this region.

Signed-off-by: Khalid Aziz <khalid.aziz@xxxxxxxxxx>
---
mm/mshare.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/mm/mshare.c b/mm/mshare.c
index 88c7cefc933d..fba31f3c190f 100644
--- a/mm/mshare.c
+++ b/mm/mshare.c
@@ -24,7 +24,7 @@

struct mshare_data {
struct mm_struct *mm, *host_mm;
- mode_t mode;
+ int flags;
refcount_t refcnt;
};

@@ -131,7 +131,7 @@ static struct dentry
}

static struct inode
-*msharefs_get_inode(struct super_block *sb, int mode)
+*msharefs_get_inode(struct super_block *sb, mode_t mode)
{
struct inode *inode = new_inode(sb);

@@ -161,19 +161,22 @@ static struct inode
}

static int
-mshare_file_create(struct filename *fname, int flags,
+mshare_file_create(struct filename *fname, mode_t mode,
struct mshare_data *info)
{
struct inode *inode;
struct dentry *root, *dentry;
int err = 0;
+ mode_t fmode;

root = msharefs_sb->s_root;

/*
- * This is a read only file.
+ * This is a read only file so mask out all other bits. Make sure
+ * it is readable by owner at least.
*/
- inode = msharefs_get_inode(msharefs_sb, S_IFREG | 0400);
+ fmode = (mode & 0444) | S_IFREG | 0400;
+ inode = msharefs_get_inode(msharefs_sb, fmode);
if (IS_ERR(inode))
return PTR_ERR(inode);

@@ -247,6 +250,7 @@ SYSCALL_DEFINE5(mshare, const char __user *, name, unsigned long, addr,
dput(dentry);
goto err_unlock_inode;
}
+ oflag &= (O_RDONLY | O_WRONLY | O_RDWR);

if (dentry) {
unsigned long mapaddr, prot = PROT_NONE;
@@ -276,7 +280,11 @@ SYSCALL_DEFINE5(mshare, const char __user *, name, unsigned long, addr,
/*
* Map in the address range as anonymous mappings
*/
- oflag &= (O_RDONLY | O_WRONLY | O_RDWR);
+ if (oflag != (oflag & info->flags)) {
+ err = -EPERM;
+ goto err_unlock_inode;
+ }
+
if (oflag & O_RDONLY)
prot |= PROT_READ;
else if (oflag & O_WRONLY)
@@ -331,7 +339,7 @@ SYSCALL_DEFINE5(mshare, const char __user *, name, unsigned long, addr,
new_mm->task_size--;
info->mm = new_mm;
info->host_mm = old_mm;
- info->mode = mode;
+ info->flags = oflag;
refcount_set(&info->refcnt, 1);

/*
@@ -412,7 +420,7 @@ SYSCALL_DEFINE5(mshare, const char __user *, name, unsigned long, addr,
mmap_write_unlock(old_mm);
mmap_write_unlock(new_mm);

- err = mshare_file_create(fname, oflag, info);
+ err = mshare_file_create(fname, mode, info);
if (err)
goto free_info;
}
--
2.32.0