Show Notes

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 iovecs 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.