Skip to content

elf_patch_cache is keyed by a recyclable fd number #1316

Description

@CvvT

A bug found by our static analysis tool

Severity: High
File: litebox_shim_linux/src/syscalls/mm.rs

/// Per-process collection of ELF patching state, keyed by fd number.
pub(crate) type ElfPatchCache = BTreeMap<i32, ElfPatchState>;

The documentation states the flaw. do_close_and_replace vacates the fd slot
under the descriptor-store guard, drops it, and only then runs the subsystem
teardown that calls finalize_elf_patch(raw_fd). Between those two points the
number is free and the next open receives it.

Two consequences follow:

fn init_elf_patch_state(&self, fd: i32, mapped_addr: usize, file_offset: usize) {
    // Quick check: skip if already initialized.
    if self.global.elf_patch_cache.lock().contains_key(&fd) {
        return;
    }
  • The new file inherits the closed file's state — its trampoline_addr,
    pre_patched flag and cursor — because the key is already present.
  • The pending finalize_elf_patch then deletes that state, and if
    trampoline_mapped was set it munmaps state.trampoline_addr, an address
    belonging to a mapping the closer never owned.

Evidence. syscalls::mm::tests::patch_state_is_not_inherited_by_a_recycled_fd:

assertion `left != right` failed: fd 3 now belongs to /other, but the patch cache
still keys /patched's state to it
  left: Some(3735879680)      // 0xdead0000, the marker seeded for /patched
 right: Some(3735879680)

The test seeds the cache entry directly rather than driving a real ELF mmap,
because init_elf_patch_state parses an ELF header and the test filesystem has
no ELF fixture. The interleaving, the fd reuse and the inheritance are real; only
the provenance of the state object is synthetic.

Suggested fix. Key the cache on file identity rather than the fd integer, or
finalise the patch state under the same guard that vacates the slot.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions