Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deployment/simple-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ verify_module_files() {
push "$work/files.tar" /data/local/tmp/eip-module-files.tar
push "$work/manifest" /data/local/tmp/eip-module-manifest
push "$work/names" /data/local/tmp/eip-module-names
phone 'tar -xf /data/local/tmp/eip-module-files.tar -C /data/adb/modules/eip-pixel8a-forge && chown -R 0:0 /data/adb/modules/eip-pixel8a-forge && cd /data/adb/modules/eip-pixel8a-forge && /data/adb/ksu/bin/busybox sha256sum -c /data/local/tmp/eip-module-manifest -s && find . -type f | sed "s|^\\./||" | LC_ALL=C sort | LC_ALL=C comm -23 - /data/local/tmp/eip-module-names | while IFS= read -r stale; do case "$stale" in disable|remove|update|skip_mount) continue ;; esac; rm -f "$stale"; done; n_names=$(wc -l < /data/local/tmp/eip-module-names); n_files=$(find . -type f | wc -l); n_markers=0; for m in disable remove update skip_mount; do [ -f "$m" ] && n_markers=$((n_markers + 1)); done; if [ "$n_files" -ne $((n_names + n_markers)) ]; then printf 'module tree contains unexpected files beyond the payload and module-state markers\n' >&2; exit 5; fi; rm -f /data/local/tmp/eip-module-files.tar /data/local/tmp/eip-module-manifest /data/local/tmp/eip-module-names; exit 0' \
phone 'tar -xf /data/local/tmp/eip-module-files.tar -C /data/adb/modules/eip-pixel8a-forge && chown -R 0:0 /data/adb/modules/eip-pixel8a-forge && cd /data/adb/modules/eip-pixel8a-forge && /data/adb/ksu/bin/busybox sha256sum -c /data/local/tmp/eip-module-manifest -s && find . -type f | sed "s|^\\./||" | LC_ALL=C sort | LC_ALL=C comm -23 - /data/local/tmp/eip-module-names | while IFS= read -r stale; do case "$stale" in disable|remove|update|skip_mount) continue ;; esac; rm -f "$stale"; done; n_names=$(wc -l < /data/local/tmp/eip-module-names); n_files=$(find . -type f | wc -l); n_markers=0; for m in disable remove update skip_mount; do [ -f "$m" ] && n_markers=$((n_markers + 1)); done; if [ "$n_files" -ne $((n_names + n_markers)) ]; then printf "module tree contains unexpected files beyond the payload and module-state markers\n" >&2; exit 5; fi; rm -f /data/local/tmp/eip-module-files.tar /data/local/tmp/eip-module-manifest /data/local/tmp/eip-module-names; exit 0' \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified this fix and it's correct.

Before this change, the printf '...' inside the (already single-quoted) phone '...' argument closed the outer quote early. Locally in bash, that split the intended one-argument command into several word-split arguments; since phone() only reads $1, the remote script that actually reached the device was truncated right at ...then printf — an unterminated if. On a real device shell that's a syntax error, so su -c fails non-zero and the local || die 'installed module files do not match the payload' fires. Worse, by the time the parser hits that error, the preceding tar -xf, chown -R 0:0, and the stale-file rm -f "$stale" pruning loop have already run — so the module tree gets partially mutated even though the size/count safety check (the very if block meant to catch unexpected leftover files) and the final cleanup/exit 0 never execute.

Switching the inner printf to double quotes removes the only other literal ' in the string, so the whole thing is now one well-formed single-quoted argument again — I scanned it and confirmed there's exactly one opening and one closing '.

The new /bin/dash -n parse-check in tests/simple-installer.test.mjs (line 323) is well-targeted: it validates the exact string phone() hands to the device shell, which is precisely what would have caught this regression. ubuntu-latest (used in .github/workflows/check.yml) always ships /bin/dash, so no portability concern there.

Scope-wise this PR only touches these two files — no DEVICE.json/build-target, kernel config, Wi-Fi policy, Docker startup, or packaging changes, and nothing that looks like firmware/credentials/generated-artifact inclusion. No further issues found.

|| die 'installed module files do not match the payload'
rm -rf "$work"
}
Expand Down
8 changes: 8 additions & 0 deletions tests/simple-installer.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ async function fakeToolMain() {
return;
}
if (command.startsWith("tar -xf /data/local/tmp/eip-module-files.tar")) {
// The phone command must parse before anything else: a quoting break in
// the assembled string truncated it on a real device and no other check
// caught it.
const parse = spawnSync("/bin/dash", ["-n"], { input: command, encoding: "utf8" });
if (parse.status !== 0) {
process.stderr.write(`phone command does not parse: ${parse.stderr}\n`);
process.exit(98);
}
// Reproduce the phone-side proof on the host: extract the pushed overlay
// and verify it against the pushed manifest with the same flags.
const staged = fs.mkdtempSync(`${env.FAKE_PUSH_DIR}/verify-`);
Expand Down