From fca37c251af3c542ba8b9786143188ce9cd51989 Mon Sep 17 00:00:00 2001 From: Chris Goldsworthy Date: Tue, 22 Jun 2021 14:23:06 -0700 Subject: [PATCH] ANDROID: dma-buf: Don't change vm_ops if vm_file changes When CONFIG_DMABUF_SYSFS_STATS=y, dma_buf_do_mmap() will call a dma-bufs mmap() callback before overriding the open() and close() callbacks for the dma-buf's vm_operations_stuct, such that dma_buf_vma_open() and dma_buf_vma_close() are used instead. Each of the two aforementioend callbacks assumes that the vma->vm_file pointer they use points to a dma-buf file. However, it is possible that during the invocation of the dma-buf's mmap() callback, that the vma->vm_file pointer changes to store something other than a dma-buf file (it is permissible to do this so long as certain conditions are met, see the callsite of call_mmap in mm/mmap.c as of commit a2e00b4b5da4 ("FROMGIT: mm/slub: add taint after the errors are printed"). This means that when dma_buf_vma_open() and dma_buf_vma_close() run, that their accesses to vma->vm_file will cease to be semantically valid. Accordingly, only override the open() and close() vm_operations_struct callbacks if a dma-buf's mmap() callback preserves the vma->vm_file across the mmap() callback. Bug: 191742286 Fixes: 9132fbe54592 ("ANDROID: dmabuf: Add mmap_count to struct dmabuf") Signed-off-by: Chris Goldsworthy Change-Id: I4f80ade7f0bc85e2cb9219478550dcb6bbb29f3e --- drivers/dma-buf/dma-buf.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 0ab865543d1f..9ca8f84732b3 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -173,12 +173,17 @@ static void dma_buf_vma_close(struct vm_area_struct *vma) static int dma_buf_do_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) { - /* call this first because the exporter might override vma->vm_ops */ - int ret = dmabuf->ops->mmap(dmabuf, vma); + int ret; + struct file *orig_vm_file = vma->vm_file; + /* call this first because the exporter might override vma->vm_ops */ + ret = dmabuf->ops->mmap(dmabuf, vma); if (ret) return ret; + if (orig_vm_file != vma->vm_file) + return 0; + /* save the exporter provided vm_ops */ dmabuf->exp_vm_ops = vma->vm_ops; dmabuf->vm_ops = *(dmabuf->exp_vm_ops);