forked from Manuel/meeting-assistant
Read Recovery version from current guest SystemVersion evidence
This commit is contained in:
@@ -99,26 +99,56 @@ read_scalar() {
|
||||
SCALAR="$value"
|
||||
}
|
||||
|
||||
# BEGIN successful sw_vers version parser
|
||||
read_product_version() {
|
||||
local value status line version="" fields=0
|
||||
# Read the entire successful native output. EOF is mandatory; a NUL delimiter
|
||||
# or reaching the 1025-byte sentinel must never hide a suffix.
|
||||
LC_ALL=C IFS= read -r -n 1025 -d '' value < "$LAST_OUTPUT"; status=$?
|
||||
(( status == 1 && ${#value} <= 1024 )) || return 1
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
if [[ "$line" =~ ^[[:blank:]]*ProductVersion: ]]; then
|
||||
fields=$((fields + 1))
|
||||
(( fields == 1 )) || return 1
|
||||
[[ "$line" =~ ^[[:blank:]]*ProductVersion:[[:blank:]]*([0-9]+\.[0-9]+(\.[0-9]+)?)[[:blank:]]*$ ]] || return 1
|
||||
version="${BASH_REMATCH[1]}"
|
||||
# BEGIN native SystemVersion plist request helpers
|
||||
read_native_system_version() {
|
||||
# Recovery has Bash 3.2 before .NET. Read bytes here; XML is parsed by the
|
||||
# existing owned host controller, never by shell or VERSION metadata.
|
||||
local LC_ALL=C source="/System/Library/CoreServices/SystemVersion.plist"
|
||||
local value status owner reply started=$SECONDS invalid_bytes
|
||||
local raw="$STATE_DIR/native-system-version.plist"
|
||||
local ready="$STATE_DIR/native-system-version.request"
|
||||
local response="$STATE_DIR/native-system-version.reply"
|
||||
NATIVE_VERSION_ERROR=native_system_version_read_failed
|
||||
printf '[native-version-start] method=guest-file/host-xml source=%s seconds=%s\n' "$source" "$started" >&3
|
||||
IFS= read -r -n 81 -d '' owner < "$STATE_DIR/run.owner"; status=$?
|
||||
(( status == 1 && ${#owner} <= 80 )) &&
|
||||
[ "$owner" = "$PROOF_TOKEN"$'\n' ] || { NATIVE_VERSION_ERROR=native_system_version_foreign_owner; return 1; }
|
||||
[ ! -e "$ready" ] && [ ! -L "$ready" ] &&
|
||||
[ ! -e "$raw" ] && [ ! -L "$raw" ] &&
|
||||
[ ! -e "$response" ] && [ ! -L "$response" ] || { NATIVE_VERSION_ERROR=native_system_version_stale_exchange; return 1; }
|
||||
[ -f "$source" ] || return 1
|
||||
IFS= read -r -n 4097 -d '' value < "$source"; status=$?
|
||||
# EOF is mandatory. NUL stops read with status 0; 4097 is the overbound sentinel.
|
||||
(( status == 1 && ${#value} > 0 && ${#value} <= 4096 )) || { NATIVE_VERSION_ERROR=native_system_version_invalid_bytes; return 1; }
|
||||
invalid_bytes=${value//$'\t'/}
|
||||
invalid_bytes=${invalid_bytes//$'\r'/}
|
||||
invalid_bytes=${invalid_bytes//$'\n'/}
|
||||
[[ "$invalid_bytes" =~ [[:cntrl:]] ]] && { NATIVE_VERSION_ERROR=native_system_version_binary; return 1; }
|
||||
printf '%s' "$value" > "$raw" || return 1
|
||||
# Publish this final marker only after the complete raw write has closed.
|
||||
printf '%s\n%s\n%s\nready:%s\n' "$PROOF_TOKEN" "$source" "${#value}" "$PROOF_TOKEN" > "$ready" || return 1
|
||||
printf '[native-version-request] method=guest-file/host-xml source=%s bytes=%s seconds=%s\n' "$source" "${#value}" "$SECONDS" >&3
|
||||
while (( SECONDS - started < 180 )); do
|
||||
if [ -e "$response" ] || [ -L "$response" ]; then
|
||||
[ -f "$response" ] && [ ! -L "$response" ] || { NATIVE_VERSION_ERROR=native_system_version_invalid_reply; return 1; }
|
||||
IFS= read -r -n 81 -d '' reply < "$response"; status=$?
|
||||
(( status == 1 && ${#reply} <= 80 )) && [[ "$reply" = *$'\n' ]] || { NATIVE_VERSION_ERROR=native_system_version_invalid_reply; return 1; }
|
||||
reply=${reply%$'\n'}
|
||||
if [[ "$reply" =~ ^([0-9a-f]{32}):([0-9]+\.[0-9]+(\.[0-9]+)?)$ ]] && [ "${BASH_REMATCH[1]}" = "$PROOF_TOKEN" ]; then
|
||||
SCALAR="${BASH_REMATCH[2]}"
|
||||
NATIVE_VERSION_ERROR=""
|
||||
printf '[native-version-result] method=guest-file/host-xml source=%s version=%s elapsed=%ss\n' "$source" "$SCALAR" "$((SECONDS - started))" >&3
|
||||
return 0
|
||||
fi
|
||||
NATIVE_VERSION_ERROR=native_system_version_rejected_reply
|
||||
return 1
|
||||
fi
|
||||
done <<< "$value"
|
||||
(( fields == 1 )) || return 1
|
||||
SCALAR="$version"
|
||||
IFS= read -r -t 1 -u 9 unused || :
|
||||
done
|
||||
NATIVE_VERSION_ERROR=native_system_version_reply_timeout
|
||||
return 1
|
||||
}
|
||||
|
||||
# END successful sw_vers version parser
|
||||
# END native SystemVersion plist request helpers
|
||||
# BEGIN disk IPC diagnostic
|
||||
# Optional observations have their own child/timer ownership. Thread state/time
|
||||
# targets only this probe's diskutil and does not request stack symbolication.
|
||||
@@ -283,24 +313,9 @@ run_command uid /usr/bin/id -u
|
||||
read_scalar || fail_probe uid_output_invalid
|
||||
uid="$SCALAR"
|
||||
[ "$uid" = 0 ] || fail_probe recovery_account_not_root
|
||||
run_command platform /usr/bin/sw_vers
|
||||
platform_exit="$LAST_EXIT"
|
||||
flush_outputs || finish false diagnostic_log_budget_exceeded
|
||||
if (( platform_exit != 0 )); then
|
||||
run_command system /bin/launchctl print system
|
||||
system_exit="$LAST_EXIT"
|
||||
run_command arbitration /bin/launchctl print system/com.apple.diskarbitrationd
|
||||
arbitration_exit="$LAST_EXIT"
|
||||
run_command recovery /bin/launchctl print system/com.apple.recoveryosd
|
||||
recovery_exit="$LAST_EXIT"
|
||||
printf '[proof-retry] sw_vers once after native service context; same 45-second deadline\n' >&3
|
||||
run_command platform-warm /usr/bin/sw_vers
|
||||
platform_exit="$LAST_EXIT"
|
||||
fi
|
||||
(( platform_exit == 0 )) || fail_probe sw_vers_failed
|
||||
# BEGIN successful sw_vers version extraction
|
||||
read_product_version || fail_probe product_version_invalid
|
||||
# END successful sw_vers version extraction
|
||||
# BEGIN native SystemVersion plist getter
|
||||
read_native_system_version || fail_probe "$NATIVE_VERSION_ERROR"
|
||||
# END native SystemVersion plist getter
|
||||
os_version="$SCALAR"
|
||||
[[ "$os_version" =~ ^[0-9]+\.[0-9]+(\.[0-9]+)?$ ]] || fail_probe product_version_invalid
|
||||
(( ${os_version%%.*} >= 14 )) || fail_probe unsupported_macos_version
|
||||
|
||||
Reference in New Issue
Block a user