fix: validate command lock process identity - #286
Conversation
Command locks previously stored only a PID, so a stale lock could survive a host reboot and block container management after Android reused that PID. Store process start ticks and the boot ID with new locks, while retaining read compatibility and conservative fallbacks for older lock formats. Share proc starttime parsing with socketd to avoid duplicate logic. Signed-off-by: UmiSlat <275275677+UmiSlat@users.noreply.github.com>
External command locks stored only the CLI PID and trusted kill(pid, 0) == 0 as proof the holder was still running. A lock left behind by a reboot mid-command survives on persistent storage, and after boot Android almost always hands that PID to an unrelated long-lived process, so every later command on the container fails with "Cannot acquire lock: held by process N" until the file is deleted by hand. Reported against v6.4.5, where PID 4806 was reused by com.android.systemui after a reboot (PR #286). A lock holder is always a CLI process, so no lock can legitimately outlive a boot. Stamp locks as "<pid> <boot-id>" and accept only that exact format with a matching boot ID and a live PID. Anything else, including pid-only locks from older versions, is removed and the command proceeds, since a bare PID cannot be told apart from post-reboot PID reuse. Stale lock cleanup is logged with the [DEBUG] tag, so it reaches the container log file but not the terminal. Older binaries atoi() the new format and still read the leading PID. Co-authored-by: UmiSlat <275275677+UmiSlat@users.noreply.github.com> Signed-off-by: ravindu644 <droidcasts@protonmail.com>
|
Thanks for this, confirmed real. The lock lives on persistent storage, nothing sweeps it at boot, and as root kill(pid, 0) succeeds against any live process, so a reboot mid-command plus Android's dense PID reuse bricks the container exactly as you described. I landed a smaller version of your fix on dev as 5d20069, with you as co-author. It keeps your core insight but leans on one invariant: a lock holder is always a CLI process, so no lock can legitimately outlive a boot. Locks are now stamped and only that exact format with a matching boot ID and a live PID counts as held. Anything else, including old pid-only locks, is removed and the command proceeds, since a bare PID cannot be told apart from PID reuse. That also made the starttime and comm checks unnecessary. Old binaries still atoi() the leading PID fine. Verified on device: the reported scenario now self-heals silently and a live lock still blocks a second command. Closing in favor of 5d20069. Thanks again for the excellent report and compatibility analysis. |
Problem
External command locks previously stored only the CLI PID and treated
kill(pid, 0) == 0as proof that the original owner was still running.This is unsafe when a stale lock survives a host reboot and Android reuses
the PID for an unrelated process.
The issue was reproduced with Droidspaces v6.4.5. The host rebooted while
the Debian13.6 container was running, leaving a lock owned by PID 4806.
After reboot, Android reused PID 4806 for
com.android.systemui, whose/proc/4806/commvalue wasTB_Client.Trying to stop the container then failed:
Solution
<pid> <proc-start-ticks> <boot-id>./proc/<pid>/statstarttime before accepting anexisting lock as active.
/proc/<pid>/commequalsdroidspaces.metadata is unavailable.
identity cannot be read.
cleanup.
maintaining duplicate implementations.
Compatibility
unavailable.
Testing
Regression harness:
The shared proc starttime parser was also tested with spaces and
)insidethe process command name:
GitHub CI passed on the final commit:
CI run:
https://github.com/UmiSlat/Droidspaces-OSS/actions/runs/32350081335
Tested environment
6.6.77-android15-8-g8d05d8f2439f6-ab10030741-4kThe fixed binary has not yet been installed for a complete live container
and host reboot lifecycle test. Kernel 3.10 real hardware has not been tested.