Re: [PATCH] ovl: fix mmap denywrite

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





Am 09.07.21 um 15:48 schrieb Miklos Szeredi:
On Wed, Jun 23, 2021 at 01:41:02PM +0200, Christian König wrote:

Am 22.06.21 um 17:10 schrieb Miklos Szeredi:
On Tue, 22 Jun 2021 at 14:43, Christian König <christian.koenig@xxxxxxx> wrote:
Am 22.06.21 um 14:30 schrieb Miklos Szeredi:
Overlayfs did not honor positive i_writecount on realfile for VM_DENYWRITE
mappings.  Similarly negative i_mmap_writable counts were ignored for
VM_SHARED mappings.

Fix by making vma_set_file() switch the temporary counts obtained and
released by mmap_region().
Mhm, I don't fully understand the background but that looks like
something specific to overlayfs to me.

So why are you changing the common helper?
Need to hold the temporary counts until the final ones are obtained in
vma_link(), which is out of overlayfs' scope.
Ah! So basically we need to move the denial counts which mmap_region() added
to the original file to the new one as well. That's indeed a rather good
point.

Can you rather change the vma_set_file() function to return the error and
add a __must_check?

I can take care fixing the users in DMA-buf and DRM subsystem.
Okay, but changing to __must_check has to be the last step to avoid compile
errors.  This v2 is with __must_check commented out.

Good point. Please ping me whenever that is upstream and I will take care of fixing all the callers in the DRM subsystem and DMA-buf


Thanks,
Miklos
---

From: Miklos Szeredi <mszeredi@xxxxxxxxxx>
Subject: [PATCH v2] ovl: fix mmap denywrite

Overlayfs did not honor positive i_writecount on realfile for VM_DENYWRITE
mappings.  Similarly negative i_mmap_writable counts were ignored for
VM_SHARED mappings.

Fix by making vma_set_file() switch the temporary counts obtained and
released by mmap_region().

Reported-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx>
Signed-off-by: Miklos Szeredi <mszeredi@xxxxxxxxxx>

Reviewed-by: Christian König <christian.koenig@xxxxxxx>

Regards,
Christian.

---
  fs/overlayfs/file.c |    4 +++-
  include/linux/mm.h  |    2 +-
  mm/mmap.c           |    2 +-
  mm/util.c           |   27 ++++++++++++++++++++++++++-
  4 files changed, 31 insertions(+), 4 deletions(-)

--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -430,7 +430,9 @@ static int ovl_mmap(struct file *file, s
  	if (WARN_ON(file != vma->vm_file))
  		return -EIO;
- vma_set_file(vma, realfile);
+	ret = vma_set_file(vma, realfile);
+	if (ret)
+		return ret;
old_cred = ovl_override_creds(file_inode(file)->i_sb);
  	ret = call_mmap(vma->vm_file, vma);
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2776,7 +2776,7 @@ static inline void vma_set_page_prot(str
  }
  #endif
-void vma_set_file(struct vm_area_struct *vma, struct file *file);
+int /* __must_check */ vma_set_file(struct vm_area_struct *vma, struct file *file);
#ifdef CONFIG_NUMA_BALANCING
  unsigned long change_prot_numa(struct vm_area_struct *vma,
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1807,6 +1807,7 @@ unsigned long mmap_region(struct file *f
  		 */
  		vma->vm_file = get_file(file);
  		error = call_mmap(file, vma);
+		file = vma->vm_file;
  		if (error)
  			goto unmap_and_free_vma;
@@ -1868,7 +1869,6 @@ unsigned long mmap_region(struct file *f
  		if (vm_flags & VM_DENYWRITE)
  			allow_write_access(file);
  	}
-	file = vma->vm_file;
  out:
  	perf_event_mmap(vma);
--- a/mm/util.c
+++ b/mm/util.c
@@ -314,12 +314,37 @@ int vma_is_stack_for_current(struct vm_a
  /*
   * Change backing file, only valid to use during initial VMA setup.
   */
-void vma_set_file(struct vm_area_struct *vma, struct file *file)
+int vma_set_file(struct vm_area_struct *vma, struct file *file)
  {
+	vm_flags_t vm_flags = vma->vm_flags;
+	int err = 0;
+
  	/* Changing an anonymous vma with this is illegal */
  	get_file(file);
+
+	/* Get temporary denial counts on replacement */
+	if (vm_flags & VM_DENYWRITE) {
+		err = deny_write_access(file);
+		if (err)
+			goto out_put;
+	}
+	if (vm_flags & VM_SHARED) {
+		err = mapping_map_writable(file->f_mapping);
+		if (err)
+			goto out_allow;
+	}
+
  	swap(vma->vm_file, file);
+
+	/* Undo temporary denial counts on replaced */
+	if (vm_flags & VM_SHARED)
+		mapping_unmap_writable(file->f_mapping);
+out_allow:
+	if (vm_flags & VM_DENYWRITE)
+		allow_write_access(file);
+out_put:
  	fput(file);
+	return err;
  }
  EXPORT_SYMBOL(vma_set_file);




[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux