@samitouri / QOSamiQemu / commits / 6c712a86f6

hw/ide: reject an unsupported CHS translation

ide_set_sector() divides by (s->heads * s->sectors) when the drive is addressed in CHS mode. Both come from the guest via INITIALIZE DEVICE PARAMETERS, and cmd_specify() stored them without any check, so a guest asking for zero sectors per logical track killed QEMU with SIGFPE on the completion of the first CHS read or write. s->heads is safe, as the command passes a heads-1 value. The count has an upper bound as well. The legacy sector count register is eight bits wide, but handle_cmd() takes the count from a 16 bit field of the register FIS, so an AHCI guest can ask for up to 65535 sectors per track, and the CHS branch of ide_get_sector() then overflows the int it multiplies cylinder, heads and sectors in. ATA-5 6.2 numbers CHS sectors from one and ATA-2 D.2.8 limits IDENTIFY DEVICE word 56 to 1 through 255, so neither end is a translation a device may accept. ATA-5 8.16.6 requires an unsupported one to be reported as an aborted command: do that, leave the translation in effect alone, and refuse the value rather than checking it at every use. Cc: John Snow <jsnow@redhat.com> Cc: Peter Maydell <peter.maydell@linaro.org> Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Cc: qemu-stable@nongnu.org Fixes: 176e4961bb33 ("hw/ide/core.c: Implement ATA INITIALIZE_DEVICE_PARAMETERS command") Reported-by: Zheyu Ma <zheyuma97@gmail.com> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2399 Signed-off-by: Denis V. Lunev <den@openvz.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>

Denis V. Lunev committed Aug 14, 2026 at 15:35 UTC 6c712a86f6c8d8bdd8a3ba6b39cbcd9550668c36
1 file changed +12 -5
hw/ide/core.c
+12 -5
@@ -1655,14 +1655,21 @@ static bool cmd_check_power_mode(IDEState *s, uint8_t cmd)
1655 /* INITIALIZE DEVICE PARAMETERS */
1656 static bool cmd_specify(IDEState *s, uint8_t cmd)
1657 {
1658 - if (s->blk && s->drive_kind != IDE_CD) {
1659 - s->heads = (s->select & (ATA_DEV_HS)) + 1;
1660 - s->sectors = s->nsector;
1661 - ide_bus_set_irq(s->bus);
1662 - } else {
1658 + if (!s->blk || s->drive_kind == IDE_CD) {
1659 + ide_abort_command(s);
1660 + return true;
1661 + }
1662 +
1663 + /* ATA-2 D.2.8 limits IDENTIFY DEVICE word 56, and the count, to 1..255 */
1664 + if (s->nsector == 0 || s->nsector > 255) {
1665 ide_abort_command(s);
1666 + return true;
1667 }
1668
1669 + s->heads = (s->select & (ATA_DEV_HS)) + 1;
1670 + s->sectors = s->nsector;
1671 + ide_bus_set_irq(s->bus);
1672 +
1673 return true;
1674 }
1675