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
- Match on an executable ('x') mapping containing the marker — update the scanning logic to iterate until an executable mapping for the marker is found.
- Take the address marker from the code (text) section, not data, so the matched mapping is executable.
- 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
- Take the proof marker address from the code (text) segment so the matched mapping is executable.
- Scan all maps lines covering the marker, not just the first.
- Unit-test the maps parser against real Android /proc/self/maps samples.
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
- loaded-image mapping for updater marker has no file inode
- loaded-image mapping for updater marker has no pathname
- Android dladdr could not locate the updater's loaded image
- Android dladdr returned an empty loaded-image path
- Android identifies runtime linker ` `; refusing to use the…
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)