| From b5b515445f4f5a905c5dd27e6e682868ccd6c09d Mon Sep 17 00:00:00 2001 |
| From: Dan Rosenberg <drosenberg@vsecurity.com> |
| Date: Mon, 11 Jul 2011 14:08:23 -0700 |
| Subject: [SCSI] pmcraid: reject negative request size |
| |
| From: Dan Rosenberg <drosenberg@vsecurity.com> |
| |
| commit b5b515445f4f5a905c5dd27e6e682868ccd6c09d upstream. |
| |
| There's a code path in pmcraid that can be reached via device ioctl that |
| causes all sorts of ugliness, including heap corruption or triggering the |
| OOM killer due to consecutive allocation of large numbers of pages. |
| |
| First, the user can call pmcraid_chr_ioctl(), with a type |
| PMCRAID_PASSTHROUGH_IOCTL. This calls through to |
| pmcraid_ioctl_passthrough(). Next, a pmcraid_passthrough_ioctl_buffer |
| is copied in, and the request_size variable is set to |
| buffer->ioarcb.data_transfer_length, which is an arbitrary 32-bit |
| signed value provided by the user. If a negative value is provided |
| here, bad things can happen. For example, |
| pmcraid_build_passthrough_ioadls() is called with this request_size, |
| which immediately calls pmcraid_alloc_sglist() with a negative size. |
| The resulting math on allocating a scatter list can result in an |
| overflow in the kzalloc() call (if num_elem is 0, the sglist will be |
| smaller than expected), or if num_elem is unexpectedly large the |
| subsequent loop will call alloc_pages() repeatedly, a high number of |
| pages will be allocated and the OOM killer might be invoked. |
| |
| It looks like preventing this value from being negative in |
| pmcraid_ioctl_passthrough() would be sufficient. |
| |
| Signed-off-by: Dan Rosenberg <drosenberg@vsecurity.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: James Bottomley <JBottomley@Parallels.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/scsi/pmcraid.c | 3 +++ |
| 1 file changed, 3 insertions(+) |
| |
| --- a/drivers/scsi/pmcraid.c |
| +++ b/drivers/scsi/pmcraid.c |
| @@ -3557,6 +3557,9 @@ static long pmcraid_ioctl_passthrough( |
| pmcraid_err("couldn't build passthrough ioadls\n"); |
| goto out_free_buffer; |
| } |
| + } else if (request_size < 0) { |
| + rc = -EINVAL; |
| + goto out_free_buffer; |
| } |
| |
| /* If data is being written into the device, copy the data from user |