On Monday, January 30, 2023 1:26 PM, Ackerley Tng wrote:
quoted hunk ↗ jump to hunk
quoted
+static int restrictedmem_getattr(struct user_namespace *mnt_userns,
+ const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int query_flags)
{quoted
+ struct inode *inode = d_inode(path->dentry);
+ struct restrictedmem_data *data = inode->i_mapping-
private_data;
+ struct file *memfd = data->memfd;
+
+ return memfd->f_inode->i_op->getattr(mnt_userns, path, stat,
+ request_mask, query_flags);
Instead of calling shmem's getattr() with path, we should be using the the
memfd's path.
Otherwise, shmem's getattr() will use restrictedmem's inode instead of
shmem's inode. The private fields will be of the wrong type, and the host will
crash when shmem_is_huge() does SHMEM_SB(inode->i_sb)->huge), since
inode->i_sb->s_fs_info is NULL for the restrictedmem's superblock.
Here's the patch:
diff --git a/mm/restrictedmem.c b/mm/restrictedmem.c index
37191cd9eed1..06b72d593bd8 100644
--- a/mm/restrictedmem.c
+++ b/mm/restrictedmem.c
@@ -84,7 +84,7 @@ static int restrictedmem_getattr(struct user_namespace
*mnt_userns,
struct restrictedmem *rm = inode->i_mapping->private_data;
struct file *memfd = rm->memfd;
- return memfd->f_inode->i_op->getattr(mnt_userns, path, stat,
+ return memfd->f_inode->i_op->getattr(mnt_userns, &memfd-
quoted
f_path, stat,
request_mask, query_flags);
}
Nice catch. I also encountered this issue during my work.
The fix can further be enforced by shmem:
index c301487be5fb..d850c0190359 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -472,8 +472,9 @@ bool shmem_is_huge(struct vm_area_struct *vma, struct inode *inode,
pgoff_t index, bool shmem_huge_force)
{
loff_t i_size;
+ struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
- if (!S_ISREG(inode->i_mode))
+ if (!sbinfo || !S_ISREG(inode->i_mode))
return false;
if (vma && ((vma->vm_flags & VM_NOHUGEPAGE) ||
test_bit(MMF_DISABLE_THP, &vma->vm_mm->flags)))@@ -485,7 +486,7 @@ bool shmem_is_huge(struct vm_area_struct *vma, struct inode *inode,
if (shmem_huge == SHMEM_HUGE_DENY)
return false;
- switch (SHMEM_SB(inode->i_sb)->huge) {
+ switch (sbinfo->huge) {
case SHMEM_HUGE_ALWAYS:
return true;
case SHMEM_HUGE_WITHIN_SIZE: