{"record":{"id":"3b95d3a2d9024b79","repo":"Hmbown/CodeWhale","slug":"android-loaded-image-authorities-disagree-dladdr","errorCode":null,"errorMessage":"Android loaded-image authorities disagree: dladdr resolved to {}, but /proc/self/maps resolved to {}","messagePattern":"Android loaded-image authorities disagree: dladdr resolved to (.+?), but /proc/self/maps resolved to (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/update.rs","lineNumber":449,"sourceCode":") -> Result<AndroidExecutableProof> {\n    let mapping = parse_android_image_mapping(maps, marker)?;\n    validate_android_reported_path(\"dladdr\", dladdr_path)?;\n    validate_android_reported_path(\"/proc/self/maps\", &mapping.path)?;\n\n    let resolved_dladdr = dladdr_path.canonicalize().with_context(|| {\n        format!(\n            \"failed to canonicalize Android dladdr path {}\",\n            dladdr_path.display()\n        )\n    })?;\n    let resolved_mapping = mapping.path.canonicalize().with_context(|| {\n        format!(\n            \"failed to canonicalize Android loaded-image mapping {}\",\n            mapping.path.display()\n        )\n    })?;\n    if resolved_dladdr != resolved_mapping {\n        bail!(\n            \"Android loaded-image authorities disagree: dladdr resolved to {}, but /proc/self/maps resolved to {}\",\n            resolved_dladdr.display(),\n            resolved_mapping.display()\n        );\n    }\n    if is_android_linker_name(&resolved_mapping) {\n        bail!(\n            \"Android loaded-image authorities resolved to runtime linker {}; refusing to use the linker as an update target\",\n            resolved_mapping.display()\n        );\n    }\n    if !is_executable_file(&resolved_mapping) {\n        bail!(\n            \"Android loaded image `{}` is not an executable regular file; refusing to select an update target\",\n            resolved_mapping.display()\n        );\n    }\n","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/update.rs#L431-L467","documentation":"The Android self-update proof cross-checks two independent authorities for the location of the running executable: dladdr (the dynamic linker's answer for the object containing the marker function) and the /proc/self/maps row covering the same address. After canonicalizing both paths, if they differ the updater cannot prove which file it is actually running from and refuses to proceed, since replacing the wrong file could corrupt an unrelated binary.","triggerScenarios":"android_loaded_executable_proof (during self-update) when canonicalize() of the dladdr-reported path and the maps-reported path yield different absolute paths for the same marker address.","commonSituations":"Symlink or bind-mount setups where one authority reports the symlink path and the other the real path outside the resolver's view; running from an overlay/twerged filesystem where canonicalization diverges; a stale maps row after the binary was replaced mid-run.","solutions":["Check whether the binary path involves symlinks or bind mounts; run the update from the canonical, real path of the executable.","Re-run the updater after re-installing the binary so dladdr and /proc/self/maps refer to the same inode; do not replace the binary underneath a running process.","Verify the filesystem supports canonicalization consistently (avoid overlayfs quirks or FUSE mounts that report different paths).","If it persists, capture the two reported paths from the error message and file a bug with that output."],"exampleFix":"// before: running updater through a symlink\n$PREFIX/bin/codewhale update   # $PREFIX/bin/codewhale -> /data/.../bin/codewhale.real\n// after: run the real path directly\n/data/app/.../bin/codewhale.real update","handlingStrategy":"validation","validationCode":"let via_dladdr = std::fs::canonicalize(dladdr_path)?;\nlet via_maps = std::fs::canonicalize(maps_path)?;\nif via_dladdr != via_maps {\n    eprintln!(\"authority mismatch: {via_dladdr:?} vs {via_maps:?}; refusing self-update\");\n    return Err(anyhow!(\"loaded-image authorities disagree\"));\n}","typeGuard":null,"tryCatchPattern":"match run_update() {\n    Err(e) if e.to_string().contains(\"authorities disagree\") => {\n        // fall back to manual install instructions\n    }\n    other => other?,\n}","preventionTips":["Avoid launching the updater through symlinks or bind mounts.","Update only from the canonical real path of the binary.","Do not replace the binary while a process is running from it.","Test self-update on your actual Android filesystem (overlayfs, FUSE) before relying on it."],"tags":["android","self-update","dladdr","procfs"],"backgroundTag":"internal-invariant-violation","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"}