update
This commit is contained in:
@@ -0,0 +1,412 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${PRE15_DUT:?PRE15_DUT is required}"
|
||||
: "${PRE15_ROOT:?PRE15_ROOT is required}"
|
||||
: "${PRE15_CASE_TMP:?PRE15_CASE_TMP is required}"
|
||||
: "${PRE15_RUN_DIR:?PRE15_RUN_DIR is required}"
|
||||
: "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}"
|
||||
. "$PRE15_LIB_DIR/runner.sh"
|
||||
|
||||
baseline=083acc65f842c409c5a2e089e50060d0062b677c
|
||||
fixture_dir=$PRE15_DUT/tests/pre15/fixtures
|
||||
spec=$fixture_dir/B23-explicit-spec.json
|
||||
generator=$fixture_dir/B23-explicit-generate.py
|
||||
oracle=$fixture_dir/B23-explicit-oracle.py
|
||||
probe=$fixture_dir/B23-explicit-probe.c
|
||||
kld_builder=$fixture_dir/B23-build-kld.sh
|
||||
zmap=$PRE15_DUT/src/zmap.c
|
||||
linux_zmap=$PRE15_ROOT/src-linux/zmap.c
|
||||
artifacts=$PRE15_RUN_DIR/artifacts
|
||||
first=$PRE15_CASE_TMP/first
|
||||
second=$PRE15_CASE_TMP/second
|
||||
|
||||
for tool in cc diff git mkfs.erofs python3 sha256sum; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B23 host tool: $tool"
|
||||
done
|
||||
|
||||
pre15_record_fixture b23-spec "$spec"
|
||||
pre15_record_fixture b23-generator "$generator"
|
||||
pre15_record_fixture b23-oracle "$oracle"
|
||||
pre15_record_fixture b23-probe "$probe"
|
||||
pre15_record_fixture b23-kld-builder "$kld_builder"
|
||||
pre15_record_fixture b23-case "$PRE15_DUT/tests/pre15/cases/B23-explicit-table.sh"
|
||||
pre15_record_fixture b23-zmap "$zmap"
|
||||
pre15_record_fixture b23-linux-zmap "$linux_zmap"
|
||||
mkdir -p "$artifacts"
|
||||
|
||||
if ! python3 -B "$generator" --spec "$spec" --output "$first" \
|
||||
>"$artifacts/B23-generate-first.stdout" \
|
||||
2>"$artifacts/B23-generate-first.stderr"; then
|
||||
pre15_runner_fail 'B23 first fixture generation failed'
|
||||
fi
|
||||
if ! python3 -B "$generator" --spec "$spec" --output "$second" \
|
||||
>"$artifacts/B23-generate-second.stdout" \
|
||||
2>"$artifacts/B23-generate-second.stderr"; then
|
||||
pre15_runner_fail 'B23 repeat fixture generation failed'
|
||||
fi
|
||||
if ! diff -u "$first/SHA256SUMS" "$second/SHA256SUMS" \
|
||||
>"$artifacts/B23-repeat-sums.diff" || \
|
||||
! diff -u "$first/fixture-manifest.json" "$second/fixture-manifest.json" \
|
||||
>"$artifacts/B23-repeat-manifest.diff"; then
|
||||
pre15_runner_fail 'B23 fixture generation is not byte deterministic'
|
||||
fi
|
||||
if ! python3 -B "$oracle" --spec "$spec" --fixtures "$first" \
|
||||
--report "$artifacts/B23-oracle-first.json" \
|
||||
>"$artifacts/B23-oracle-first.stdout" \
|
||||
2>"$artifacts/B23-oracle-first.stderr"; then
|
||||
pre15_runner_fail 'B23 independent fixture oracle failed'
|
||||
fi
|
||||
if ! python3 -B "$oracle" --spec "$spec" --fixtures "$second" \
|
||||
--report "$artifacts/B23-oracle-second.json" \
|
||||
>"$artifacts/B23-oracle-second.stdout" \
|
||||
2>"$artifacts/B23-oracle-second.stderr"; then
|
||||
pre15_runner_fail 'B23 repeat fixture oracle failed'
|
||||
fi
|
||||
cp "$first/SHA256SUMS" "$artifacts/B23-fixture-SHA256SUMS"
|
||||
cp "$first/fixture-manifest.json" "$artifacts/B23-fixture-manifest.json"
|
||||
pre15_record_fixture b23-generated-sums "$artifacts/B23-fixture-SHA256SUMS"
|
||||
|
||||
if ! cc -std=c11 -Wall -Wextra -Werror -c "$probe" \
|
||||
-o "$PRE15_CASE_TMP/B23-explicit-probe.o" \
|
||||
>"$artifacts/B23-probe-compile.stdout" \
|
||||
2>"$artifacts/B23-probe-compile.stderr"; then
|
||||
pre15_runner_fail 'B23 guest probe does not compile on the host'
|
||||
fi
|
||||
|
||||
if python3 -B - "$PRE15_ROOT" "$PRE15_DUT" "$baseline" "$spec" \
|
||||
"$artifacts/B23-source-audit.json" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
root = Path(sys.argv[1])
|
||||
dut = Path(sys.argv[2])
|
||||
baseline = sys.argv[3]
|
||||
spec_path = Path(sys.argv[4])
|
||||
report_path = Path(sys.argv[5])
|
||||
|
||||
|
||||
def committed(path: str) -> str:
|
||||
completed = subprocess.run(
|
||||
["git", "-C", str(root), "show", f"{baseline}:repo-pre-15/{path}"],
|
||||
check=False,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
)
|
||||
if completed.returncode != 0:
|
||||
raise SystemExit(f"cannot read B23 baseline {path}: {completed.stderr}")
|
||||
return completed.stdout
|
||||
|
||||
|
||||
def function(source: str, name: str) -> str:
|
||||
match = re.search(r"^" + re.escape(name) + r"\s*\(", source, re.MULTILINE)
|
||||
if match is None:
|
||||
raise SystemExit(f"missing function: {name}")
|
||||
start = source.rfind("\n", 0, source.rfind("\n", 0, match.start())) + 1
|
||||
brace = source.find("{", match.end())
|
||||
depth = 0
|
||||
state = "code"
|
||||
index = brace
|
||||
while index < len(source):
|
||||
char = source[index]
|
||||
following = source[index + 1] if index + 1 < len(source) else ""
|
||||
if state == "code":
|
||||
if char == "/" and following == "*":
|
||||
state = "block"
|
||||
index += 2
|
||||
continue
|
||||
if char == "/" and following == "/":
|
||||
state = "line"
|
||||
index += 2
|
||||
continue
|
||||
if char == '"':
|
||||
state = "string"
|
||||
elif char == "'":
|
||||
state = "character"
|
||||
elif char == "{":
|
||||
depth += 1
|
||||
elif char == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[start : index + 1]
|
||||
elif state == "block" and char == "*" and following == "/":
|
||||
state = "code"
|
||||
index += 2
|
||||
continue
|
||||
elif state == "line" and char == "\n":
|
||||
state = "code"
|
||||
elif state in {"string", "character"}:
|
||||
if char == "\\":
|
||||
index += 2
|
||||
continue
|
||||
if (state == "string" and char == '"') or (
|
||||
state == "character" and char == "'"
|
||||
):
|
||||
state = "code"
|
||||
index += 1
|
||||
raise SystemExit(f"unterminated function: {name}")
|
||||
|
||||
|
||||
spec = json.loads(spec_path.read_text(encoding="ascii"))
|
||||
current = (dut / "src/zmap.c").read_text(encoding="utf-8")
|
||||
before = committed("src/zmap.c")
|
||||
validator = function(current, "z_erofs_validate_extent_table")
|
||||
old_validator = function(before, "z_erofs_validate_extent_table")
|
||||
if validator == old_validator:
|
||||
raise SystemExit("B23 validator did not change")
|
||||
if function(current, "z_erofs_read_extent") != function(before, "z_erofs_read_extent"):
|
||||
raise SystemExit("B23 changed the local record decoder")
|
||||
for name in ("z_erofs_map_blocks_ext", "z_erofs_fill_inode"):
|
||||
if function(current, name) != function(before, name):
|
||||
raise SystemExit(f"B23 changed {name}")
|
||||
if "#define Z_EROFS_EXTENT_VALIDATE_CHUNK_SIZE (64 * 1024)" not in current:
|
||||
raise SystemExit("B23 fixed validation chunk bound is missing")
|
||||
required = (
|
||||
"z_erofs_read_extent(sbi, vi, record_pos, recsz, &ext)",
|
||||
"while (scan_pos < table_end)",
|
||||
"Z_EROFS_EXTENT_VALIDATE_CHUNK_SIZE",
|
||||
"erofs_read_metadata(sbi, vi->nid, scan_pos, chunk_len, &buf)",
|
||||
"memcpy(&ext, (const char *)buf.data + offset, recsz)",
|
||||
"z_erofs_extent_lstart(&ext, recsz)",
|
||||
"erofs_put_metabuf(&buf)",
|
||||
"return (index == vi->z_extents ? 0 : EINTEGRITY)",
|
||||
)
|
||||
if not all(marker in validator for marker in required):
|
||||
raise SystemExit("B23 validator is missing a bounded-scan contract marker")
|
||||
if validator.count("z_erofs_read_extent(") != 1:
|
||||
raise SystemExit("B23 short tail probe count changed")
|
||||
if validator.count("erofs_read_metadata(") != 1:
|
||||
raise SystemExit("B23 long-table reader is not chunk-scoped")
|
||||
if re.search(r"return\s*\(\s*-E[A-Z0-9_]+", validator):
|
||||
raise SystemExit("B23 introduced Linux negative errno")
|
||||
|
||||
allowed = {
|
||||
"repo-pre-15/src/zmap.c",
|
||||
"repo-pre-15/tests/pre15/cases/B23-explicit-table.sh",
|
||||
"repo-pre-15/tests/pre15/fixtures/B23-build-kld.sh",
|
||||
"repo-pre-15/tests/pre15/fixtures/B23-explicit-generate.py",
|
||||
"repo-pre-15/tests/pre15/fixtures/B23-explicit-oracle.py",
|
||||
"repo-pre-15/tests/pre15/fixtures/B23-explicit-probe.c",
|
||||
"repo-pre-15/tests/pre15/fixtures/B23-explicit-spec.json",
|
||||
}
|
||||
changed = set(
|
||||
subprocess.run(
|
||||
["git", "-C", str(root), "diff", "--name-only", baseline, "--", "repo-pre-15"],
|
||||
check=True,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.splitlines()
|
||||
)
|
||||
changed.update(
|
||||
subprocess.run(
|
||||
[
|
||||
"git", "-C", str(root), "ls-files", "--others",
|
||||
"--exclude-standard", "--", "repo-pre-15",
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.splitlines()
|
||||
)
|
||||
if changed != allowed:
|
||||
raise SystemExit(f"B23 write set differs: {sorted(changed ^ allowed)}")
|
||||
for path in (
|
||||
"src/erofs_fs.h",
|
||||
"src/data.c",
|
||||
"src/decompressor.c",
|
||||
"src/decompressor_lz4.c",
|
||||
"src/decompressor_lzma.c",
|
||||
"src/decompressor_deflate.c",
|
||||
"src/decompressor_zstd.c",
|
||||
"src/internal.h",
|
||||
):
|
||||
if (dut / path).read_text(encoding="utf-8") != committed(path):
|
||||
raise SystemExit(f"B23 changed an excluded provider/codec/ABI file: {path}")
|
||||
|
||||
linux = (root / "src-linux/zmap.c").read_text(encoding="utf-8")
|
||||
for marker in (
|
||||
"recsz <= offsetof(struct z_erofs_extent, pstart_hi)",
|
||||
"le64_to_cpu(*(__le64 *)ext)",
|
||||
"le32_to_cpu(ext->pstart_lo)",
|
||||
"le32_to_cpu(ext->pstart_hi) << 32",
|
||||
"le32_to_cpu(ext->lstart_hi) << 32",
|
||||
"erofs_inode_in_metabox(inode)",
|
||||
):
|
||||
if marker not in linux:
|
||||
raise SystemExit(f"Linux explicit-table anchor changed: {marker}")
|
||||
|
||||
report = {
|
||||
"baseline": baseline,
|
||||
"batch": "B23",
|
||||
"candidates": spec["candidates"],
|
||||
"chunk_size": spec["chunk_size"],
|
||||
"decompressor_files_unchanged": True,
|
||||
"freebsd_positive_errno": True,
|
||||
"linux_record_decode_audited": True,
|
||||
"ondisk_header_unchanged": True,
|
||||
"primary_metabox_reader_unchanged": True,
|
||||
"status": "PASS",
|
||||
"test": spec["test"],
|
||||
"write_set": sorted(changed),
|
||||
}
|
||||
report_path.write_text(
|
||||
json.dumps(report, ensure_ascii=True, indent=2, sort_keys=True) + "\n",
|
||||
encoding="ascii",
|
||||
)
|
||||
print("B23 source/write-set/Linux-FreeBSD audit PASS")
|
||||
PY
|
||||
then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'B23 source, write-set, or cross-tree audit failed'
|
||||
fi
|
||||
|
||||
sha256sum "$artifacts/B23-fixture-SHA256SUMS" \
|
||||
"$artifacts/B23-fixture-manifest.json" \
|
||||
"$artifacts/B23-oracle-first.json" \
|
||||
"$artifacts/B23-oracle-second.json" \
|
||||
"$artifacts/B23-source-audit.json" \
|
||||
>"$artifacts/SHA256SUMS"
|
||||
pre15_target_reached
|
||||
|
||||
if test "${PRE15_MODE:-host}" != qemu; then
|
||||
printf '%s\n' \
|
||||
'TC171 host real-fixture, independent oracle, and bounded source audit PASS' \
|
||||
'QEMU exact-source mapped/backing runtime NOT_RUN in host mode' \
|
||||
'Full feature suite NOT_RUN'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for tool in awk clang file nm scp tar; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B23 QEMU tool: $tool"
|
||||
done
|
||||
: "${PRE15_QEMU_CONTROL_PATH:?QEMU control path is required}"
|
||||
: "${PRE15_QEMU_SSH_KEY:?QEMU SSH key is required}"
|
||||
: "${PRE15_QEMU_SSH_PORT:?QEMU SSH port is required}"
|
||||
: "${PRE15_QEMU_SSH_USER:?QEMU SSH user is required}"
|
||||
|
||||
fixture_archive=$PRE15_CASE_TMP/B23-fixtures.tar.gz
|
||||
module=$PRE15_CASE_TMP/B23-erofs.ko
|
||||
if ! /bin/sh "$kld_builder" "$PRE15_DUT" "$PRE15_FREEBSD_SRC" "$module" \
|
||||
"$PRE15_CASE_TMP/kld-work" >"$artifacts/B23-kld-build.stdout" \
|
||||
2>"$artifacts/B23-kld-build.stderr"; then
|
||||
pre15_dut_fail 'B23 cross-target zstdio0 KLD build failed'
|
||||
fi
|
||||
pre15_record_module "$module"
|
||||
file "$module" >"$artifacts/B23-kld-file.txt"
|
||||
sha256sum "$module" >"$artifacts/B23-kld-sha256.txt"
|
||||
nm -u "$module" | LC_ALL=C sort >"$artifacts/B23-kld-nm-u.txt"
|
||||
tar -C "$first" -czf "$fixture_archive" .
|
||||
|
||||
pre15_scp()
|
||||
{
|
||||
timeout -k 5 "${PRE15_GUEST_COMMAND_TIMEOUT:-60}" scp -O -q \
|
||||
-o BatchMode=yes -o StrictHostKeyChecking=no \
|
||||
-o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 \
|
||||
-o "ControlPath=$PRE15_QEMU_CONTROL_PATH" \
|
||||
-i "$PRE15_QEMU_SSH_KEY" -P "$PRE15_QEMU_SSH_PORT" \
|
||||
"$1" "$PRE15_QEMU_SSH_USER@127.0.0.1:$2"
|
||||
}
|
||||
|
||||
if ! pre15_scp "$fixture_archive" /root/B23-fixtures.tar.gz || \
|
||||
! pre15_scp "$probe" /root/B23-explicit-probe.c || \
|
||||
! pre15_scp "$module" /root/B23-erofs.ko; then
|
||||
pre15_infra_blocked 'could not transfer B23 module, probe, or fixtures'
|
||||
fi
|
||||
if ! pre15_guest_ssh_bounded \
|
||||
'rm -rf /root/pre15-b23-fixtures && mkdir /root/pre15-b23-fixtures && tar -xzf /root/B23-fixtures.tar.gz -C /root/pre15-b23-fixtures'; then
|
||||
pre15_infra_blocked 'could not prepare B23 guest fixtures'
|
||||
fi
|
||||
if pre15_guest_ssh_bounded kldstat -n erofs >/dev/null 2>&1; then
|
||||
pre15_infra_blocked 'FreeBSD guest already has an EROFS module loaded'
|
||||
fi
|
||||
if ! pre15_guest_ssh_bounded kldload /root/B23-erofs.ko \
|
||||
>"$artifacts/B23-kldload.stdout" 2>"$artifacts/B23-kldload.stderr"; then
|
||||
if grep -q 'module already loaded or in kernel' "$artifacts/B23-kldload.stderr"; then
|
||||
pre15_infra_blocked 'guest kernel already owns the erofs.1 interface'
|
||||
fi
|
||||
pre15_dut_fail 'B23 exact-source KLD failed to load'
|
||||
fi
|
||||
pre15_own_guest_kld erofs 'B23 exact-source KLD'
|
||||
if ! pre15_guest_ssh_bounded cc -std=c11 -Wall -Wextra -Werror \
|
||||
-o /root/B23-explicit-probe /root/B23-explicit-probe.c; then
|
||||
pre15_infra_blocked 'could not compile the B23 guest probe'
|
||||
fi
|
||||
|
||||
python3 -B - "$first/fixture-manifest.json" >"$PRE15_CASE_TMP/B23-qemu-cases.tsv" <<'PY'
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
manifest = json.loads(Path(sys.argv[1]).read_text(encoding="ascii"))
|
||||
for name, case in sorted(manifest["cases"].items()):
|
||||
offsets = ",".join(str(value) for value in case["probe_offsets"])
|
||||
print(
|
||||
name,
|
||||
case["image"],
|
||||
case["expected_errno"],
|
||||
case["file_size"],
|
||||
offsets,
|
||||
case["target_marker"],
|
||||
sep="\t",
|
||||
)
|
||||
PY
|
||||
|
||||
pre15_attach_md()
|
||||
{
|
||||
pre15_md=$(pre15_guest_ssh_bounded mdconfig -a -t vnode -f "$1") || \
|
||||
pre15_dut_fail "could not attach B23 provider: $1"
|
||||
case "$pre15_md" in
|
||||
md[0-9]*) ;;
|
||||
*) pre15_runner_fail "unexpected mdconfig output: $pre15_md" ;;
|
||||
esac
|
||||
pre15_md=${pre15_md#md}
|
||||
pre15_own_guest_md "$pre15_md" "$2"
|
||||
printf '%s\n' "$pre15_md"
|
||||
}
|
||||
|
||||
while IFS="$(printf '\t')" read -r case_id image_name expected_errno \
|
||||
file_size offsets target_marker; do
|
||||
mountpoint=/mnt/pre15-b23-$case_id
|
||||
unit=$(pre15_attach_md "/root/pre15-b23-fixtures/$image_name" \
|
||||
"B23 $case_id primary")
|
||||
pre15_guest_ssh_bounded mkdir -p "$mountpoint"
|
||||
if ! pre15_guest_ssh_bounded mount -t erofs -o ro "/dev/md$unit" \
|
||||
"$mountpoint"; then
|
||||
pre15_dut_fail "B23 $case_id mount failed before $target_marker"
|
||||
fi
|
||||
pre15_own_guest_mount "$mountpoint" "B23 $case_id mount"
|
||||
if test "$expected_errno" -eq 0; then
|
||||
old_ifs=$IFS
|
||||
IFS=,
|
||||
set -- $offsets
|
||||
IFS=$old_ifs
|
||||
if ! pre15_guest_ssh_bounded /root/B23-explicit-probe pass \
|
||||
"$mountpoint/target.bin" "$file_size" "$@"; then
|
||||
pre15_dut_fail "B23 mapped positive failed at $target_marker"
|
||||
fi
|
||||
else
|
||||
if ! pre15_guest_ssh_bounded /root/B23-explicit-probe errno \
|
||||
"$mountpoint/target.bin" "$expected_errno"; then
|
||||
pre15_dut_fail "B23 corruption result failed at $target_marker"
|
||||
fi
|
||||
fi
|
||||
done <"$PRE15_CASE_TMP/B23-qemu-cases.tsv"
|
||||
|
||||
pre15_guest_ssh_bounded dmesg >"$artifacts/B23-dmesg.txt"
|
||||
if grep -Eq 'panic:|Fatal trap|lock order reversal|KDB: stack backtrace' \
|
||||
"$artifacts/B23-dmesg.txt"; then
|
||||
pre15_dut_fail 'B23 runtime produced a kernel diagnostic'
|
||||
fi
|
||||
printf '%s\n' \
|
||||
'TC171 QEMU explicit primary/metabox mapped and corruption runtime PASS' \
|
||||
'All errno values are positive FreeBSD ABI values; full feature suite NOT_RUN'
|
||||
Reference in New Issue
Block a user