aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorDennis Dalessandro <dennis.dalessandro@intel.com>2014-02-20 11:02:53 -0500
committerRoland Dreier <roland@purestorage.com>2014-03-17 19:16:51 -0400
commita2cb0eb8a64adb29a99fd864013de957028f36ae (patch)
tree29398a975c31580c9c545df3e8081e566e49f46b /drivers/infiniband
parent1c20c81909455f64f2df6107cb099ee5569d9f62 (diff)
IB/ipath: Fix potential buffer overrun in sending diag packet routine
Guard against a potential buffer overrun. The size to read from the user is passed in, and due to the padding that needs to be taken into account, as well as the place holder for the ICRC it is possible to overflow the 32bit value which would cause more data to be copied from user space than is allocated in the buffer. Cc: <stable@vger.kernel.org> Reported-by: Nico Golde <nico@ngolde.de> Reported-by: Fabian Yamaguchi <fabs@goesec.de> Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com> Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c66
1 files changed, 25 insertions, 41 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 714293b78518..e2f9a51f4a38 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -326,7 +326,7 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
326 size_t count, loff_t *off) 326 size_t count, loff_t *off)
327{ 327{
328 u32 __iomem *piobuf; 328 u32 __iomem *piobuf;
329 u32 plen, clen, pbufn; 329 u32 plen, pbufn, maxlen_reserve;
330 struct ipath_diag_pkt odp; 330 struct ipath_diag_pkt odp;
331 struct ipath_diag_xpkt dp; 331 struct ipath_diag_xpkt dp;
332 u32 *tmpbuf = NULL; 332 u32 *tmpbuf = NULL;
@@ -335,51 +335,29 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
335 u64 val; 335 u64 val;
336 u32 l_state, lt_state; /* LinkState, LinkTrainingState */ 336 u32 l_state, lt_state; /* LinkState, LinkTrainingState */
337 337
338 if (count < sizeof(odp)) {
339 ret = -EINVAL;
340 goto bail;
341 }
342 338
343 if (count == sizeof(dp)) { 339 if (count == sizeof(dp)) {
344 if (copy_from_user(&dp, data, sizeof(dp))) { 340 if (copy_from_user(&dp, data, sizeof(dp))) {
345 ret = -EFAULT; 341 ret = -EFAULT;
346 goto bail; 342 goto bail;
347 } 343 }
348 } else if (copy_from_user(&odp, data, sizeof(odp))) { 344 } else if (count == sizeof(odp)) {
349 ret = -EFAULT; 345 if (copy_from_user(&odp, data, sizeof(odp))) {
346 ret = -EFAULT;
347 goto bail;
348 }
349 } else {
350 ret = -EINVAL;
350 goto bail; 351 goto bail;
351 } 352 }
352 353
353 /*
354 * Due to padding/alignment issues (lessened with new struct)
355 * the old and new structs are the same length. We need to
356 * disambiguate them, which we can do because odp.len has never
357 * been less than the total of LRH+BTH+DETH so far, while
358 * dp.unit (same offset) unit is unlikely to get that high.
359 * Similarly, dp.data, the pointer to user at the same offset
360 * as odp.unit, is almost certainly at least one (512byte)page
361 * "above" NULL. The if-block below can be omitted if compatibility
362 * between a new driver and older diagnostic code is unimportant.
363 * compatibility the other direction (new diags, old driver) is
364 * handled in the diagnostic code, with a warning.
365 */
366 if (dp.unit >= 20 && dp.data < 512) {
367 /* very probable version mismatch. Fix it up */
368 memcpy(&odp, &dp, sizeof(odp));
369 /* We got a legacy dp, copy elements to dp */
370 dp.unit = odp.unit;
371 dp.data = odp.data;
372 dp.len = odp.len;
373 dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
374 }
375
376 /* send count must be an exact number of dwords */ 354 /* send count must be an exact number of dwords */
377 if (dp.len & 3) { 355 if (dp.len & 3) {
378 ret = -EINVAL; 356 ret = -EINVAL;
379 goto bail; 357 goto bail;
380 } 358 }
381 359
382 clen = dp.len >> 2; 360 plen = dp.len >> 2;
383 361
384 dd = ipath_lookup(dp.unit); 362 dd = ipath_lookup(dp.unit);
385 if (!dd || !(dd->ipath_flags & IPATH_PRESENT) || 363 if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
@@ -422,16 +400,22 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
422 goto bail; 400 goto bail;
423 } 401 }
424 402
425 /* need total length before first word written */ 403 /*
426 /* +1 word is for the qword padding */ 404 * need total length before first word written, plus 2 Dwords. One Dword
427 plen = sizeof(u32) + dp.len; 405 * is for padding so we get the full user data when not aligned on
428 406 * a word boundary. The other Dword is to make sure we have room for the
429 if ((plen + 4) > dd->ipath_ibmaxlen) { 407 * ICRC which gets tacked on later.
408 */
409 maxlen_reserve = 2 * sizeof(u32);
410 if (dp.len > dd->ipath_ibmaxlen - maxlen_reserve) {
430 ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n", 411 ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
431 plen - 4, dd->ipath_ibmaxlen); 412 dp.len, dd->ipath_ibmaxlen);
432 ret = -EINVAL; 413 ret = -EINVAL;
433 goto bail; /* before writing pbc */ 414 goto bail;
434 } 415 }
416
417 plen = sizeof(u32) + dp.len;
418
435 tmpbuf = vmalloc(plen); 419 tmpbuf = vmalloc(plen);
436 if (!tmpbuf) { 420 if (!tmpbuf) {
437 dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, " 421 dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
@@ -473,11 +457,11 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
473 */ 457 */
474 if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) { 458 if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
475 ipath_flush_wc(); 459 ipath_flush_wc();
476 __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1); 460 __iowrite32_copy(piobuf + 2, tmpbuf, plen - 1);
477 ipath_flush_wc(); 461 ipath_flush_wc();
478 __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1); 462 __raw_writel(tmpbuf[plen - 1], piobuf + plen + 1);
479 } else 463 } else
480 __iowrite32_copy(piobuf + 2, tmpbuf, clen); 464 __iowrite32_copy(piobuf + 2, tmpbuf, plen);
481 465
482 ipath_flush_wc(); 466 ipath_flush_wc();
483 467