mirror of
https://git.FreeBSD.org/src.git
synced 2024-10-19 02:29:40 +00:00
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 <pierre@freebsdfoundation.org>
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 670b582db6
)
This commit is contained in:
parent
90af1336ed
commit
29937d7a1a
@ -5673,21 +5673,24 @@ ctl_write_buffer(struct ctl_scsiio *ctsio)
|
|||||||
return (CTL_RETVAL_COMPLETE);
|
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,
|
* If this kernel request hasn't started yet, initialize the data
|
||||||
* malloc it and tell the caller the data buffer is here.
|
* 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 (ctsio->kern_data_ptr == NULL) {
|
||||||
if (lun->write_buffer == NULL) {
|
|
||||||
lun->write_buffer = malloc(CTL_WRITE_BUFFER_SIZE,
|
|
||||||
M_CTL, M_WAITOK);
|
|
||||||
}
|
|
||||||
ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
|
ctsio->kern_data_ptr = lun->write_buffer + buffer_offset;
|
||||||
ctsio->kern_data_len = len;
|
ctsio->kern_data_len = len;
|
||||||
ctsio->kern_total_len = len;
|
ctsio->kern_total_len = len;
|
||||||
ctsio->kern_rel_offset = 0;
|
ctsio->kern_rel_offset = 0;
|
||||||
ctsio->kern_sg_entries = 0;
|
ctsio->kern_sg_entries = 0;
|
||||||
ctsio->io_hdr.flags |= CTL_FLAG_ALLOCATED;
|
|
||||||
ctsio->be_move_done = ctl_config_move_done;
|
ctsio->be_move_done = ctl_config_move_done;
|
||||||
ctl_datamove((union ctl_io *)ctsio);
|
ctl_datamove((union ctl_io *)ctsio);
|
||||||
|
|
||||||
|
@ -411,6 +411,14 @@ struct ctl_lun {
|
|||||||
uint8_t pr_res_type;
|
uint8_t pr_res_type;
|
||||||
int prevent_count;
|
int prevent_count;
|
||||||
uint32_t *prevent;
|
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;
|
uint8_t *write_buffer;
|
||||||
struct ctl_devid *lun_devid;
|
struct ctl_devid *lun_devid;
|
||||||
TAILQ_HEAD(tpc_lists, tpc_list) tpc_lists;
|
TAILQ_HEAD(tpc_lists, tpc_list) tpc_lists;
|
||||||
|
Loading…
Reference in New Issue
Block a user