Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F159339050
D57496.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D57496.diff
View Options
diff --git a/sys/dev/firewire/firewire.c b/sys/dev/firewire/firewire.c
--- a/sys/dev/firewire/firewire.c
+++ b/sys/dev/firewire/firewire.c
@@ -372,23 +372,21 @@
static void
firewire_watchdog(void *arg)
{
- struct firewire_comm *fc;
- static int watchdog_clock = 0;
-
- fc = arg;
+ struct firewire_softc *sc = arg;
+ struct firewire_comm *fc = sc->fc;
/*
* At boot stage, the device interrupt is disabled and
- * We encounter a timeout easily. To avoid this,
- * ignore clock interrupt for a while.
+ * we encounter a timeout easily. To avoid this,
+ * ignore clock ticks for a while.
*/
- if (watchdog_clock > WATCHDOG_HZ * 15)
+ if (sc->watchdog_clock > WATCHDOG_HZ * 15)
taskqueue_enqueue(fc->taskqueue, &fc->task_timeout);
else
- watchdog_clock++;
+ sc->watchdog_clock++;
callout_reset(&fc->timeout_callout, hz / WATCHDOG_HZ,
- firewire_watchdog, fc);
+ firewire_watchdog, sc);
}
/*
@@ -444,8 +442,9 @@
CALLOUT_INIT(&fc->busprobe_callout);
TASK_INIT(&fc->task_timeout, 0, firewire_xfer_timeout, fc);
+ sc->watchdog_clock = 0;
callout_reset(&sc->fc->timeout_callout, hz,
- firewire_watchdog, sc->fc);
+ firewire_watchdog, sc);
/* create thread */
kproc_create(fw_bus_probe_thread, fc, &fc->probe_thread,
@@ -1048,39 +1047,47 @@
}
/*
- * To obtain XFER structure by transaction label.
+ * Look up an XFER by transaction label.
+ * Removes the xfer from fc->tlabels only when AT transmit has completed
+ * (FWXF_SENT); FWXF_START xfers remain so fw_drain_txq() can find them
+ * on a bus reset.
*/
static struct fw_xfer *
fw_tl2xfer(struct firewire_comm *fc, int node, int tlabel, int tcode)
{
struct fw_xfer *xfer;
- int s = splfw();
int req;
mtx_lock(&fc->tlabel_lock);
- STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel)
- if (xfer->send.hdr.mode.hdr.dst == node) {
+ STAILQ_FOREACH(xfer, &fc->tlabels[tlabel], tlabel) {
+ if (xfer->send.hdr.mode.hdr.dst != node)
+ continue;
+ /* Validate tcode match before claiming the xfer. */
+ req = xfer->send.hdr.mode.hdr.tcode;
+ if (xfer->fc->tcode[req].valid_res != tcode) {
+ printf("%s: invalid response tcode "
+ "(0x%x for 0x%x)\n", __func__, tcode, req);
mtx_unlock(&fc->tlabel_lock);
- splx(s);
- KASSERT(xfer->tl == tlabel,
- ("xfer->tl 0x%x != 0x%x", xfer->tl, tlabel));
- /* extra sanity check */
- req = xfer->send.hdr.mode.hdr.tcode;
- if (xfer->fc->tcode[req].valid_res != tcode) {
- printf("%s: invalid response tcode "
- "(0x%x for 0x%x)\n", __FUNCTION__,
- tcode, req);
- return (NULL);
- }
-
- if (firewire_debug > 2)
- printf("fw_tl2xfer: found tl=%d\n", tlabel);
- return (xfer);
+ return (NULL);
}
+ /*
+ * Remove from tlabels only after AT transmit completes
+ * (FWXF_SENT). Early responses (FWXF_START) must stay
+ * in the list until fwohci_txd() drains the descriptor.
+ */
+ if (xfer->flag & FWXF_SENT) {
+ STAILQ_REMOVE(&fc->tlabels[tlabel], xfer,
+ fw_xfer, tlabel);
+ xfer->tl = -1;
+ }
+ mtx_unlock(&fc->tlabel_lock);
+ if (firewire_debug > 2)
+ printf("fw_tl2xfer: found tl=%d\n", tlabel);
+ return (xfer);
+ }
mtx_unlock(&fc->tlabel_lock);
if (firewire_debug > 1)
printf("fw_tl2xfer: not found tl=%d\n", tlabel);
- splx(s);
return (NULL);
}
diff --git a/sys/dev/firewire/firewirereg.h b/sys/dev/firewire/firewirereg.h
--- a/sys/dev/firewire/firewirereg.h
+++ b/sys/dev/firewire/firewirereg.h
@@ -69,6 +69,7 @@
struct firewire_softc {
struct cdev *dev;
struct firewire_comm *fc;
+ int watchdog_clock;
};
#define FW_MAX_DMACH 0x20
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jun 14, 12:52 AM (1 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33882211
Default Alt Text
D57496.diff (3 KB)
Attached To
Mode
D57496: firewire: Fix watchdog_clock aliasing and fw_tl2xfer UAF race
Attached
Detach File
Event Timeline
Log In to Comment