git: a8df23541444 - releng/14.1 - ctl: limit memory allocation in pci_virtio_scsi

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Tue, 29 Oct 2024 18:45:37 UTC
The branch releng/14.1 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=a8df23541444f6630a572bcce90ba26327ba25df

commit a8df23541444f6630a572bcce90ba26327ba25df
Author:     Pierre Pronchery <pierre@freebsdfoundation.org>
AuthorDate: 2024-07-19 17:32:27 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2024-10-29 18:44:17 +0000

    ctl: limit memory allocation in pci_virtio_scsi
    
    The virtio_scsi device allows a VM guest to directly send SCSI commands
    (ctsio->cdb array) to the kernel driver exposed on /dev/cam/ctl
    (ctl.ko).
    
    All kernel commands accessible from the guest are defined by
    ctl_cmd_table.
    
    The command ctl_persistent_reserve_out (cdb[0]=0x5F and cbd[1]=0) allows
    the caller to call malloc() with an arbitrary size (uint32_t). This can
    be used by the guest to overload the kernel memory (DOS attack).
    
    Reported by:    Synacktiv
    Reviewed by:    asomers
    Security:       HYP-08
    Security:       FreeBSD-SA-24:18.ctl
    Approved by:    so
    Sponsored by:   The Alpha-Omega Project
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D46044
    
    (cherry picked from commit 64b0f52be2c9d7bcecebfeef393f8ec56cb85f47)
    (cherry picked from commit 2e7f4728fa738a7a7b6c4e4c46eb68952386efce)
---
 sys/cam/ctl/ctl.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 0e0d79d15d8f..420d9088c27b 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -8320,6 +8320,18 @@ ctl_persistent_reserve_out(struct ctl_scsiio *ctsio)
 
 	param_len = scsi_4btoul(cdb->length);
 
+	/* validate the parameter length */
+	if (param_len != 24) {
+		ctl_set_invalid_field(ctsio,
+				/*sks_valid*/ 1,
+				/*command*/ 1,
+				/*field*/ 5,
+				/*bit_valid*/ 1,
+				/*bit*/ 0);
+		ctl_done((union ctl_io *)ctsio);
+		return (CTL_RETVAL_COMPLETE);
+	}
+
 	if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
 		ctsio->kern_data_ptr = malloc(param_len, M_CTL, M_WAITOK);
 		ctsio->kern_data_len = param_len;