-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
A scan of the codebase found unchecked arithmetic operations on usize values derived from untrusted guest input. These can cause panics in debug builds (via Rust's overflow checks) when a malicious guest supplies crafted values.
Findings
1. 🔴 HIGH: Underflow in socket address write — litebox_shim_linux/src/syscalls/net.rs:1150
Code:
UnixSocketAddr::Path(path) => {
let offset = offset_of!(CSockUnixAddr, path);
let max_len = addrlen_val as usize - offset; // ← no guardIssue: addrlen_val is read directly from a guest-provided *addrlen pointer (line 1106). offset is the compile-time constant offset_of!(CSockUnixAddr, path) (typically 2 on all platforms). If the guest sets the addrlen value to 0 or 1, the subtraction addrlen_val as usize - offset underflows and panics in debug builds.
Note the inconsistency: the Abstract variant above (lines 1136–1145) correctly guards with if addrlen_val as usize > offset { ... } before a similar subtraction, but the Path variant lacks this guard entirely.
Severity: High — directly triggered by guest-supplied addrlen value.
Fix:
let max_len = (addrlen_val as usize).saturating_sub(offset);
// or add a guard:
if addrlen_val as usize <= offset {
return Ok(());
}
let max_len = addrlen_val as usize - offset;2. 🔴 HIGH: Overflow in robust list futex address calculation — litebox_shim_linux/src/syscalls/process.rs:478 and :494
Code:
// line 470: both values read from guest memory via head.read_at_offset(0)
let futex_offset = head.futex_offset; // guest-controlled usize
// line 478
handle_futex_death(
crate::ConstPtr::from_usize(entry.as_usize() + futex_offset), // ← overflow
...
)?;
// line 494
handle_futex_death(
crate::ConstPtr::from_usize(pending.as_usize() + futex_offset), // ← overflow
...
)?;Issue: Both entry (from head.list.next) and futex_offset (from head.futex_offset) are read from the guest's RobustListHead structure, which is set by the guest via set_robust_list. The guest can set entry to a near-MAX address and futex_offset to any value, making the sum overflow and panic in debug builds.
Note: In the Linux kernel, futex_offset is a signed long (it can be negative) but is declared here as usize, which is an additional semantic concern.
Severity: High — both operands are directly from guest-controlled memory.
Fix:
// Use wrapping_add to avoid debug panic; the resulting pointer will be
// validated by the read/write access check inside handle_futex_death.
crate::ConstPtr::from_usize(entry.as_usize().wrapping_add(futex_offset))
crate::ConstPtr::from_usize(pending.as_usize().wrapping_add(futex_offset))3. 🟡 MEDIUM: Overflow in argv/envp pointer advancement — litebox_shim_linux/src/syscalls/process.rs:1314
Code:
// base is a ConstPtr into user space (argv/envp array)
base = crate::ConstPtr::from_usize(base.as_usize() + core::mem::size_of::(usize)());Issue: base is a guest-provided pointer to the argv or envp array. If the current base value is within size_of::(usize)() bytes of usize::MAX, incrementing it overflows and panics in debug builds. The resulting wrapped pointer would then be read on the next loop iteration.
Severity: Medium — the guest controls the initial pointer value, but triggering this requires placing the pointer at an extreme address.
Fix:
base = crate::ConstPtr::from_usize(base.as_usize().wrapping_add(core::mem::size_of::(usize)()));4. 🟡 MEDIUM: Unchecked arithmetic in ELF loader — litebox_common_linux/src/loader.rs:420–423
Code:
// p_vaddr, p_filesz, p_memsz come from ELF program headers (guest binary)
// base_addr comes from mapper.reserve() for ET_DYN
let adjusted_vaddr = base_addr + p_vaddr; // ← no combined overflow check
let file_end = page_align_up(adjusted_vaddr + p_filesz); // ← no check
let load_end = page_align_up(adjusted_vaddr + p_memsz); // ← no checkIssue: Lines 409–414 validate that p_vaddr + p_memsz does not overflow in isolation, but do not check for overflow when base_addr is added. For ET_DYN binaries (where base_addr > 0 is chosen by the allocator), a carefully crafted ELF with a large p_vaddr could overflow base_addr + p_vaddr. The subsequent additions of p_filesz and p_memsz can compound this.
Severity: Medium — triggered by a malicious ELF binary; base_addr = 0 for ET_EXEC so only affects dynamically-linked (ET_DYN) executables.
Fix:
let adjusted_vaddr = base_addr.checked_add(p_vaddr).ok_or(ElfLoadError::InvalidProgramHeader)?;
let file_end = adjusted_vaddr.checked_add(p_filesz).map(page_align_up).ok_or(ElfLoadError::InvalidProgramHeader)?;
let load_end = adjusted_vaddr.checked_add(p_memsz).map(page_align_up).ok_or(ElfLoadError::InvalidProgramHeader)?;Non-Issues (False Positives Investigated)
The following patterns were examined and found to be safe:
signal/mod.rs:266and:353(stack.sp + stack.size):set_sigaltstackvalidates this sum withsp.checked_add(size).is_none()at line 312 before storing; the stored values are safe to add.ldelf.rs:71,81,206,252: Protected bychecked_addvalidations fortotal_sizebefore the mmap call; the mmap-returned address is kernel-allocated far fromusize::MAX.signal/x86.rsandsignal/x86_64.rs: All frame address arithmetic already useswrapping_sub/wrapping_add— correctly hardened.
Background
This type of vulnerability is documented in the repository's memory as a known class: wrapping arithmetic (wrapping_sub, wrapping_add) should be used instead of direct operators on usize values derived from untrusted guest registers or guest-provided memory structures, to prevent debug-mode overflow panics.
Generated by Integer Overflow Scanner