90 - HyperKit Bugs & an Open5GS Stack Overflow
When parsing session establishment request packets in ogs_fqdn_parse()
, the function would take an unmitigated length and pass it directly to memcpy()
. The blogpost indicates the destination is a stack buffer, leading to stack overflow. It’s worth noting the build config does enable stack cookies, so it wouldn’t be a straightforward exploit.
Four issues in HyperKit, a hypervisor based on bhyve used in docker for macOS.
Issue 1: vi_pci_read null vc_cfgread function pointer dereference (GHSL-2021-054)
Various handlers in the virtio
table might not be initialized by certain devices. One example is vc_cfgread()
in the vtrand
device. The vi_pci_read()
function doesn’t check if the handler is null and calls it directly, resulting in a null dereference. DoS only.
Issue 2: vi_pci_write null vc_cfgwrite function pointer dereference (GHSL-2021-055)
The same root cause as the first issue, but instead in the vi_pci_write
path.
Issue 3: vtrnd pci_vtrnd_notify uninitialized memory use (GHSL-2021-056)
Identical to a previously reported bhyve issue, where the vtrnd
device would fail to check the return value of vq_getchain()
, leading to usage of uninitialized iovec
objects, which can yield arbitrary read/write. For reference the previously covered bhyve issue: [https://dayzerosec.com/vulns/2021/09/08/code-execution-outside-the-virtualized-guest-in-bhyve-cve202129631.html]
Issue 4: virtio-sock pci_vtsock_proc_tx uninitialized memory use (GHSL-2021-057)
Similar to issue 3. pci_vtsock_proc_tx()
calls vq_getchain()
, and while it asserts the value isn’t too large, it doesn’t check for a fail return (-1). This again leads to using uninitialized iovec
s resulting in memory corruption.
pci_vtblk_proc
handling of incoming virtio
descriptiors and the VBH_OP_DISCORD
operation has a likely typo that allows for a guest to perform an out of bound memory read.
The problem is the following assert statement:
/* We currently limit the discard to one segment in the initial negotiation
so expect exactly one correctly-sized payload descriptor. */
assert(iov[1].iov_len = sizeof(struct virtio_blk_discard_write_zeroes));
The comment above the assert indicates that the assert is there to ensure a correct payload descriptor, however the assert itself does not check equality but rather performs an assignment to iov[1].iov_len
. Leading to a mismatched, and potentially too long iov_len
value being used.