Skip to content

Integer overflow scan: potential unsafe usize arithmetic on guest-derived values #8

@github-actions

Description

@github-actions

Integer Overflow Scan Results

Scanned the following directories for arithmetic operations on usize values that could derive from untrusted guest input:

  • litebox_shim_linux/src/syscalls/
  • litebox_shim_optee/src/syscalls/
  • litebox_common_linux/src/
  • All files referencing PtRegs, esp, rsp, frame_addr, etc.

Good news: signal frame arithmetic is already safe

The core signal delivery code (litebox_shim_linux/src/syscalls/signal/x86.rs and x86_64.rs) correctly uses wrapping_sub/wrapping_add for all arithmetic on guest register values (esp, rsp, frame_addr). No issues there.


Finding 1 — Medium severity

File: litebox_shim_linux/src/syscalls/signal/mod.rs:266

Unsafe pattern:

fn is_on_stack(stack: &SigAltStack, sp: usize) -> bool {
    if stack.flags.contains(SsFlags::DISABLE) {
        return false;
    }
    let stack_start = stack.sp;
    let stack_end = stack.sp + stack.size;  // ← raw + on guest-supplied values
    sp >= stack_start && sp < stack_end
}

stack.sp and stack.size originate from guest sigaltstack(2) syscall arguments. While set_sigaltstack() currently validates them with checked_add before storing (line 312), the is_on_stack() function relies on that implicit invariant rather than defensive arithmetic. If the invariant is ever loosened or a new code path introduces an unvalidated SigAltStack, this would silently overflow in release builds or panic in debug builds.

Suggested fix:

let stack_end = stack.sp.wrapping_add(stack.size);

Finding 2 — Medium severity

File: litebox_shim_linux/src/syscalls/signal/mod.rs:353

Unsafe pattern:

let sp = if switch_stacks {
    altstack.sp + altstack.size  // ← raw + on guest-supplied values
} else {
    sp
};

Same root cause as Finding 1: altstack.sp and altstack.size come from guest-provided sigaltstack(2) data. The invariant from set_sigaltstack() makes this safe today, but the pattern is fragile and inconsistent with the wrapping-arithmetic convention used in the adjacent signal-frame code.

Suggested fix:

let sp = if switch_stacks {
    altstack.sp.wrapping_add(altstack.size)
} else {
    sp
};

Finding 3 — Low severity (ELF loader)

File: litebox_common_linux/src/loader.rs:420–464

Unsafe pattern:

// Only p_vaddr + p_memsz is validated; base_addr + p_vaddr is not.
let adjusted_vaddr = base_addr + p_vaddr;          // line 420
let file_end = page_align_up(adjusted_vaddr + p_filesz); // line 422
let load_end = page_align_up(adjusted_vaddr + p_memsz);  // line 423
// ...
let unaligned_file_end = adjusted_vaddr + p_filesz; // line 443
phdrs_addr = adjusted_vaddr + offset_in_segment;    // line 464

p_vaddr, p_filesz, p_memsz, and offset_in_segment come from ELF program headers. The code validates p_vaddr.checked_add(p_memsz).is_none() (line 410), but not base_addr.checked_add(p_vaddr). For ET_DYN binaries, base_addr is chosen by the host memory mapper; in practice the reservation bounds make overflow unlikely. For ET_EXEC (where base_addr = 0), the existing checked_add for p_vaddr + p_memsz is sufficient. Nonetheless, raw + on values derived (however indirectly) from file-supplied ELF headers is a fragile pattern that could become exploitable if the loading path or mapper changes.

Suggested fix: Add an explicit overflow check for base_addr + p_vaddr alongside the existing validation:

if p_memsz < p_filesz
    || p_vaddr.checked_add(p_memsz).is_none()
    || base_addr.checked_add(p_vaddr).is_none()   // ← new check
    || ph.p_offset.checked_add(ph.p_filesz).is_none()
{
    return Err(ElfLoadError::InvalidProgramHeader);
}
let adjusted_vaddr = base_addr + p_vaddr; // now safe

And for adjusted_vaddr + p_filesz / + p_memsz — since after the above check base_addr + p_vaddr is known to not overflow, and p_vaddr + p_memsz is known to not overflow, the remaining additions are bounded. Alternatively use wrapping_add for defense in depth.


Summary table

# File Line Guest-derived values Current protection Risk
1 litebox_shim_linux/src/syscalls/signal/mod.rs 266 stack.sp, stack.size (via sigaltstack syscall) Validated in set_sigaltstack — implicit invariant Medium
2 litebox_shim_linux/src/syscalls/signal/mod.rs 353 altstack.sp, altstack.size (via sigaltstack syscall) Validated in set_sigaltstack — implicit invariant Medium
3 litebox_common_linux/src/loader.rs 420–464 p_vaddr, p_filesz, p_memsz, offset_in_segment (from ELF file) p_vaddr + p_memsz is checked; base_addr + p_vaddr is not Low

Generated by Integer Overflow Scanner

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions