All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] coda: pass the host file in vma->vm_file on mmap
@ 2019-07-23 20:17 Jan Harkes
  2019-07-24 11:07 ` Greg KH
  0 siblings, 1 reply; 2+ messages in thread
From: Jan Harkes @ 2019-07-23 20:17 UTC (permalink / raw)
  To: stable; +Cc: Jan Harkes

commit 7fa0a1da3dadfd9216df7745a1331fdaa0940d1c upstream.

Various file systems expect that vma->vm_file points at their own file
handle, several use file_inode(vma->vm_file) to get at their inode or
use vma->vm_file->private_data. However the way Coda wrapped mmap on a
host file broke this assumption, vm_file was still pointing at the Coda
file and the host file systems would scribble over Coda's inode and
private file data.

This patch fixes the incorrect expectation and wraps vm_ops->open and
vm_ops->close to allow Coda to track when the vm_area_struct is
destroyed so we still release the reference on the Coda file handle at
the right time.

This patch differs from the original upstream patch because older stable
kernels do not have the call_mmap vfs helper so we call f_ops->mmap
directly.

Cc: stable@vger.kernel.org # 4.9.x
Cc: stable@vger.kernel.org # 4.4.x
Cc: stable@vger.kernel.org # 3.16.x
Signed-off-by: Jan Harkes <jaharkes@cs.cmu.edu>
---
 fs/coda/file.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/fs/coda/file.c b/fs/coda/file.c
index 9e83b7790212..933dcddcb024 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -93,6 +93,41 @@ coda_file_write(struct file *coda_file, const char __user *buf, size_t count, lo
 	return ret;
 }
 
+struct coda_vm_ops {
+	atomic_t refcnt;
+	struct file *coda_file;
+	const struct vm_operations_struct *host_vm_ops;
+	struct vm_operations_struct vm_ops;
+};
+
+static void
+coda_vm_open(struct vm_area_struct *vma)
+{
+	struct coda_vm_ops *cvm_ops =
+		container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+	atomic_inc(&cvm_ops->refcnt);
+
+	if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->open)
+		cvm_ops->host_vm_ops->open(vma);
+}
+
+static void
+coda_vm_close(struct vm_area_struct *vma)
+{
+	struct coda_vm_ops *cvm_ops =
+		container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
+
+	if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->close)
+		cvm_ops->host_vm_ops->close(vma);
+
+	if (atomic_dec_and_test(&cvm_ops->refcnt)) {
+		vma->vm_ops = cvm_ops->host_vm_ops;
+		fput(cvm_ops->coda_file);
+		kfree(cvm_ops);
+	}
+}
+
 static int
 coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 {
@@ -100,6 +135,8 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 	struct coda_inode_info *cii;
 	struct file *host_file;
 	struct inode *coda_inode, *host_inode;
+	struct coda_vm_ops *cvm_ops;
+	int ret;
 
 	cfi = CODA_FTOC(coda_file);
 	BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
@@ -108,6 +145,13 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 	if (!host_file->f_op->mmap)
 		return -ENODEV;
 
+	if (WARN_ON(coda_file != vma->vm_file))
+		return -EIO;
+
+	cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL);
+	if (!cvm_ops)
+		return -ENOMEM;
+
 	coda_inode = file_inode(coda_file);
 	host_inode = file_inode(host_file);
 
@@ -121,6 +165,7 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 	 * the container file on us! */
 	else if (coda_inode->i_mapping != host_inode->i_mapping) {
 		spin_unlock(&cii->c_lock);
+		kfree(cvm_ops);
 		return -EBUSY;
 	}
 
@@ -129,7 +174,29 @@ coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
 	cfi->cfi_mapcount++;
 	spin_unlock(&cii->c_lock);
 
-	return host_file->f_op->mmap(host_file, vma);
+	vma->vm_file = get_file(host_file);
+	ret = host_file->f_op->mmap(host_file, vma);
+
+	if (ret) {
+		/* if call_mmap fails, our caller will put coda_file so we
+		 * should drop the reference to the host_file that we got.
+		 */
+		fput(host_file);
+		kfree(cvm_ops);
+	} else {
+		/* here we add redirects for the open/close vm_operations */
+		cvm_ops->host_vm_ops = vma->vm_ops;
+		if (vma->vm_ops)
+			cvm_ops->vm_ops = *vma->vm_ops;
+
+		cvm_ops->vm_ops.open = coda_vm_open;
+		cvm_ops->vm_ops.close = coda_vm_close;
+		cvm_ops->coda_file = coda_file;
+		atomic_set(&cvm_ops->refcnt, 1);
+
+		vma->vm_ops = &cvm_ops->vm_ops;
+	}
+	return ret;
 }
 
 int coda_open(struct inode *coda_inode, struct file *coda_file)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] coda: pass the host file in vma->vm_file on mmap
  2019-07-23 20:17 [PATCH] coda: pass the host file in vma->vm_file on mmap Jan Harkes
@ 2019-07-24 11:07 ` Greg KH
  0 siblings, 0 replies; 2+ messages in thread
From: Greg KH @ 2019-07-24 11:07 UTC (permalink / raw)
  To: Jan Harkes; +Cc: stable

On Tue, Jul 23, 2019 at 04:17:01PM -0400, Jan Harkes wrote:
> commit 7fa0a1da3dadfd9216df7745a1331fdaa0940d1c upstream.
> 
> Various file systems expect that vma->vm_file points at their own file
> handle, several use file_inode(vma->vm_file) to get at their inode or
> use vma->vm_file->private_data. However the way Coda wrapped mmap on a
> host file broke this assumption, vm_file was still pointing at the Coda
> file and the host file systems would scribble over Coda's inode and
> private file data.
> 
> This patch fixes the incorrect expectation and wraps vm_ops->open and
> vm_ops->close to allow Coda to track when the vm_area_struct is
> destroyed so we still release the reference on the Coda file handle at
> the right time.
> 
> This patch differs from the original upstream patch because older stable
> kernels do not have the call_mmap vfs helper so we call f_ops->mmap
> directly.
> 
> Cc: stable@vger.kernel.org # 4.9.x
> Cc: stable@vger.kernel.org # 4.4.x

Now queued up, thanks!

greg k-h

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-07-24 11:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-23 20:17 [PATCH] coda: pass the host file in vma->vm_file on mmap Jan Harkes
2019-07-24 11:07 ` Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.