⬢ DragonFlyBSD Kernel Audit
DF-4399 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/raid/tws/tws_cam.c
+++ b/sys/dev/raid/tws/tws_cam.c
@@ -1031,10 +1031,21 @@
              GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) !=
                             TWS_FW_CMD_EXECUTE_SCSI) ||
               req->type == TWS_GETSET_PARAM_REQ) {
+            u_int16_t ent_u32;
             gcmd = &req->cmd_pkt->cmd.pkt_g.generic;
+            ent_u32 = (req->sc->is64bit && !tws_use_32bit_sgls) ? 4 : 2;
+            /*
+             * gcmd->size arrives from the passthrough ioctl and is used as
+             * the SGL offset (u32 units). Never let the SGL start beyond,
+             * or overflow, this request's own giga-packet body.
+             */
+            if ((u_int)gcmd->size + (u_int)sgls * ent_u32 >
+                (sizeof(union tws_command_giga) / 4)) {
+                req->error_code = TWS_REQ_ERR_INVALID;
+                return; /* do not submit the command */
+            }
             sgl_ptr = (u_int32_t *)(gcmd) + gcmd->size;
-            gcmd->size += sgls *
-                          ((req->sc->is64bit && !tws_use_32bit_sgls) ? 4 :2 );
+            gcmd->size += sgls * ent_u32;
             tws_fill_sg_list(req->sc, segs, sgl_ptr, sgls);
 
         } else {