summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2010-08-11 02:18:26 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2010-08-11 02:18:26 +0000
commit08950a9628800a6c04d1b045ef8a18d5fd0864ba (patch)
tree055d1abbe7b7565fff5d8a23ee91d93e6ab6c65f
parent5f0d4c915d87938445313e5481a3ccd7ccfbeedf (diff)
Fix two problems in gdt, introduced in 4.7. Eliminate a use-after-free
of xs for xs->flags. Avoid calling scsi_done() twice when sync'ing disks during shut down. scsi_done() problem found by Federico Giannici. Feedback and fixes from matthew@ and dlg@. Testing of various versions by Federico and sthen@ via Pierre Berthier. ok matthew@ deraadt@
-rw-r--r--sys/dev/ic/gdt_common.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/sys/dev/ic/gdt_common.c b/sys/dev/ic/gdt_common.c
index 01ff8c10acb..e725786d5c8 100644
--- a/sys/dev/ic/gdt_common.c
+++ b/sys/dev/ic/gdt_common.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: gdt_common.c,v 1.51 2010/06/28 18:31:02 krw Exp $ */
+/* $OpenBSD: gdt_common.c,v 1.52 2010/08/11 02:18:25 krw Exp $ */
/*
* Copyright (c) 1999, 2000, 2003 Niklas Hallqvist. All rights reserved.
@@ -587,6 +587,7 @@ gdt_scsi_cmd(struct scsi_xfer *xs)
bus_dmamap_t xfer;
int error;
int s;
+ int polled;
GDT_DPRINTF(GDT_D_CMD, ("gdt_scsi_cmd "));
@@ -615,6 +616,7 @@ gdt_scsi_cmd(struct scsi_xfer *xs)
ccb = NULL;
link = xs->sc_link;
target = link->target;
+ polled = ISSET(xs->flags, SCSI_POLL);
if (!gdt_polling && !(xs->flags & SCSI_POLL) &&
sc->sc_test_busy(sc)) {
@@ -759,7 +761,6 @@ gdt_scsi_cmd(struct scsi_xfer *xs)
splx(s);
return;
}
- scsi_done(xs);
}
}
@@ -767,7 +768,7 @@ gdt_scsi_cmd(struct scsi_xfer *xs)
/*
* Don't process the queue if we are polling.
*/
- if (xs->flags & SCSI_POLL) {
+ if (polled) {
break;
}
}
@@ -1155,8 +1156,11 @@ gdt_intr(void *arg)
sync_val = gdt_sync_event(sc, ctx.service, ctx.istatus, xs);
finish:
-
switch (sync_val) {
+ case 0:
+ if (xs && gdt_from_wait)
+ scsi_done(xs);
+ break;
case 1:
scsi_done(xs);
break;