All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Denis V. Lunev" <den@openvz.org>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org, "Denis V. Lunev" <den@openvz.org>,
	"John Snow" <jsnow@redhat.com>,
	"Philippe Mathieu-Daudé" <philmd@oss.qualcomm.com>
Subject: [PATCH 07/11] hw/ide/ahci: reject a command header with an invalid FIS length
Date: Thu, 20 Aug 2026 16:43:05 +0200	[thread overview]
Message-ID: <20260820144309.835173-8-den@openvz.org> (raw)
In-Reply-To: <20260820144309.835173-1-den@openvz.org>

From: Denis V. Lunev <den@openvz.org>

AHCI 1.3.1 defines CFL in the command header as the "Length of the
Command FIS", where "A length of '0' or '1' is illegal" and "The
maximum value allowed is 10h, or 16 DW". handle_cmd() never looks at
it, so an all-zero command header is executable: its zero tbl_addr maps
a command table at guest physical address 0, and a guest that has put a
valid Register H2D FIS there gets it run.

That is the reachability a guest gains by pointing PxCLB at an MMIO
region, where the CLB is a zero-filled bounce buffer rather than
anything the guest wrote.

Reject a header whose CFL falls outside the legal range. Nothing else
consults it; the command FIS is always mapped at its full 128 bytes.

The slot is dropped without reporting anything, as the unmappable
command table beside it already is. No PxIS bit describes a malformed
command header: HBFS is for a host bus error, "such as a bad software
pointer", which is why the short mapping below raises it and this does
not.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/4043
Cc: John Snow <jsnow@redhat.com>
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
 hw/ide/ahci.c       | 9 +++++++++
 hw/ide/trace-events | 1 +
 2 files changed, 10 insertions(+)

diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 436a0eaab6..2b2ef873e0 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1334,6 +1334,7 @@ static void handle_cmd(AHCIState *s, int port, uint8_t slot)
     AHCICmdHdr *cmd;
     uint8_t *cmd_fis;
     dma_addr_t cmd_len;
+    uint8_t cfl;
 
     if (s->dev[port].port.ifs[0].status & (BUSY_STAT|DRQ_STAT)) {
         /* Engine currently busy, try again later */
@@ -1346,6 +1347,14 @@ static void handle_cmd(AHCIState *s, int port, uint8_t slot)
         return;
     }
     cmd = get_cmd_header(s, port, slot);
+
+    /* AHCI 1.3.1: a CFL below 2 dwords or above 16 is illegal */
+    cfl = le16_to_cpu(cmd->opts) & AHCI_CMD_HDR_CMD_FIS_LEN;
+    if (cfl < 2 || cfl > 16) {
+        trace_handle_cmd_badcfl(s, port, le16_to_cpu(cmd->opts));
+        return;
+    }
+
     /* remember current slot handle for later */
     s->dev[port].cur_cmd = cmd;
 
diff --git a/hw/ide/trace-events b/hw/ide/trace-events
index f1472f5852..3ab5e7bd1d 100644
--- a/hw/ide/trace-events
+++ b/hw/ide/trace-events
@@ -106,6 +106,7 @@ handle_reg_h2d_fis_res(void *s, int port, char b0, char b1, char b2) "ahci(%p)[%
 handle_cmd_busy(void *s, int port) "ahci(%p)[%d]: engine busy"
 handle_cmd_nolist(void *s, int port) "ahci(%p)[%d]: handle_cmd called without s->dev[port].lst"
 handle_cmd_badport(void *s, int port) "ahci(%p)[%d]: guest accessed unused port"
+handle_cmd_badcfl(void *s, int port, uint16_t opts) "ahci(%p)[%d]: guest provided an invalid cmd FIS length: 0x%04x"
 handle_cmd_badfis(void *s, int port) "ahci(%p)[%d]: guest provided an invalid cmd FIS"
 handle_cmd_badmap(void *s, int port, uint64_t len) "ahci(%p)[%d]: dma_memory_map failed, 0x%02"PRIx64" != 0x80"
 handle_cmd_unhandled_fis(void *s, int port, uint8_t b0, uint8_t b1, uint8_t b2) "ahci(%p)[%d]: unhandled FIS type. cmd_fis: 0x%02x-%02x-%02x"
-- 
2.53.0



  parent reply	other threads:[~2026-08-20 14:43 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-20 14:42 [PATCH 00/11] hw/ide: pending IDE fixes Denis V. Lunev
2026-08-20 14:42 ` [PATCH 01/11] hw/ide: reject an out-of-range PIO transfer window on load Denis V. Lunev
2026-08-20 14:43 ` [PATCH 02/11] tests/qtest/ide-test: cover the migrated PIO transfer window Denis V. Lunev
2026-08-20 14:43 ` [PATCH 03/11] hw/ide/ahci: refuse a PIO transfer with no command header Denis V. Lunev
2026-08-20 14:43 ` [PATCH 04/11] hw/ide/ahci: clear cur_cmd when the command list is unmapped Denis V. Lunev
2026-08-20 14:43 ` [PATCH 05/11] tests/qtest/ahci: regression test for a PIO write vs. engine stop Denis V. Lunev
2026-08-20 14:43 ` [PATCH 06/11] hw/ide/ahci: treat a failed PRDT walk as a PIO transfer failure Denis V. Lunev
2026-08-20 14:43 ` Denis V. Lunev [this message]
2026-08-20 14:43 ` [PATCH 08/11] hw/ide/ahci: drain the ports on teardown Denis V. Lunev
2026-08-20 14:43 ` [PATCH 09/11] tests/qtest/ahci: regression test for a request outliving an unplug Denis V. Lunev
2026-08-20 14:43 ` [PATCH 10/11] hw/ide: report ATAPI UDMA5 with a matching standard and cable Denis V. Lunev
2026-08-20 14:43 ` [PATCH 11/11] tests/qtest/ide-test: cover the UDMA5 identify words Denis V. Lunev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260820144309.835173-8-den@openvz.org \
    --to=den@openvz.org \
    --cc=jsnow@redhat.com \
    --cc=philmd@oss.qualcomm.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.