diff --git a/lib/SCSI2SD/src/firmware/mode.c b/lib/SCSI2SD/src/firmware/mode.c index 0cac7275..68e4e099 100755 --- a/lib/SCSI2SD/src/firmware/mode.c +++ b/lib/SCSI2SD/src/firmware/mode.c @@ -3,6 +3,7 @@ // Copyright (C) 2019 Landon Rodgers // Copyright (c) 2024-2025 Rabbit Hole Computing™ // Copyright (C) 2024 jokker +// Copyright (c) 2026 Eric Helgeson // This file is part of SCSI2SD. // // SCSI2SD is free software: you can redistribute it and/or modify @@ -679,6 +680,13 @@ static void doModeSelect(void) int idx; int blockDescLen; + + // SCSI2 8.2.8: the command shall be terminated with CHECK CONDITION + // if the parameter list length truncates the mode parameter header, + // the block descriptor(s), or a mode page. + int headerLen = (scsiDev.cdb[0] == 0x55) ? 8 : 4; + if (scsiDev.dataLen < headerLen) goto badLength; + if (scsiDev.cdb[0] == 0x55) { blockDescLen = @@ -691,6 +699,9 @@ static void doModeSelect(void) idx = 4; } + // The header check above guarantees dataLen >= idx. + if (blockDescLen > scsiDev.dataLen - idx) goto badLength; + // The unwritten rule. Blocksizes are normally set using the // block descriptor value, not by changing page 0x03. if (blockDescLen >= 8) @@ -724,8 +735,9 @@ static void doModeSelect(void) int pageCode = scsiDev.data[idx] & 0x3F; if (pageCode == 0) goto out; + if (idx + 2 > scsiDev.dataLen) goto badLength; int pageLen = scsiDev.data[idx + 1]; - if (idx + 2 + pageLen > scsiDev.dataLen) goto bad; + if (idx + 2 + pageLen > scsiDev.dataLen) goto badLength; switch (pageCode) { @@ -767,6 +779,15 @@ static void doModeSelect(void) } goto out; + +// SCSI2 8.2.8 separates a parameter list that is too short for what it +// describes (1Ah) from one whose contents are unsupported (26h). +badLength: + scsiDev.status = CHECK_CONDITION; + scsiDev.target->sense.code = ILLEGAL_REQUEST; + scsiDev.target->sense.asc = PARAMETER_LIST_LENGTH_ERROR; + goto out; + bad: scsiDev.status = CHECK_CONDITION; scsiDev.target->sense.code = ILLEGAL_REQUEST;