Hmbown/CodeWhale · error

loaded-image mapping for updater marker is not executable

Error message

loaded-image mapping for updater marker is not executable

What it means

parse_android_image_mapping parses a /proc/self/maps line to prove the loaded image is backed by a real executable file. It bails when the mapping's permission field lacks 'x' at position 3, meaning the mapping containing the updater marker is not an executable mapping and therefore not proof of the executable file's identity.

Solutions

  1. Match on an executable ('x') mapping containing the marker — update the scanning logic to iterate until an executable mapping for the marker is found.
  2. Take the address marker from the code (text) section, not data, so the matched mapping is executable.
  3. Fall back to dladdr or /proc/self/exe for the executable identity if maps scanning is unreliable in this environment.

Example fix

// before
if permissions.as_bytes().get(2) != Some(&b'x') {
    bail!("loaded-image mapping for updater marker is not executable");
}
// after
// (scanner fix) continue scanning subsequent maps lines until
// the mapping containing the marker has 'x' in its permissions
Defensive patterns

Strategy: validation

Validate before calling

// check the maps line you rely on is executable before parsing it
let is_exec = line.split_whitespace().nth(1)
    .map(|perm| perm.as_bytes().get(2) == Some(&b'x'))
    .unwrap_or(false);

Type guard

fn is_exec_mapping(perm: &str) -> bool { perm.as_bytes().get(2) == Some(&b'x') }

Try / catch

match parse_android_image_mapping(line) {
    Err(e) if e.to_string().contains("not executable") => continue, // scan next line
    other => other?,
}

Prevention

When it happens

Trigger: android_loaded_executable_proof_report scanning /proc/self/maps when the first mapping whose address range contains the marker has non-executable permissions (e.g. 'rw-p' data segment or 'r--p' mapping matched instead of the 'r-xp' text segment).

Common situations: Marker address resolving into a non-executable section; unusual map layouts under hardened Android runtimes; custom linkers changing segment layout.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/0f73d60e1a0aadf3. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/update.rs:385

        let permissions = fields
            .next()
            .context("loaded-image mapping is missing permissions")?;
        let _offset = fields
            .next()
            .context("loaded-image mapping is missing its file offset")?;
        let device = fields
            .next()
            .context("loaded-image mapping is missing its device")?;
        let inode = fields
            .next()
            .context("loaded-image mapping is missing its inode")?
            .parse::<u64>()
            .context("loaded-image mapping has an invalid inode")?;
        let path = fields.collect::<Vec<_>>().join(" ");

        if permissions.as_bytes().get(2) != Some(&b'x') {
            bail!("loaded-image mapping for updater marker is not executable");
        }
        if inode == 0 {
            bail!("loaded-image mapping for updater marker has no file inode");
        }
        let (device_major, device_minor) = device
            .split_once(':')
            .context("loaded-image mapping has an invalid device")?;
        let device_major = u32::from_str_radix(device_major, 16)
            .context("loaded-image mapping has an invalid device major number")?;
        let device_minor = u32::from_str_radix(device_minor, 16)
            .context("loaded-image mapping has an invalid device minor number")?;
        if path.is_empty() {
            bail!("loaded-image mapping for updater marker has no pathname");
        }

        let mapping = AndroidImageMapping {
            start,
            end,

View on GitHub (pinned to 73e0f67d83)