Repository navigation
[temp][do not merge] probe: an APE (Cosmopolitan) on every system and architecture (mcpp#849) #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # PROBE (mcpp#849), temporary, not merged: an APE built with Cosmopolitan's | |
| # cosmocc, run on every system and architecture a runner exists for. It | |
| # measures what an openkal implementation over Cosmopolitan (openkal-cosmo) | |
| # and an APE carrier would rest on: the libc primitives of each openkal area | |
| # (probe/ape/probe.c), the first-run behaviour of the APE prelude, startup | |
| # latency, signing, gatekeeping and an MZ binfmt handler on Linux. | |
| name: probe-ape | |
| on: | |
| push: | |
| branches: [probe/ape-cosmopolitan] | |
| pull_request: | |
| workflow_dispatch: | |
| concurrency: | |
| group: probe-ape-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| COSMOCC_VERSION: 4.0.2 | |
| jobs: | |
| build: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ~/cosmocc | |
| key: cosmocc-${{ env.COSMOCC_VERSION }} | |
| - name: cosmocc | |
| run: | | |
| set -euo pipefail | |
| if [ ! -x ~/cosmocc/bin/cosmocc ]; then | |
| gh release download "$COSMOCC_VERSION" -R jart/cosmopolitan -p "cosmocc-$COSMOCC_VERSION.zip" -D "$RUNNER_TEMP" | |
| mkdir -p ~/cosmocc && unzip -q "$RUNNER_TEMP/cosmocc-$COSMOCC_VERSION.zip" -d ~/cosmocc | |
| fi | |
| ~/cosmocc/bin/cosmocc --version | head -1 | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Build the APE | |
| run: | | |
| set -euo pipefail | |
| mkdir -p out | |
| ~/cosmocc/bin/cosmocc -O2 -o out/probe.com probe/ape/probe.c | |
| ls -l out | |
| python3 - out/probe.com <<'PY' | |
| import sys | |
| d = open(sys.argv[1], 'rb').read() | |
| elf, i = [], 0 | |
| while (i := d.find(b'\x7fELF', i)) >= 0: | |
| elf.append(int.from_bytes(d[i+18:i+20], 'little')); i += 4 | |
| print("size", len(d), "head", d[:8], "ELF machines", elf, "Mach-O at", hex(d.find(b'\xcf\xfa\xed\xfe'))) | |
| PY | |
| cp ~/cosmocc/bin/assimilate out/assimilate | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: ape | |
| path: out/ | |
| run: | |
| needs: build | |
| name: run (${{ matrix.platform }}) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 20 | |
| continue-on-error: true | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { platform: linux-x64, os: ubuntu-24.04 } | |
| - { platform: linux-arm64, os: ubuntu-24.04-arm } | |
| - { platform: macos-arm64, os: macos-14 } | |
| - { platform: macos-x64, os: macos-15-intel } | |
| - { platform: win-x64, os: windows-2022 } | |
| - { platform: win-arm64, os: windows-11-arm } | |
| defaults: | |
| run: | |
| shell: bash | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: ape | |
| - name: First run, from a fresh home and temporary directory | |
| run: | | |
| set +e | |
| mkdir -p "$RUNNER_TEMP/home" "$RUNNER_TEMP/tmp" results | |
| if [ "$RUNNER_OS" = Windows ]; then cp probe.com probe.exe; P=./probe.exe; else chmod +x probe.com; P=./probe.com; fi | |
| echo "P=$P" >> "$GITHUB_ENV" | |
| before=$(cd "$RUNNER_TEMP" && find home tmp | sort) | |
| python3 - "$P" > results/first-run.txt 2>&1 <<'PY' | |
| import os, subprocess, sys, time | |
| env = dict(os.environ, HOME=os.path.join(os.environ["RUNNER_TEMP"], "home"), | |
| TMPDIR=os.path.join(os.environ["RUNNER_TEMP"], "tmp")) | |
| posix = os.name != "nt" | |
| try: | |
| r = subprocess.run([sys.argv[1], "--hello"], env=env, capture_output=True, text=True) | |
| print("direct execve: exit", r.returncode, repr(r.stdout.strip())) | |
| except OSError as e: | |
| print("direct execve:", e) | |
| launch = (["sh", sys.argv[1]] if posix else [sys.argv[1]]) | |
| for n in ("first", "second"): | |
| t = time.perf_counter() | |
| r = subprocess.run(launch + ["--hello"], env=env, capture_output=True, text=True) | |
| print(n, "run" + (" via sh" if posix else "") + ": exit", r.returncode, "in %.1f ms" % ((time.perf_counter() - t) * 1e3), | |
| "stdout", repr(r.stdout.strip()), "stderr", repr(r.stderr.strip()[:300])) | |
| PY | |
| after=$(cd "$RUNNER_TEMP" && find home tmp | sort) | |
| echo "files the first run created:" >> results/first-run.txt | |
| comm -13 <(echo "$before") <(echo "$after") >> results/first-run.txt | |
| for f in $(comm -13 <(echo "$before") <(echo "$after")); do | |
| [ -f "$RUNNER_TEMP/$f" ] && { ls -l "$RUNNER_TEMP/$f"; command -v file >/dev/null && file "$RUNNER_TEMP/$f"; } >> results/first-run.txt | |
| done | |
| cat results/first-run.txt | |
| - name: The probe | |
| run: | | |
| set +e | |
| "$P" > results/probe.ndjson 2> results/probe.stderr; echo "exit $?" >> results/probe.stderr | |
| cat results/probe.ndjson; cat results/probe.stderr | |
| if [ "$RUNNER_OS" != Windows ]; then | |
| sh ./probe.com --hello > results/via-sh.txt 2>&1; echo "exit $?" >> results/via-sh.txt | |
| echo "--- sh ./probe.com --hello"; cat results/via-sh.txt | |
| fi | |
| - name: Startup latency against a native program | |
| run: | | |
| set +e | |
| if [ "$RUNNER_OS" = Windows ]; then NATIVE='C:\Windows\System32\whoami.exe'; else NATIVE=/bin/echo; fi | |
| A="" | |
| if [ "$RUNNER_OS" != Windows ]; then | |
| cp probe.com assimilated.com && chmod +x assimilate assimilated.com | |
| sh ./assimilate assimilated.com > results/assimilate.txt 2>&1; echo "assimilate: exit $?" >> results/assimilate.txt | |
| command -v file >/dev/null && file assimilated.com >> results/assimilate.txt | |
| ls -l probe.com assimilated.com >> results/assimilate.txt | |
| A=./assimilated.com | |
| fi | |
| python3 - "$P" "$NATIVE" "$A" > results/latency.txt <<'PY' | |
| import os, statistics, subprocess, sys, time | |
| def med(cmd): | |
| xs = [] | |
| for _ in range(40): | |
| t = time.perf_counter() | |
| try: subprocess.run(cmd, capture_output=True) | |
| except OSError as e: return str(e) | |
| xs.append((time.perf_counter() - t) * 1e3) | |
| return "%.1f ms" % statistics.median(xs) | |
| if os.name != "nt": | |
| print("ape via sh --hello median", med(["sh", sys.argv[1], "--hello"])) | |
| print("assimilated, direct execve --hello median", med([sys.argv[3], "--hello"])) | |
| else: | |
| print("ape --hello median", med([sys.argv[1], "--hello"])) | |
| print("native median", med([sys.argv[2]])) | |
| PY | |
| cat results/assimilate.txt 2>/dev/null | |
| cat results/latency.txt | |
| - name: Linux, an MZ binfmt handler (as wine-binfmt registers) | |
| if: runner.os == 'Linux' | |
| run: | | |
| set +e | |
| ls /proc/sys/fs/binfmt_misc/ | tee results/binfmt.txt | |
| if [ -w /proc/sys/fs/binfmt_misc/register ] || sudo test -w /proc/sys/fs/binfmt_misc/register; then | |
| echo ':ProbeMZ:M::MZ::/usr/bin/false:' | sudo tee /proc/sys/fs/binfmt_misc/register > /dev/null | |
| ./probe.com --hello > /tmp/direct.txt 2>&1; echo "direct with MZ handler: exit $? $(cat /tmp/direct.txt)" | tee -a results/binfmt.txt | |
| sh ./probe.com --hello > /tmp/sh.txt 2>&1; echo "via sh with MZ handler: exit $? $(cat /tmp/sh.txt)" | tee -a results/binfmt.txt | |
| echo -1 | sudo tee /proc/sys/fs/binfmt_misc/ProbeMZ > /dev/null | |
| else | |
| echo "binfmt_misc not writable" | tee -a results/binfmt.txt | |
| fi | |
| - name: macOS, quarantine and codesign | |
| if: runner.os == 'macOS' | |
| run: | | |
| set +e | |
| cp probe.com q.com | |
| xattr -w com.apple.quarantine "0081;$(printf %x "$(date +%s)");Safari;" q.com | |
| ./q.com --hello > /tmp/q.txt 2>&1; echo "quarantined: exit $? $(cat /tmp/q.txt)" | tee results/macos.txt | |
| codesign -s - probe.com > /tmp/cs.txt 2>&1; echo "codesign -s - probe.com: exit $? $(cat /tmp/cs.txt)" | tee -a results/macos.txt | |
| for l in "$RUNNER_TEMP"/tmp/.ape-* "$RUNNER_TEMP"/home/.ape-* ~/.ape-*; do | |
| [ -e "$l" ] || continue | |
| echo "loader $l: $(file "$l")" | tee -a results/macos.txt | |
| codesign -dv "$l" 2>&1 | head -5 | tee -a results/macos.txt | |
| done | |
| - name: Windows, Defender and Authenticode | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Continue' | |
| $mp = Join-Path $env:ProgramFiles 'Windows Defender\MpCmdRun.exe' | |
| if (Test-Path $mp) { & $mp -Scan -ScanType 3 -File (Resolve-Path probe.exe) -DisableRemediation *>&1 | Tee-Object -FilePath results/defender.txt } else { 'no MpCmdRun' | Tee-Object -FilePath results/defender.txt } | |
| $cert = New-SelfSignedCertificate -Type CodeSigningCert -Subject 'CN=probe-ape' -CertStoreLocation Cert:\CurrentUser\My | |
| Copy-Item probe.exe signed.exe | |
| $sig = Set-AuthenticodeSignature -FilePath signed.exe -Certificate $cert | |
| "sign: $($sig.Status) $($sig.StatusMessage)" | Tee-Object -FilePath results/sign.txt | |
| $out = & .\signed.exe --hello 2>&1; "signed run: exit $LASTEXITCODE $out" | Tee-Object -FilePath results/sign.txt -Append | |
| "size before $((Get-Item probe.exe).Length) after $((Get-Item signed.exe).Length)" | Tee-Object -FilePath results/sign.txt -Append | |
| $st = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin" -Recurse -Filter signtool.exe -ErrorAction SilentlyContinue | Where-Object { $_.FullName -match '\\x64\\' } | Select-Object -First 1 | |
| if ($st) { | |
| $pfx = Join-Path $env:RUNNER_TEMP 'probe.pfx'; $pw = ConvertTo-SecureString 'probe' -AsPlainText -Force | |
| Export-PfxCertificate -Cert $cert -FilePath $pfx -Password $pw | Out-Null | |
| Copy-Item probe.exe signtool.exe.target.exe | |
| $o = & $st.FullName sign /fd SHA256 /f $pfx /p probe signtool.exe.target.exe 2>&1 | |
| "signtool: exit $LASTEXITCODE $o" | Tee-Object -FilePath results/sign.txt -Append | |
| $o2 = & .\signtool.exe.target.exe --hello 2>&1; "signtool-signed run: exit $LASTEXITCODE $o2" | Tee-Object -FilePath results/sign.txt -Append | |
| "size after signtool $((Get-Item signtool.exe.target.exe).Length)" | Tee-Object -FilePath results/sign.txt -Append | |
| Copy-Item signtool.exe.target.exe signed.exe -Force | |
| } else { 'no signtool' | Tee-Object -FilePath results/sign.txt -Append } | |
| New-Item -ItemType Directory -Force signed | Out-Null; Copy-Item signed.exe signed/signed.com | |
| - uses: actions/upload-artifact@v4 | |
| if: runner.os == 'Windows' && matrix.platform == 'win-x64' | |
| with: | |
| name: signed | |
| path: signed/signed.com | |
| - uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: results-${{ matrix.platform }} | |
| path: results | |
| signed-elsewhere: | |
| needs: run | |
| name: the Authenticode-signed APE on ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| continue-on-error: true | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14] | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: signed | |
| - name: Run it | |
| run: | | |
| set +e | |
| chmod +x signed.com | |
| ./signed.com --hello; echo "exit $?" | |
| sh ./signed.com --hello; echo "via sh: exit $?" | |
| summary: | |
| needs: [run, signed-elsewhere] | |
| if: always() | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| pattern: results-* | |
| - name: Table | |
| run: | | |
| python3 - <<'PY' | tee -a "$GITHUB_STEP_SUMMARY" | |
| import glob, json, os | |
| rows, checks = {}, [] | |
| for d in sorted(glob.glob("results-*")): | |
| plat = d[len("results-"):] | |
| res = {} | |
| try: | |
| for line in open(os.path.join(d, "probe.ndjson")): | |
| try: o = json.loads(line) | |
| except Exception: continue | |
| if "area" in o: | |
| k = o["area"] + "/" + o["check"] | |
| res[k] = o | |
| if k not in checks: checks.append(k) | |
| except FileNotFoundError: pass | |
| rows[plat] = res | |
| plats = list(rows) | |
| print("| check | " + " | ".join(plats) + " |") | |
| print("|---|" + "---|" * len(plats)) | |
| for k in checks: | |
| cells = [] | |
| for p in plats: | |
| o = rows[p].get(k) | |
| cells.append("—" if o is None else ("ok" if o["ok"] else "**FAIL** " + o["detail"][:60].replace("|", "/"))) | |
| print(f"| {k} | " + " | ".join(cells) + " |") | |
| for p in plats: | |
| for f in ("first-run.txt", "latency.txt", "binfmt.txt", "macos.txt", "sign.txt", "defender.txt", "via-sh.txt", "assimilate.txt", "probe.stderr"): | |
| path = os.path.join("results-" + p, f) | |
| if os.path.exists(path): | |
| print(f"\n**{p} {f}**\n```\n" + open(path, errors="replace").read()[-3000:] + "\n```") | |
| PY |