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
3 changes: 2 additions & 1 deletion modules/system-customize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2825,7 +2825,8 @@ xanmod_pending_allocation_proof_trusted() {
{
IFS= read -r proof_token || return 1
IFS= read -r proof_identity || return 1
if IFS= read -r extra_line; then
# read returns failure at EOF even after consuming an unterminated tail.
if IFS= read -r extra_line || [[ -n "$extra_line" ]]; then
return 1
fi
} < "$proof_path"
Expand Down
69 changes: 69 additions & 0 deletions tests/test-xanmod.sh
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,75 @@ make_layout "$TEST_DIR/tool"
# shellcheck source=../tools/xanmod-install.sh
source "$TOOL"
trap 'rm -rf "$TEST_DIR"' EXIT
# Proof parser fixtures: no APT, services or production paths.
(
proof_root="$TEST_DIR/proof-tail"
mkdir -m 0700 "$proof_root"
XANMOD_ALLOCATION_CANDIDATE="$proof_root/candidate"
XANMOD_ALLOCATION_KIND=file
XANMOD_ALLOCATION_OWNER_TOKEN=fixture-token
XANMOD_ALLOCATION_EXPECTED_MODE=600
touch "$XANMOD_ALLOCATION_CANDIDATE"
chmod 600 "$XANMOD_ALLOCATION_CANDIDATE"
proof="$proof_root/proof"
xanmod_allocation_proof_path() { printf "%s\n" "$proof"; }
identity=$(stat -c "%d:%i" "$XANMOD_ALLOCATION_CANDIDATE")
printf "%s\n%s\n" fixture-token "$identity" > "$proof"
chmod 600 "$proof"
assert_ok "exact two-line proof accepted" xanmod_pending_allocation_owned
for tail in unterminated "$identity"; do
printf "%s\n%s\n%s" fixture-token "$identity" "$tail" > "$proof"
assert_fail "unterminated proof tail rejected" xanmod_pending_allocation_proof_trusted
assert_fail "malformed proof cannot establish ownership" xanmod_pending_allocation_owned
[[ -f "$XANMOD_ALLOCATION_CANDIDATE" ]] || fail "candidate unexpectedly removed"
done
printf "%s\n%s\nextra\n" fixture-token "$identity" > "$proof"
assert_fail "complete third line rejected" xanmod_pending_allocation_owned
printf "%s\n%s\n\n" fixture-token "$identity" > "$proof"
assert_fail "empty third line rejected" xanmod_pending_allocation_owned

# Reproduce the old EOF mistake with inert text, not an old production script.
legacy_accepts_tail() {
local token identity extra_line
{
IFS= read -r token || return 1
IFS= read -r identity || return 1
if IFS= read -r extra_line; then return 1; fi
} < "$proof"
[[ "$token" == fixture-token && "$identity" =~ ^[0-9]+:[0-9]+$ ]]
}
printf "%s\n%s\ntail" fixture-token "$identity" > "$proof"
assert_ok "old parser incorrectly accepts unterminated tail" legacy_accepts_tail
assert_fail "fixed parser rejects same counterexample" xanmod_pending_allocation_proof_trusted

# Only candidate state without prior ownership is covered here.
# Residue/previously-owned resources use a separate existing cleanup contract.
# Exercise the real dispatcher; the deletion primitive is a spy.
cleanup_calls=0
xanmod_cleanup_created_allocation() { cleanup_calls=$((cleanup_calls + 1)); return 0; }
for candidate_exists in yes no; do
XANMOD_ALLOCATION_CANDIDATE="$proof_root/candidate"
XANMOD_ALLOCATION_KIND=file
XANMOD_ALLOCATION_OWNER_TOKEN=fixture-token
XANMOD_ALLOCATION_EXPECTED_MODE=600
XANMOD_ALLOCATION_STATE=candidate
XANMOD_ALLOCATION_PROOF_OWNED=false
if [[ "$candidate_exists" == no ]]; then command rm -- "$XANMOD_ALLOCATION_CANDIDATE"; fi
assert_ok "unowned candidate cleanup returns safely" cleanup_xanmod_pending_allocation
assert_eq "" "$XANMOD_ALLOCATION_CANDIDATE" "candidate path cleared"
assert_eq "" "$XANMOD_ALLOCATION_KIND" "allocation kind cleared"
assert_eq "" "$XANMOD_ALLOCATION_OWNER_TOKEN" "owner token cleared"
assert_eq "" "$XANMOD_ALLOCATION_EXPECTED_MODE" "expected mode cleared"
assert_eq "" "$XANMOD_ALLOCATION_STATE" "allocation state cleared"
assert_eq false "$XANMOD_ALLOCATION_PROOF_OWNED" "proof ownership remains false"
assert_eq 0 "$cleanup_calls" "malformed proof does not authorize deletion of unowned candidate"
[[ -f "$proof" ]] || fail "untrusted proof was removed"
if [[ "$candidate_exists" == yes ]]; then
[[ -f "$proof_root/candidate" ]] || fail "untrusted candidate was removed"
fi
done
)

OTHER_UID=65534; [[ "$OTHER_UID" == "$XANMOD_TRUSTED_UID" ]] && OTHER_UID=0
OTHER_GID=65534; [[ "$OTHER_GID" == "$XANMOD_TRUSTED_GID" ]] && OTHER_GID=0

Expand Down
3 changes: 2 additions & 1 deletion tools/xanmod-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,8 @@ xanmod_pending_allocation_proof_trusted() {
{
IFS= read -r proof_token || return 1
IFS= read -r proof_identity || return 1
if IFS= read -r extra_line; then
# read returns failure at EOF even after consuming an unterminated tail.
if IFS= read -r extra_line || [[ -n "$extra_line" ]]; then
return 1
fi
} < "$proof_path"
Expand Down