If a filehandle is dup()ped, then it is possible to close it from one fd
and call mmap from the other. This creates a race condition in vb2_mmap
where it is using queue data that __vb2_queue_free (called from close())
is in the process of releasing.

By moving up the mutex_lock(mmap_lock) in vb2_mmap this race is avoided
since __vb2_queue_free is called with the same mutex locked. So vb2_mmap
now reads consistent buffer data.

Signed-off-by: Hans Verkuil <hverk...@xs4all.nl>
Reported-by: syzbot+be93025dd45dccd89...@syzkaller.appspotmail.com
---
 drivers/media/common/videobuf2/videobuf2-core.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/drivers/media/common/videobuf2/videobuf2-core.c 
b/drivers/media/common/videobuf2/videobuf2-core.c
index c49c67473408..03954c13024c 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -2120,9 +2120,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct 
*vma)
                        return -EINVAL;
                }
        }
+
+       mutex_lock(&q->mmap_lock);
+
        if (vb2_fileio_is_active(q)) {
                dprintk(1, "mmap: file io in progress\n");
-               return -EBUSY;
+               ret = -EBUSY;
+               goto unlock;
        }

        /*
@@ -2130,7 +2134,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct 
*vma)
         */
        ret = __find_plane_by_offset(q, off, &buffer, &plane);
        if (ret)
-               return ret;
+               goto unlock;

        vb = q->bufs[buffer];

@@ -2146,8 +2150,9 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct 
*vma)
                return -EINVAL;
        }

-       mutex_lock(&q->mmap_lock);
        ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
+
+unlock:
        mutex_unlock(&q->mmap_lock);
        if (ret)
                return ret;
-- 
2.19.1

Reply via email to