| From 6a8dadcca81fceff9976e8828cceb072873b7bd5 Mon Sep 17 00:00:00 2001 |
| From: Todd Poynor <toddpoynor@google.com> |
| Date: Tue, 15 Aug 2017 22:41:08 -0700 |
| Subject: scsi: sg: protect against races between mmap() and SG_SET_RESERVED_SIZE |
| |
| From: Todd Poynor <toddpoynor@google.com> |
| |
| commit 6a8dadcca81fceff9976e8828cceb072873b7bd5 upstream. |
| |
| Take f_mutex around mmap() processing to protect against races with the |
| SG_SET_RESERVED_SIZE ioctl. Ensure the reserve buffer length remains |
| consistent during the mapping operation, and set the "mmap called" flag |
| to prevent further changes to the reserved buffer size as an atomic |
| operation with the mapping. |
| |
| [mkp: fixed whitespace] |
| |
| Signed-off-by: Todd Poynor <toddpoynor@google.com> |
| Acked-by: Douglas Gilbert <dgilbert@interlog.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/scsi/sg.c | 12 +++++++++--- |
| 1 file changed, 9 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/scsi/sg.c |
| +++ b/drivers/scsi/sg.c |
| @@ -1244,6 +1244,7 @@ sg_mmap(struct file *filp, struct vm_are |
| unsigned long req_sz, len, sa; |
| Sg_scatter_hold *rsv_schp; |
| int k, length; |
| + int ret = 0; |
| |
| if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data))) |
| return -ENXIO; |
| @@ -1254,8 +1255,11 @@ sg_mmap(struct file *filp, struct vm_are |
| if (vma->vm_pgoff) |
| return -EINVAL; /* want no offset */ |
| rsv_schp = &sfp->reserve; |
| - if (req_sz > rsv_schp->bufflen) |
| - return -ENOMEM; /* cannot map more than reserved buffer */ |
| + mutex_lock(&sfp->f_mutex); |
| + if (req_sz > rsv_schp->bufflen) { |
| + ret = -ENOMEM; /* cannot map more than reserved buffer */ |
| + goto out; |
| + } |
| |
| sa = vma->vm_start; |
| length = 1 << (PAGE_SHIFT + rsv_schp->page_order); |
| @@ -1269,7 +1273,9 @@ sg_mmap(struct file *filp, struct vm_are |
| vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP; |
| vma->vm_private_data = sfp; |
| vma->vm_ops = &sg_mmap_vm_ops; |
| - return 0; |
| +out: |
| + mutex_unlock(&sfp->f_mutex); |
| + return ret; |
| } |
| |
| static void |