⬢ DragonFlyBSD Kernel Audit
DF-4988 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/tws/tws_user.c
+++ b/sys/dev/raid/tws/tws_user.c
@@ -126,10 +126,26 @@ tws_passthru(struct tws_softc *sc, void *buf)
     memcpy(&req->cmd_pkt->cmd, &ubuf->cmd_pkt.cmd,
                               sizeof(struct tws_command_apache));
 
     if ( GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) ==
                                                  TWS_FW_CMD_EXECUTE_SCSI ) {
         lun4 = req->cmd_pkt->cmd.pkt_a.lun_l4__req_id & 0xF000;
         req->cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun4 | req->request_id;
     } else {
+        /*
+         * The generic path writes the SGL at
+         *     (u_int32_t *)gcmd + gcmd->size
+         * (tws_cam.c:1035) with up to max_sg_elements descriptors.  gcmd->size
+         * is caller-controlled and previously unvalidated: with size=255 up
+         * to 736 bytes of descriptors are written ~860 bytes past the end of
+         * this request's 1024-byte command packet into neighboring requests
+         * of the dma_mem pool.  Keep the SGL inside this packet.
+         */
+        size_t ent = (sc->is64bit && !tws_use_32bit_sgls) ?
+                        sizeof(struct tws_sg_desc64) :
+                        sizeof(struct tws_sg_desc32);
+        u_int max_sgls = (sc->is64bit && !tws_use_32bit_sgls) ?
+                        TWS_MAX_64BIT_SG_ELEMENTS : TWS_MAX_32BIT_SG_ELEMENTS;
+        size_t off = sizeof(struct tws_command_header) +
+                        4 * req->cmd_pkt->cmd.pkt_g.generic.size;
+        if ( off + max_sgls * ent > sizeof(struct tws_command_packet) ) {
+            req->state = TWS_REQ_STATE_FREE;
+            if ( sc->chan ) { sc->chan = 0; wakeup((void *)&sc->chan); }
+            return(EINVAL);
+        }
         req->cmd_pkt->cmd.pkt_g.generic.request_id = (u_int8_t) req->request_id;
 
     }