DragonFlyBSD Kernel Audit
DF-1590 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/tws/tws_cam.c b/sys/dev/raid/tws/tws_cam.c
--- a/sys/dev/raid/tws/tws_cam.c
+++ b/sys/dev/raid/tws/tws_cam.c
@@ -510,6 +510,14 @@
         hdr = sen->hdr;
         TWS_TRACE_DEBUG(sc, "sen, hdr", sen, hdr);
         req_id = hdr->header_desc.request_id;
+        /*
+         * DF-1590: tws_err_complete had NO req_id bound check at all
+         * (not even INVALID).  Validate before indexing sc->reqs[].
+         */
+        if (req_id >= tws_queue_depth) {
+            TWS_TRACE_DEBUG(sc, "invalid req_id in sense", req_id, req_id);
+            return;
+        }
         req = &sc->reqs[req_id];
         TWS_TRACE_DEBUG(sc, "req, id", req, req_id);
         if ( req->error_code != TWS_REQ_SUBMIT_SUCCESS )
@@ -1160,7 +1168,13 @@
 
     while ( tws_get_response(sc, &req_id, &mfa) ) {
         sc->stats.reqs_out++;
-        if ( req_id == TWS_INVALID_REQID ) {
+        /*
+         * DF-1590: req_id is a u16 from firmware DMA reply; reqs[] is
+         * sized tws_queue_depth (<=256).  Without an upper bound the
+         * cb() call below derefs an out-of-bounds struct that the
+         * firmware completely controls.
+         */
+        if ( req_id == TWS_INVALID_REQID || req_id >= tws_queue_depth ) {
             TWS_TRACE_DEBUG(sc, "invalid req_id", mfa, req_id);
             sc->stats.reqs_errored++;
             tws_err_complete(sc, mfa);