Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/jdolecek-ncqfixes]: src/sys/dev/ata fix use-after-free in wd(4) dump, de...



details:   https://anonhg.NetBSD.org/src/rev/7db6c7bb3860
branches:  jdolecek-ncqfixes
changeset: 850582:7db6c7bb3860
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Sat Sep 22 16:14:25 2018 +0000

description:
fix use-after-free in wd(4) dump, detected by switch to the pool

change code in wd_dumpblocks() to use it's own non-pool ata_xfer,
which skips the deallocation step and thus keeps the contents when the I/O
is finished

diffstat:

 sys/dev/ata/TODO.ncq |   2 --
 sys/dev/ata/ata.c    |  11 ++++++-----
 sys/dev/ata/atavar.h |   3 ++-
 sys/dev/ata/wd.c     |  15 ++++++---------
 sys/dev/ata/wdvar.h  |   4 +++-
 5 files changed, 17 insertions(+), 18 deletions(-)

diffs (143 lines):

diff -r 4e7fae7cb16c -r 7db6c7bb3860 sys/dev/ata/TODO.ncq
--- a/sys/dev/ata/TODO.ncq      Sat Sep 22 12:20:31 2018 +0000
+++ b/sys/dev/ata/TODO.ncq      Sat Sep 22 16:14:25 2018 +0000
@@ -1,8 +1,6 @@
 jdolecek-ncqfixes goals:
 - add to wd(4) a callout to restart buf queue processing when ata_get_xfer()
   call fails and remove ata_channel_start()
-- change wd(4) dump code to use preallocated or on-stack ata_xfer to not rely
-  on pool having memory
 - re-fix QEMU ahci(4) bug workaround (no READ LOG EXT support) - now it
   triggers KASSERT()
 - fix ahci(4) error handling under paralles - invalid bio via WD_CHAOS_MONKEY
diff -r 4e7fae7cb16c -r 7db6c7bb3860 sys/dev/ata/ata.c
--- a/sys/dev/ata/ata.c Sat Sep 22 12:20:31 2018 +0000
+++ b/sys/dev/ata/ata.c Sat Sep 22 16:14:25 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ata.c,v 1.141.6.8 2018/09/22 12:20:31 jdolecek Exp $   */
+/*     $NetBSD: ata.c,v 1.141.6.9 2018/09/22 16:14:25 jdolecek Exp $   */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.141.6.8 2018/09/22 12:20:31 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.141.6.9 2018/09/22 16:14:25 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -1350,7 +1350,7 @@
 
        ata_channel_lock(chp);
 
-       if (xfer->c_flags & (C_WAITACT|C_WAITTIMO)) {
+       if (__predict_false(xfer->c_flags & (C_WAITACT|C_WAITTIMO))) {
                /* Someone is waiting for this xfer, so we can't free now */
                xfer->c_flags |= C_FREE;
                cv_broadcast(&chq->c_active);
@@ -1360,7 +1360,7 @@
 
        /* XXX move PIOBM and free_gw to deactivate? */
 #if NATA_PIOBM         /* XXX wdc dependent code */
-       if (xfer->c_flags & C_PIOBM) {
+       if (__predict_false(xfer->c_flags & C_PIOBM)) {
                struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 
                /* finish the busmastering PIO */
@@ -1375,7 +1375,8 @@
  
        ata_channel_unlock(chp);
 
-       pool_put(&ata_xfer_pool, xfer);
+       if (__predict_true(!ISSET(xfer->c_flags, C_PRIVATE_ALLOC)))
+               pool_put(&ata_xfer_pool, xfer);
 }
 
 void
diff -r 4e7fae7cb16c -r 7db6c7bb3860 sys/dev/ata/atavar.h
--- a/sys/dev/ata/atavar.h      Sat Sep 22 12:20:31 2018 +0000
+++ b/sys/dev/ata/atavar.h      Sat Sep 22 16:14:25 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: atavar.h,v 1.99.2.5 2018/09/22 09:22:59 jdolecek Exp $ */
+/*     $NetBSD: atavar.h,v 1.99.2.6 2018/09/22 16:14:25 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -198,6 +198,7 @@
 #define C_WAITTIMO     0x0400          /* race vs. timeout */
 #define C_CHAOS                0x0800          /* forced error xfer */
 #define C_RECOVERED    0x1000          /* error recovered, no need for reset */
+#define C_PRIVATE_ALLOC        0x2000          /* private alloc, skip pool_put() */
 
 /* reasons for c_kill_xfer() */
 #define KILL_GONE 1            /* device is gone while xfer was active */
diff -r 4e7fae7cb16c -r 7db6c7bb3860 sys/dev/ata/wd.c
--- a/sys/dev/ata/wd.c  Sat Sep 22 12:20:31 2018 +0000
+++ b/sys/dev/ata/wd.c  Sat Sep 22 16:14:25 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wd.c,v 1.441.2.4 2018/09/22 09:22:59 jdolecek Exp $ */
+/*     $NetBSD: wd.c,v 1.441.2.5 2018/09/22 16:14:25 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.4 2018/09/22 09:22:59 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.5 2018/09/22 16:14:25 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wd.h"
@@ -1458,7 +1458,7 @@
        struct wd_softc *wd = device_private(dev);
        struct dk_softc *dksc = &wd->sc_dksc;
        struct disk_geom *dg = &dksc->sc_dkdev.dk_geom;
-       struct ata_xfer *xfer;
+       struct ata_xfer *xfer = &wd->dump_xfer;
        int err;
 
        /* Recalibrate, if first dump transfer. */
@@ -1469,11 +1469,8 @@
                wd->drvp->state = RESET;
        }
 
-       xfer = ata_get_xfer(wd->drvp->chnl_softc, false);
-       if (xfer == NULL) {
-               printf("%s: no xfer\n", __func__);
-               return EAGAIN;
-       }
+       memset(xfer, 0, sizeof(*xfer));
+       xfer->c_flags |= C_PRIVATE_ALLOC;
 
        xfer->c_bio.blkno = blkno;
        xfer->c_bio.flags = ATA_POLL;
@@ -1519,7 +1516,7 @@
                err = 0;
                break;
        default:
-               panic("wddump: unknown error type %d", err);
+               panic("wddump: unknown error type %x", err);
        }
 
        if (err != 0) {
diff -r 4e7fae7cb16c -r 7db6c7bb3860 sys/dev/ata/wdvar.h
--- a/sys/dev/ata/wdvar.h       Sat Sep 22 12:20:31 2018 +0000
+++ b/sys/dev/ata/wdvar.h       Sat Sep 22 16:14:25 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wdvar.h,v 1.46.6.2 2018/09/22 09:22:59 jdolecek Exp $  */
+/*     $NetBSD: wdvar.h,v 1.46.6.3 2018/09/22 16:14:25 jdolecek Exp $  */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -71,6 +71,8 @@
        SLIST_HEAD(, ata_xfer) sc_requeue_list;
        struct callout sc_requeue_callout;      /* requeue callout handle */
 
+       struct ata_xfer dump_xfer;
+
        /* Sysctl nodes specific for the disk */
        struct sysctllog *nodelog;
        bool drv_ncq;



Home | Main Index | Thread Index | Old Index