The branch stable/14 has been updated by emaste:

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

commit 29937d7a1a0a3061c6ae12b5b35cc32b03829501
Author:     Alan Somers <[email protected]>
AuthorDate: 2024-09-04 14:38:11 +0000
Commit:     Ed Maste <[email protected]>
CommitDate: 2024-09-04 14:59:52 +0000

    ctl: fix Use-After-Free in ctl_write_buffer
    
    The virtio_scsi device allows a guest VM to directly send SCSI commands
    to the kernel driver exposed on /dev/cam/ctl. This setup makes the
    vulnerability directly accessible from VMs through the pci_virtio_scsi
    bhyve device.
    
    The function ctl_write_buffer sets the CTL_FLAG_ALLOCATED flag, causing
    the kern_data_ptr to be freed when the command finishes processing.
    However, the buffer is still stored in lun->write_buffer, leading to a
    Use-After-Free vulnerability.
    
    Since the buffer needs to persist indefinitely, so it can be accessed by
    READ BUFFER, do not set CTL_FLAG_ALLOCATED.
    
    Reported by:    Synacktiv
    Reviewed by:    Pierre Pronchery <[email protected]>
    Reviewed by:    jhb
    Security:       FreeBSD-SA-24:11.ctl
    Security:       CVE-2024-45063
    Security:       HYP-03
    Sponsored by:   Axcient
    Sponsored by:   The Alpha-Omega Project
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D46424
    
    (cherry picked from commit 670b582db6cb827a8760df942ed8af0020a0b4d0)
---
 sys/cam/ctl/ctl.c         | 19 +++++++++++--------
 sys/cam/ctl/ctl_private.h |  8 ++++++++
 2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/sys/cam/ctl/ctl.c b/sys/cam/ctl/ctl.c
index 1d5e13ad4671..b449e05889ec 100644
--- a/sys/cam/ctl/ctl.c
+++ b/sys/cam/ctl/ctl.c
@@ -5673,21 +5673,24 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
                return (CTL_RETVAL_COMPLETE);
        }
 
+       if (lun->write_buffer == NULL) {
+               lun->write_buffer = malloc(CTL_WRITE_BUFFER_SIZE,
+                   M_CTL, M_WAITOK);
+       }
+
        /*
-        * If we've got a kernel request that hasn't been malloced yet,
-        * malloc it and tell the caller the data buffer is here.
+        * If this kernel request hasn't started yet, initialize the data
+        * buffer to the correct region of the LUN's write buffer.  Note that
+        * this doesn't set CTL_FLAG_ALLOCATED since this points into a
+        * persistent buffer belonging to the LUN rather than a buffer
+        * dedicated to this request.
         */
-       if ((ctsio->io_hdr.flags & CTL_FLAG_ALLOCATED) == 0) {
-               if (lun->write_buffer == NULL) {
-                       lun->write_buffer = malloc(CTL_WRITE_BUFFER_SIZE,
-                           M_CTL, M_WAITOK);
-               }
+       if (ctsio->kern_data_ptr == NULL) {
                ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
                ctsio->kern_data_len = len;
                ctsio->kern_total_len = len;
                ctsio->kern_rel_offset = 0;
                ctsio->kern_sg_entries = 0;
-               ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
                ctsio->be_move_done = ctl_config_move_done;
                ctl_datamove((union ctl_io *)ctsio);
 
diff --git a/sys/cam/ctl/ctl_private.h b/sys/cam/ctl/ctl_private.h
index 04846f80e913..db8e748ec014 100644
--- a/sys/cam/ctl/ctl_private.h
+++ b/sys/cam/ctl/ctl_private.h
@@ -411,6 +411,14 @@ struct ctl_lun {
        uint8_t                         pr_res_type;
        int                             prevent_count;
        uint32_t                        *prevent;
+
+       /*
+        * The READ_BUFFER and WRITE_BUFFER commands permit access to a logical
+        * data buffer associated with a LUN.  Accesses to the data buffer do
+        * not affect data stored on the storage medium.  To support this,
+        * allocate a buffer on first use that persists until the LUN is
+        * destroyed.
+        */
        uint8_t                         *write_buffer;
        struct ctl_devid                *lun_devid;
        TAILQ_HEAD(tpc_lists, tpc_list) tpc_lists;

Reply via email to