287 lines
11 KiB
Shell
287 lines
11 KiB
Shell
|
|
#!/usr/bin/env bash
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
[[ $# -eq 2 ]] || {
|
||
|
|
echo "usage: test-native-resident-candidate.sh <candidate-image> <receipt-output>" >&2
|
||
|
|
exit 64
|
||
|
|
}
|
||
|
|
|
||
|
|
candidate=$(readlink -f "$1")
|
||
|
|
receipt=$(readlink -m "$2")
|
||
|
|
source_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||
|
|
native_root=${source_root}/native/x86_64-bios
|
||
|
|
test_root=$(mktemp -d)
|
||
|
|
serial_log=${test_root}/serial.log
|
||
|
|
serial_log_second=${test_root}/serial-second.log
|
||
|
|
disk_image=${test_root}/resident-layout.img
|
||
|
|
corrupt_disk_image=${test_root}/resident-layout-corrupt.img
|
||
|
|
peer_receipt=${test_root}/native-net-peer.hldp
|
||
|
|
peer_log=${test_root}/native-net-peer.log
|
||
|
|
peer_receipt_second=${test_root}/native-net-peer-second.hldp
|
||
|
|
peer_log_second=${test_root}/native-net-peer-second.log
|
||
|
|
peer_receipt_corrupt=${test_root}/native-net-peer-corrupt.hldp
|
||
|
|
peer_log_corrupt=${test_root}/native-net-peer-corrupt.log
|
||
|
|
serial_log_corrupt=${test_root}/serial-corrupt.log
|
||
|
|
peer_pid=
|
||
|
|
cleanup() {
|
||
|
|
if [[ -n ${peer_pid} ]]; then
|
||
|
|
kill "${peer_pid}" 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
if [[ ${GHOS_KEEP_TEST_ROOT:-0} != 1 ]]; then
|
||
|
|
rm -rf "${test_root}"
|
||
|
|
else
|
||
|
|
echo "GHOS_TEST_ROOT=${test_root}" >&2
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
trap cleanup EXIT
|
||
|
|
|
||
|
|
truncate -s 700M "${disk_image}"
|
||
|
|
nasm -f bin "${native_root}/physical-test-mbr.asm" \
|
||
|
|
-o "${test_root}/physical-test-mbr.bin"
|
||
|
|
dd if="${test_root}/physical-test-mbr.bin" of="${disk_image}" \
|
||
|
|
bs=512 seek=0 conv=notrunc status=none
|
||
|
|
dd if="${candidate}" of="${disk_image}" \
|
||
|
|
bs=512 seek=34 conv=notrunc status=none
|
||
|
|
|
||
|
|
peer_port=$((24000 + BASHPID % 10000))
|
||
|
|
qemu_port=$((peer_port + 1))
|
||
|
|
python3 "${source_root}/scripts/qemu-native-net-peer.py" \
|
||
|
|
--listen-port "${peer_port}" \
|
||
|
|
--qemu-port "${qemu_port}" \
|
||
|
|
--receipt "${peer_receipt}" \
|
||
|
|
--resident >"${peer_log}" 2>&1 &
|
||
|
|
peer_pid=$!
|
||
|
|
set +e
|
||
|
|
timeout 30 qemu-system-x86_64 \
|
||
|
|
-machine pc,accel=tcg \
|
||
|
|
-m 64M \
|
||
|
|
-drive "if=none,id=ghboot,format=raw,file=${disk_image}" \
|
||
|
|
-device virtio-blk-pci,drive=ghboot,disable-modern=on,bootindex=0 \
|
||
|
|
-netdev "dgram,id=ghnet,local.type=inet,local.host=127.0.0.1,local.port=${qemu_port},remote.type=inet,remote.host=127.0.0.1,remote.port=${peer_port}" \
|
||
|
|
-device virtio-net-pci,netdev=ghnet,disable-modern=on,mac=52:54:00:26:71:98 \
|
||
|
|
-display none \
|
||
|
|
-monitor none \
|
||
|
|
-serial "file:${serial_log}" \
|
||
|
|
-device isa-debug-exit,iobase=0xf4,iosize=0x04
|
||
|
|
qemu_status=$?
|
||
|
|
set -e
|
||
|
|
|
||
|
|
[[ ${qemu_status} -eq 33 ]]
|
||
|
|
wait "${peer_pid}"
|
||
|
|
peer_pid=
|
||
|
|
grep -q '^arp_gateway_reply: VERIFIED$' "${peer_receipt}"
|
||
|
|
grep -q '^icmp_login_reply_count: 3$' "${peer_receipt}"
|
||
|
|
grep -q '^code_commit_reply_verified: true$' "${peer_receipt}"
|
||
|
|
grep -q '^branch_move_reply_verified: true$' "${peer_receipt}"
|
||
|
|
grep -q '^resident_login_reply_count: 10$' "${peer_receipt}"
|
||
|
|
grep -q '^recovery_reply_verified: true$' "${peer_receipt}"
|
||
|
|
grep -q '^GHOS_NATIVE_RECOVERY_BEACON=WRITE_READ_VERIFIED' "${serial_log}"
|
||
|
|
grep -q '^GHOS_GHCIP_INDEX=INITIALIZED_WRITE_READ_VERIFIED' "${serial_log}"
|
||
|
|
grep -q '^GHOS_DISK_PROOF_OBSERVED_AFTER_RESET=LBA63' "${serial_log}"
|
||
|
|
|
||
|
|
python3 - "${disk_image}" <<'PY'
|
||
|
|
import pathlib
|
||
|
|
import sys
|
||
|
|
|
||
|
|
path = pathlib.Path(sys.argv[1])
|
||
|
|
with path.open("rb") as disk:
|
||
|
|
def sector(lba: int, count: int = 1) -> bytes:
|
||
|
|
disk.seek(lba * 512)
|
||
|
|
return disk.read(count * 512)
|
||
|
|
|
||
|
|
proof = sector(63)
|
||
|
|
assert proof[0] == 0xA7
|
||
|
|
assert proof[1:].startswith(b"GHOS_NATIVE_LONG64_DISK_PROOF\x00")
|
||
|
|
assert proof[42:44] == bytes([0x7F, 0x00])
|
||
|
|
assert proof[90] == 13
|
||
|
|
assert proof[93:99] == bytes([1, 1, 1, 1, 1, 1])
|
||
|
|
assert proof[99:102] == bytes([1, 1, 1])
|
||
|
|
assert proof[102:105] == bytes([1, 1, 1])
|
||
|
|
|
||
|
|
world_store = sector(64)
|
||
|
|
assert world_store.startswith(b"GHOS_HLDP_WORLD_STORE_V1\n")
|
||
|
|
assert b"GHOS_GESTATIONAL_ENVIRONMENT=UNDER_CONSTRUCTION\n" in world_store
|
||
|
|
assert b"GHOS_PERSONA_BIRTH=NOT_BORN\n" in world_store
|
||
|
|
code_store = sector(65)
|
||
|
|
assert code_store.startswith(b"GHOS_CODE_CHANNEL_STORE_V1\n")
|
||
|
|
assert sector(66) == code_store
|
||
|
|
branch_receipt = sector(67)
|
||
|
|
assert b"branch=guanghu/main\n" in branch_receipt
|
||
|
|
assert b"object_lba=66\n" in branch_receipt
|
||
|
|
|
||
|
|
recovery_beacon = sector(68, 2)
|
||
|
|
prefix = (
|
||
|
|
b"# GRUB Environment Block\n"
|
||
|
|
b"# WARNING: Do not edit this file by tools other than grub-editenv!!!\n"
|
||
|
|
b"guanghu_recovery=ubuntu\n"
|
||
|
|
)
|
||
|
|
assert len(recovery_beacon) == 1024
|
||
|
|
assert recovery_beacon.startswith(prefix)
|
||
|
|
assert recovery_beacon[len(prefix):] == b"#" * (1024 - len(prefix))
|
||
|
|
|
||
|
|
gestational_identity = sector(70)
|
||
|
|
assert gestational_identity.startswith(b"GHOS_GHCIP_INDEX_V1\n")
|
||
|
|
assert b"GHCIP_PROTOCOL=GLS-0845\n" in gestational_identity
|
||
|
|
assert b"GHCIP_CONTENT_ROLE=CONTENT_ADDRESSED_ROOT_INDEX_ONLY\n" in gestational_identity
|
||
|
|
gestational_root = sector(71)
|
||
|
|
assert gestational_root.startswith(b"GHOS_GHCIP_ROOT_V1\n")
|
||
|
|
assert b"GHCIP_REGISTRY_STATE=EMPTY\n" in gestational_root
|
||
|
|
assert b"GHCIP_REVIEW_STATE=NOT_STARTED\n" in gestational_root
|
||
|
|
assert b"GHCIP_HISTORICAL_TIME_WATERMARK=NONE\n" in gestational_root
|
||
|
|
assert b"GHCIP_PERSONA_STATE=NOT_BORN\n" in gestational_root
|
||
|
|
assert b"GHCIP_LAST_VERIFIED_BATCH=NONE\n" in gestational_root
|
||
|
|
PY
|
||
|
|
|
||
|
|
index_sha_before=$(dd if="${disk_image}" bs=512 skip=70 count=2 status=none |
|
||
|
|
sha256sum | awk '{print $1}')
|
||
|
|
dd if=/dev/zero of="${disk_image}" bs=512 seek=63 count=1 \
|
||
|
|
conv=notrunc status=none
|
||
|
|
peer_port_second=$((peer_port + 2))
|
||
|
|
qemu_port_second=$((qemu_port + 2))
|
||
|
|
python3 "${source_root}/scripts/qemu-native-net-peer.py" \
|
||
|
|
--listen-port "${peer_port_second}" \
|
||
|
|
--qemu-port "${qemu_port_second}" \
|
||
|
|
--receipt "${peer_receipt_second}" \
|
||
|
|
--resident >"${peer_log_second}" 2>&1 &
|
||
|
|
peer_pid=$!
|
||
|
|
set +e
|
||
|
|
timeout 30 qemu-system-x86_64 \
|
||
|
|
-machine pc,accel=tcg \
|
||
|
|
-m 64M \
|
||
|
|
-drive "if=none,id=ghboot,format=raw,file=${disk_image}" \
|
||
|
|
-device virtio-blk-pci,drive=ghboot,disable-modern=on,bootindex=0 \
|
||
|
|
-netdev "dgram,id=ghnet,local.type=inet,local.host=127.0.0.1,local.port=${qemu_port_second},remote.type=inet,remote.host=127.0.0.1,remote.port=${peer_port_second}" \
|
||
|
|
-device virtio-net-pci,netdev=ghnet,disable-modern=on,mac=52:54:00:26:71:98 \
|
||
|
|
-display none \
|
||
|
|
-monitor none \
|
||
|
|
-serial "file:${serial_log_second}" \
|
||
|
|
-device isa-debug-exit,iobase=0xf4,iosize=0x04
|
||
|
|
qemu_status=$?
|
||
|
|
set -e
|
||
|
|
|
||
|
|
[[ ${qemu_status} -eq 33 ]]
|
||
|
|
wait "${peer_pid}"
|
||
|
|
peer_pid=
|
||
|
|
grep -q '^icmp_login_reply_count: 3$' "${peer_receipt_second}"
|
||
|
|
grep -q '^code_commit_reply_verified: true$' "${peer_receipt_second}"
|
||
|
|
grep -q '^branch_move_reply_verified: true$' "${peer_receipt_second}"
|
||
|
|
grep -q '^resident_login_reply_count: 10$' "${peer_receipt_second}"
|
||
|
|
grep -q '^recovery_reply_verified: true$' "${peer_receipt_second}"
|
||
|
|
grep -q '^GHOS_GHCIP_INDEX=PRESENT_READ_VERIFIED' "${serial_log_second}"
|
||
|
|
if grep -q '^GHOS_GHCIP_INDEX=INITIALIZED_WRITE_READ_VERIFIED' "${serial_log_second}"; then
|
||
|
|
echo "second native boot rewrote the existing GHCIP index" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
index_sha_after=$(dd if="${disk_image}" bs=512 skip=70 count=2 status=none |
|
||
|
|
sha256sum | awk '{print $1}')
|
||
|
|
[[ ${index_sha_before} == "${index_sha_after}" ]]
|
||
|
|
python3 - "${disk_image}" <<'PY'
|
||
|
|
import pathlib
|
||
|
|
import sys
|
||
|
|
|
||
|
|
with pathlib.Path(sys.argv[1]).open("rb") as disk:
|
||
|
|
disk.seek(63 * 512)
|
||
|
|
proof = disk.read(512)
|
||
|
|
assert proof[0] == 0xA7
|
||
|
|
assert proof[102:105] == bytes([0, 1, 1])
|
||
|
|
PY
|
||
|
|
|
||
|
|
cp "${disk_image}" "${corrupt_disk_image}"
|
||
|
|
dd if=/dev/zero of="${corrupt_disk_image}" bs=512 seek=63 count=1 \
|
||
|
|
conv=notrunc status=none
|
||
|
|
printf '\x58' | dd of="${corrupt_disk_image}" bs=1 seek=$((70 * 512)) \
|
||
|
|
count=1 conv=notrunc status=none
|
||
|
|
corrupt_index_sha_before=$(dd if="${corrupt_disk_image}" bs=512 skip=70 count=2 \
|
||
|
|
status=none | sha256sum | awk '{print $1}')
|
||
|
|
peer_port_corrupt=$((peer_port + 4))
|
||
|
|
qemu_port_corrupt=$((qemu_port + 4))
|
||
|
|
python3 "${source_root}/scripts/qemu-native-net-peer.py" \
|
||
|
|
--listen-port "${peer_port_corrupt}" \
|
||
|
|
--qemu-port "${qemu_port_corrupt}" \
|
||
|
|
--receipt "${peer_receipt_corrupt}" \
|
||
|
|
--login-only >"${peer_log_corrupt}" 2>&1 &
|
||
|
|
peer_pid=$!
|
||
|
|
set +e
|
||
|
|
timeout 30 qemu-system-x86_64 \
|
||
|
|
-machine pc,accel=tcg \
|
||
|
|
-m 64M \
|
||
|
|
-drive "if=none,id=ghboot,format=raw,file=${corrupt_disk_image}" \
|
||
|
|
-device virtio-blk-pci,drive=ghboot,disable-modern=on,bootindex=0 \
|
||
|
|
-netdev "dgram,id=ghnet,local.type=inet,local.host=127.0.0.1,local.port=${qemu_port_corrupt},remote.type=inet,remote.host=127.0.0.1,remote.port=${peer_port_corrupt}" \
|
||
|
|
-device virtio-net-pci,netdev=ghnet,disable-modern=on,mac=52:54:00:26:71:98 \
|
||
|
|
-display none \
|
||
|
|
-monitor none \
|
||
|
|
-serial "file:${serial_log_corrupt}" \
|
||
|
|
-device isa-debug-exit,iobase=0xf4,iosize=0x04
|
||
|
|
qemu_status=$?
|
||
|
|
set -e
|
||
|
|
|
||
|
|
[[ ${qemu_status} -eq 33 ]]
|
||
|
|
wait "${peer_pid}"
|
||
|
|
peer_pid=
|
||
|
|
grep -q '^icmp_login_reply_count: 3$' "${peer_receipt_corrupt}"
|
||
|
|
grep -q '^code_commit_reply_verified: false$' "${peer_receipt_corrupt}"
|
||
|
|
grep -q '^GHOS_BOOT_ERROR=NATIVE_GHCIP_INDEX' "${serial_log_corrupt}"
|
||
|
|
corrupt_index_sha_after=$(dd if="${corrupt_disk_image}" bs=512 skip=70 count=2 \
|
||
|
|
status=none | sha256sum | awk '{print $1}')
|
||
|
|
[[ ${corrupt_index_sha_before} == "${corrupt_index_sha_after}" ]]
|
||
|
|
python3 - "${corrupt_disk_image}" <<'PY'
|
||
|
|
import pathlib
|
||
|
|
import sys
|
||
|
|
|
||
|
|
with pathlib.Path(sys.argv[1]).open("rb") as disk:
|
||
|
|
disk.seek(63 * 512)
|
||
|
|
proof = disk.read(512)
|
||
|
|
assert proof[0] == 0xE1
|
||
|
|
assert proof[43] == 0x6C
|
||
|
|
assert proof[102:105] == bytes([0, 0, 0])
|
||
|
|
PY
|
||
|
|
|
||
|
|
observed_at=$(date --iso-8601=seconds)
|
||
|
|
image_sha=$(sha256sum "${candidate}" | awk '{print $1}')
|
||
|
|
cat >"${receipt}" <<EOF
|
||
|
|
schema: guanghu.native-resident-qemu-test/v1
|
||
|
|
receipt_id: GH-OS-LAB-001-NATIVE-RESIDENT-QEMU-001
|
||
|
|
status: VERIFIED
|
||
|
|
observed_at: ${observed_at}
|
||
|
|
image:
|
||
|
|
architecture: x86_64
|
||
|
|
firmware: BIOS
|
||
|
|
size_bytes: 14848
|
||
|
|
candidate_start_lba: 34
|
||
|
|
candidate_sector_count: 29
|
||
|
|
proof_lba: 63
|
||
|
|
sha256: ${image_sha}
|
||
|
|
resident_runtime:
|
||
|
|
initial_login_replies: 3
|
||
|
|
post_code_channel_login_replies: 10
|
||
|
|
remained_resident_until_recovery_command: true
|
||
|
|
native_recovery:
|
||
|
|
command: HLDP-RECOVER-OS!
|
||
|
|
reply_verified_by_external_peer: true
|
||
|
|
recovery_beacon_lba_start: 68
|
||
|
|
recovery_beacon_sector_count: 2
|
||
|
|
ubuntu_menu_id: gnulinux-simple-9842d3d6-a839-4127-bda7-f19137effe71
|
||
|
|
write_read_verified_by_native_ghal: true
|
||
|
|
hardware_reset_after_verification: true
|
||
|
|
gestational_continuity:
|
||
|
|
protocol: GLS-0845
|
||
|
|
native_index_lba_start: 70
|
||
|
|
native_index_sector_count: 2
|
||
|
|
blank_index_initialized_by_native_ghal: true
|
||
|
|
write_read_verified_by_native_ghal: true
|
||
|
|
second_boot_preserved_without_write: true
|
||
|
|
first_and_second_boot_index_sha256: ${index_sha_after}
|
||
|
|
unknown_nonzero_index_failed_closed_without_overwrite: true
|
||
|
|
registry_state: EMPTY
|
||
|
|
review_state: NOT_STARTED
|
||
|
|
persona_state: NOT_BORN
|
||
|
|
acceptance:
|
||
|
|
qemu_resident_runtime: true
|
||
|
|
physical_server_resident_runtime: false
|
||
|
|
permanent_linux_replacement: false
|
||
|
|
next_action: PHYSICAL_ONE_TIME_RESIDENT_AND_RECOVERY_GATE
|
||
|
|
EOF
|
||
|
|
cat "${serial_log}" >>"${receipt}.serial.log"
|
||
|
|
cat "${serial_log_second}" >>"${receipt}.second-boot.serial.log"
|
||
|
|
cat "${serial_log_corrupt}" >>"${receipt}.corrupt-index.serial.log"
|