Module Name: src Committed By: jdolecek Date: Sat Sep 22 16:14:25 UTC 2018
Modified Files: src/sys/dev/ata [jdolecek-ncqfixes]: TODO.ncq ata.c atavar.h wd.c wdvar.h Log Message: 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 To generate a diff of this commit: cvs rdiff -u -r1.4.2.5 -r1.4.2.6 src/sys/dev/ata/TODO.ncq cvs rdiff -u -r1.141.6.8 -r1.141.6.9 src/sys/dev/ata/ata.c cvs rdiff -u -r1.99.2.5 -r1.99.2.6 src/sys/dev/ata/atavar.h cvs rdiff -u -r1.441.2.4 -r1.441.2.5 src/sys/dev/ata/wd.c cvs rdiff -u -r1.46.6.2 -r1.46.6.3 src/sys/dev/ata/wdvar.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ata/TODO.ncq diff -u src/sys/dev/ata/TODO.ncq:1.4.2.5 src/sys/dev/ata/TODO.ncq:1.4.2.6 --- src/sys/dev/ata/TODO.ncq:1.4.2.5 Sat Sep 22 09:26:48 2018 +++ src/sys/dev/ata/TODO.ncq Sat Sep 22 16:14:25 2018 @@ -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 Index: src/sys/dev/ata/ata.c diff -u src/sys/dev/ata/ata.c:1.141.6.8 src/sys/dev/ata/ata.c:1.141.6.9 --- src/sys/dev/ata/ata.c:1.141.6.8 Sat Sep 22 12:20:31 2018 +++ src/sys/dev/ata/ata.c Sat Sep 22 16:14:25 2018 @@ -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_free_xfer(struct ata_channel *chp, s 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 @@ ata_free_xfer(struct ata_channel *chp, s /* 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_free_xfer(struct ata_channel *chp, s 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 Index: src/sys/dev/ata/atavar.h diff -u src/sys/dev/ata/atavar.h:1.99.2.5 src/sys/dev/ata/atavar.h:1.99.2.6 --- src/sys/dev/ata/atavar.h:1.99.2.5 Sat Sep 22 09:22:59 2018 +++ src/sys/dev/ata/atavar.h Sat Sep 22 16:14:25 2018 @@ -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 @@ struct ata_xfer_ops { #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 */ Index: src/sys/dev/ata/wd.c diff -u src/sys/dev/ata/wd.c:1.441.2.4 src/sys/dev/ata/wd.c:1.441.2.5 --- src/sys/dev/ata/wd.c:1.441.2.4 Sat Sep 22 09:22:59 2018 +++ src/sys/dev/ata/wd.c Sat Sep 22 16:14:25 2018 @@ -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 @@ wd_dumpblocks(device_t dev, void *va, da 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_dumpblocks(device_t dev, void *va, da 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 @@ wd_dumpblocks(device_t dev, void *va, da err = 0; break; default: - panic("wddump: unknown error type %d", err); + panic("wddump: unknown error type %x", err); } if (err != 0) { Index: src/sys/dev/ata/wdvar.h diff -u src/sys/dev/ata/wdvar.h:1.46.6.2 src/sys/dev/ata/wdvar.h:1.46.6.3 --- src/sys/dev/ata/wdvar.h:1.46.6.2 Sat Sep 22 09:22:59 2018 +++ src/sys/dev/ata/wdvar.h Sat Sep 22 16:14:25 2018 @@ -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 @@ struct wd_softc { 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;