From nobody Wed Mar 4 17:30:21 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4fR0712zj3z6SnW0 for ; Wed, 04 Mar 2026 17:30:21 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4fR0711gqGz3xtt for ; Wed, 04 Mar 2026 17:30:21 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772645421; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=0HFC45LzAekJ8v7menuO6YQTCJ2EsLLArt2yAS16rjg=; b=ZoRGKazSYkljjPRiWf0mCl79gLorobZl/TXbDTUKHhXEXw1hTE0SbRSW4RYeaI+cRxwXxe I9EIhnozrwz1RyRnIH8CohMEqFQPDovvMj1f00+ZyThV/njEq3aEZlnlOUvWki6DPurll0 8mtParmNXJB3Hs9meMXPtdKjnAg2FZx8hlBltzSGmpx1L0/5Ye1n4fNiTSfgqZBtWdt3Wb nKV8uhpPhV6u5PGj32TkNje3I96+2/c1MqvNIK91Co+FrUWokLADYhwxd0JWFbivJWJaa3 P4GUivSH3n7mRRDWaLxKh6lU0Q9S+7omkX/UwsysA21bkvUVD7EUaBkD/RL/Vg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1772645421; a=rsa-sha256; cv=none; b=mIsDEabkf4T3VDKAREGo3kSi+ysk4Dd81Oznou1vTEOBY8jhrvOiJGqdTSQysn0bgAcXFY RfRk09Sk/nVGWpeg/fJSfELdmirH6q+ByOLwqM7thQ6B+6DwuGBnSS92SLL8CJU7eSzMCb 61QisbqW4/KPhdx+jg4iVU+3TUERTrhI1Noh+q9j6vTnbc+6KcLSGxQumWKobNB1zpXV1W bciI21HlR9jJYIFlr/2thZof/ZrC3j/WCXiPaTX4UJi//V4fXlPufFUFuuVY3zKFEn61Cy LksFDOg9dWrE6gmepBCWbheS0XJ2GaDBD0qV6IVSaG6uzVsIuf959Xz4c3JZCg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1772645421; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=0HFC45LzAekJ8v7menuO6YQTCJ2EsLLArt2yAS16rjg=; b=rObHKlI64VqbGTfsGY2s7hHit9lU6X3MTJsJOSvBpRqQRrXauttw6cX5oQgkbu3iRBcKYB 6bFcyzRzyq37dOxaEneikrKyKOTdJvrurbvNBO+dMK9hYTgGXU818uydz2G3ogHAZGJBIj mbTTZbxE9HefEX62Wz6AN3zQOP0X9pvGFstINvE6pItyOw0735FKY/FlK00qwnp5caDYl3 tyDY4X4Eg2mv/+v1N0EuhVc7VeBMQ4GzV1KO22WEth5F2fobuI0B0wrb2Dk7gj9qhN0W/2 R1X105dy5V4Bc/WuqSb/GFNwyx2q6b+sBebAD/TV9nZkIlLFWxN9jTnSVvGfIw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4fR0711Gylz10Xt for ; Wed, 04 Mar 2026 17:30:21 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 409ab by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 04 Mar 2026 17:30:21 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Hans Rosenfeld From: Ed Maste Subject: git: 4dfeadc32e46 - main - bhyve/virtio-scsi: Check LUN address validity List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: emaste X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 4dfeadc32e464557c2aa450212ac419bc567d1e6 Auto-Submitted: auto-generated Date: Wed, 04 Mar 2026 17:30:21 +0000 Message-Id: <69a86c2d.409ab.42ac10c5@gitrepo.freebsd.org> The branch main has been updated by emaste: URL: https://cgit.FreeBSD.org/src/commit/?id=4dfeadc32e464557c2aa450212ac419bc567d1e6 commit 4dfeadc32e464557c2aa450212ac419bc567d1e6 Author: Hans Rosenfeld AuthorDate: 2025-10-28 08:51:26 +0000 Commit: Ed Maste CommitDate: 2026-03-04 17:30:02 +0000 bhyve/virtio-scsi: Check LUN address validity Instead of blindly trusting the guest OS driver that it sends us well- formed LUN addresses, check the LUN address for validity and fail the request if it is invalid. While here, constify the members of the virtio requests which aren't device-writable anyway. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D53470 --- usr.sbin/bhyve/pci_virtio_scsi.c | 123 ++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 15 deletions(-) diff --git a/usr.sbin/bhyve/pci_virtio_scsi.c b/usr.sbin/bhyve/pci_virtio_scsi.c index 758e2643f6a0..dafff50fa531 100644 --- a/usr.sbin/bhyve/pci_virtio_scsi.c +++ b/usr.sbin/bhyve/pci_virtio_scsi.c @@ -200,10 +200,10 @@ struct pci_vtscsi_softc { #define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 struct pci_vtscsi_ctrl_tmf { - uint32_t type; - uint32_t subtype; - uint8_t lun[8]; - uint64_t id; + const uint32_t type; + const uint32_t subtype; + const uint8_t lun[8]; + const uint64_t id; uint8_t response; } __attribute__((packed)); @@ -216,9 +216,9 @@ struct pci_vtscsi_ctrl_tmf { #define VIRTIO_SCSI_EVT_ASYNC_DEVICE_BUSY 64 struct pci_vtscsi_ctrl_an { - uint32_t type; - uint8_t lun[8]; - uint32_t event_requested; + const uint32_t type; + const uint8_t lun[8]; + const uint32_t event_requested; uint32_t event_actual; uint8_t response; } __attribute__((packed)); @@ -249,12 +249,12 @@ struct pci_vtscsi_event { } __attribute__((packed)); struct pci_vtscsi_req_cmd_rd { - uint8_t lun[8]; - uint64_t id; - uint8_t task_attr; - uint8_t prio; - uint8_t crn; - uint8_t cdb[]; + const uint8_t lun[8]; + const uint64_t id; + const uint8_t task_attr; + const uint8_t prio; + const uint8_t crn; + const uint8_t cdb[]; } __attribute__((packed)); struct pci_vtscsi_req_cmd_wr { @@ -271,7 +271,10 @@ static void pci_vtscsi_reset(void *); static void pci_vtscsi_neg_features(void *, uint64_t); static int pci_vtscsi_cfgread(void *, int, int, uint32_t *); static int pci_vtscsi_cfgwrite(void *, int, int, uint32_t); -static inline int pci_vtscsi_get_lun(uint8_t *); + +static inline bool pci_vtscsi_check_lun(const uint8_t *); +static inline int pci_vtscsi_get_lun(const uint8_t *); + static void pci_vtscsi_control_handle(struct pci_vtscsi_softc *, void *, size_t); static void pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *, struct pci_vtscsi_ctrl_tmf *); @@ -398,9 +401,76 @@ pci_vtscsi_cfgwrite(void *vsc __unused, int offset __unused, int size __unused, return (0); } +/* + * LUN address parsing + * + * The LUN address consists of 8 bytes. While the spec describes this as 0x01, + * followed by the target byte, followed by a "single-level LUN structure", + * this is actually the same as a hierarchical LUN address as defined by SAM-5, + * consisting of four levels of addressing, where in each level the two MSB of + * byte 0 select the address mode used in the remaining bits and bytes. + * + * + * Only the first two levels are acutally used by virtio-scsi: + * + * Level 1: 0x01, 0xTT: Peripheral Device Addressing: Bus 1, Target 0-255 + * Level 2: 0xLL, 0xLL: Peripheral Device Addressing: Bus MBZ, LUN 0-255 + * or: Flat Space Addressing: LUN (0-16383) + * Level 3 and 4: not used, MBZ + * + * Currently, we only support Target 0. + * + * Alternatively, the first level may contain an extended LUN address to select + * the REPORT_LUNS well-known logical unit: + * + * Level 1: 0xC1, 0x01: Extended LUN Adressing, Well-Known LUN 1 (REPORT_LUNS) + * Level 2, 3, and 4: not used, MBZ + * + * The virtio spec says that we SHOULD implement the REPORT_LUNS well-known + * logical unit but we currently don't. + * + * According to the virtio spec, these are the only LUNS address formats to be + * used with virtio-scsi. + */ + +/* + * Check that the given LUN address conforms to the virtio spec, does not + * address an unknown target, and especially does not address the REPORT_LUNS + * well-known logical unit. + */ +static inline bool +pci_vtscsi_check_lun(const uint8_t *lun) +{ + if (lun[0] == 0xC1) + return (false); + + if (lun[0] != 0x01) + return (false); + + if (lun[1] != 0x00) + return (false); + + if (lun[2] != 0x00 && (lun[2] & 0xc0) != 0x40) + return (false); + + if (lun[4] != 0 || lun[5] != 0 || lun[6] != 0 || lun[7] != 0) + return (false); + + return (true); +} + +/* + * Get the LUN id from a LUN address. + * + * Every code path using this function must have called pci_vtscsi_check_lun() + * before to make sure the LUN address is valid. + */ static inline int -pci_vtscsi_get_lun(uint8_t *lun) +pci_vtscsi_get_lun(const uint8_t *lun) { + assert(lun[0] == 0x01); + assert(lun[1] == 0x00); + assert(lun[2] == 0x00 || (lun[2] & 0xc0) == 0x40); return (((lun[2] << 8) | lun[3]) & 0x3fff); } @@ -444,6 +514,16 @@ pci_vtscsi_tmf_handle(struct pci_vtscsi_softc *sc, union ctl_io *io; int err; + if (pci_vtscsi_check_lun(tmf->lun) == false) { + DPRINTF("TMF request to invalid LUN %.2hhx%.2hhx-%.2hhx%.2hhx-" + "%.2hhx%.2hhx-%.2hhx%.2hhx", tmf->lun[0], tmf->lun[1], + tmf->lun[2], tmf->lun[3], tmf->lun[4], tmf->lun[5], + tmf->lun[6], tmf->lun[7]); + + tmf->response = VIRTIO_SCSI_S_BAD_TARGET; + return; + } + io = ctl_scsi_alloc_io(sc->vss_iid); if (io == NULL) { WPRINTF("failed to allocate ctl_io: err=%d (%s)", @@ -670,6 +750,19 @@ pci_vtscsi_queue_request(struct pci_vtscsi_softc *sc, struct vqueue_info *vq) assert(iov_to_buf(req->vsr_iov_in, req->vsr_niov_in, (void **)&req->vsr_cmd_rd) == VTSCSI_IN_HEADER_LEN(q->vsq_sc)); + /* Make sure this request addresses a valid LUN. */ + if (pci_vtscsi_check_lun(req->vsr_cmd_rd->lun) == false) { + DPRINTF("I/O request to invalid LUN " + "%.2hhx%.2hhx-%.2hhx%.2hhx-%.2hhx%.2hhx-%.2hhx%.2hhx", + req->vsr_cmd_rd->lun[0], req->vsr_cmd_rd->lun[1], + req->vsr_cmd_rd->lun[2], req->vsr_cmd_rd->lun[3], + req->vsr_cmd_rd->lun[4], req->vsr_cmd_rd->lun[5], + req->vsr_cmd_rd->lun[6], req->vsr_cmd_rd->lun[7]); + req->vsr_cmd_wr->response = VIRTIO_SCSI_S_BAD_TARGET; + pci_vtscsi_return_request(q, req, 1); + return; + } + pthread_mutex_lock(&q->vsq_rmtx); pci_vtscsi_put_request(&q->vsq_requests, req); pthread_cond_signal(&q->vsq_cv);