{"record":{"id":"0f73d60e1a0aadf3","repo":"Hmbown/CodeWhale","slug":"loaded-image-mapping-for-updater-marker-is-not-exe","errorCode":null,"errorMessage":"loaded-image mapping for updater marker is not executable","messagePattern":"loaded-image mapping for updater marker is not executable","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/update.rs","lineNumber":385,"sourceCode":"\n        let permissions = fields\n            .next()\n            .context(\"loaded-image mapping is missing permissions\")?;\n        let _offset = fields\n            .next()\n            .context(\"loaded-image mapping is missing its file offset\")?;\n        let device = fields\n            .next()\n            .context(\"loaded-image mapping is missing its device\")?;\n        let inode = fields\n            .next()\n            .context(\"loaded-image mapping is missing its inode\")?\n            .parse::<u64>()\n            .context(\"loaded-image mapping has an invalid inode\")?;\n        let path = fields.collect::<Vec<_>>().join(\" \");\n\n        if permissions.as_bytes().get(2) != Some(&b'x') {\n            bail!(\"loaded-image mapping for updater marker is not executable\");\n        }\n        if inode == 0 {\n            bail!(\"loaded-image mapping for updater marker has no file inode\");\n        }\n        let (device_major, device_minor) = device\n            .split_once(':')\n            .context(\"loaded-image mapping has an invalid device\")?;\n        let device_major = u32::from_str_radix(device_major, 16)\n            .context(\"loaded-image mapping has an invalid device major number\")?;\n        let device_minor = u32::from_str_radix(device_minor, 16)\n            .context(\"loaded-image mapping has an invalid device minor number\")?;\n        if path.is_empty() {\n            bail!(\"loaded-image mapping for updater marker has no pathname\");\n        }\n\n        let mapping = AndroidImageMapping {\n            start,\n            end,","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/update.rs#L367-L403","documentation":"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.","triggerScenarios":"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).","commonSituations":"Marker address resolving into a non-executable section; unusual map layouts under hardened Android runtimes; custom linkers changing segment layout.","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."],"exampleFix":"// before\nif permissions.as_bytes().get(2) != Some(&b'x') {\n    bail!(\"loaded-image mapping for updater marker is not executable\");\n}\n// after\n// (scanner fix) continue scanning subsequent maps lines until\n// the mapping containing the marker has 'x' in its permissions","handlingStrategy":"validation","validationCode":"// check the maps line you rely on is executable before parsing it\nlet is_exec = line.split_whitespace().nth(1)\n    .map(|perm| perm.as_bytes().get(2) == Some(&b'x'))\n    .unwrap_or(false);","typeGuard":"fn is_exec_mapping(perm: &str) -> bool { perm.as_bytes().get(2) == Some(&b'x') }","tryCatchPattern":"match parse_android_image_mapping(line) {\n    Err(e) if e.to_string().contains(\"not executable\") => continue, // scan next line\n    other => other?,\n}","preventionTips":["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."],"tags":["android","proc-maps","self-update","platform"],"backgroundTag":"unexpected-response-shape","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}