#!/bin/bash
set -euo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
CODING="$ROOT/coding"
mkdir -p "$LOGS" "$CODING"

exec > >(tee -a "$LOGS/verify_fix.log")
exec 2>&1

echo "=== CVE-2026-10536 libcurl HTTP/2 stream-dependency UAF fix verification ==="

CACHE_CTX="$ROOT/project_cache_context.json"
if [ -f "$CACHE_CTX" ] && jq -e '.prepared == true' "$CACHE_CTX" >/dev/null 2>&1; then
  PROJECT_CACHE_DIR="$(jq -r '.project_cache_dir' "$CACHE_CTX")"
else
  PROJECT_CACHE_DIR="$ROOT/artifacts/cache"
fi

REPO_DIR="$PROJECT_CACHE_DIR/repo"
PATCH="$CODING/proposed_fix.diff"
INSTALL_VULN="$PROJECT_CACHE_DIR/install-vuln"
INSTALL_PATCHED="$PROJECT_CACHE_DIR/install-verify"
VULN_COMMIT="a05f34973e6c4bb629d018f7cb51487be1c904d8"

REPRO_SRC="$CODING/reproducer.c"
REPRO_VULN="$CODING/reproducer_vuln"
REPRO_PATCHED="$CODING/reproducer_patched"
VULN_LOG="$CODING/reproducer_vuln.log"
PATCHED_LOG="$CODING/reproducer_patched.log"

if [ ! -f "$PATCH" ]; then
  echo "ERROR: patch file not found: $PATCH"
  exit 1
fi

echo "Installing dependencies if needed..."
sudo apt-get update >/dev/null
sudo apt-get install -y \
  build-essential autoconf automake libtool pkg-config \
  libssl-dev libnghttp2-dev zlib1g-dev git jq >/dev/null

mkdir -p "$PROJECT_CACHE_DIR"
if [ ! -d "$REPO_DIR/.git" ]; then
  echo "Cloning curl repository..."
  git clone --depth 2000 https://github.com/curl/curl.git "$REPO_DIR"
fi

cd "$REPO_DIR"

echo "Resetting repository to vulnerable commit $VULN_COMMIT..."
git checkout -f "$VULN_COMMIT"
git clean -fdx >/dev/null 2>&1

build_version() {
  local role="$1"
  local install_prefix="$2"
  local apply_patch="$3"

  echo "[$role] Building commit $VULN_COMMIT ..."
  rm -rf "$install_prefix"
  mkdir -p "$install_prefix"

  if [ "$apply_patch" = "yes" ]; then
    echo "[$role] Applying patch..."
    patch -p1 < "$PATCH"
  fi

  make distclean >/dev/null 2>&1 || true
  autoreconf -fi >/dev/null 2>&1
  ./configure \
    --with-nghttp2 --with-openssl --enable-debug \
    --disable-shared --enable-static \
    --disable-ldap --disable-ldaps \
    --without-libpsl --without-libidn2 \
    --without-zstd --without-brotli \
    CFLAGS="-fsanitize=address -fno-omit-frame-pointer -g" \
    LDFLAGS="-fsanitize=address" \
    --prefix="$install_prefix" >/dev/null
  make -j"$(nproc)" >/dev/null
  make install >/dev/null

  if [ "$apply_patch" = "yes" ]; then
    echo "[$role] Reverting patch to keep repo clean..."
    patch -p1 -R < "$PATCH" || git checkout -f "$VULN_COMMIT"
  fi
}

# Ensure the unpatched vulnerable build exists so we can demonstrate the bug.
if [ ! -f "$INSTALL_VULN/lib/libcurl.a" ] || [ "$(cat "$INSTALL_VULN/.build_stamp" 2>/dev/null)" != "$VULN_COMMIT" ]; then
  build_version "vuln" "$INSTALL_VULN" "no"
  echo "$VULN_COMMIT" > "$INSTALL_VULN/.build_stamp"
fi

# Build the patched version in a separate directory.
build_version "patched" "$INSTALL_PATCHED" "yes"

# Create the reproducer source if it is not present.
if [ ! -f "$REPRO_SRC" ]; then
cat > "$REPRO_SRC" <<'CEOF'
#include <curl/curl.h>
#include <stdio.h>

int main(void) {
  CURL *parent = curl_easy_init();
  CURL *child  = curl_easy_init();

  if(!parent || !child) {
    fprintf(stderr, "init failed\n");
    return 1;
  }

  curl_easy_setopt(parent, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2_0);
  curl_easy_setopt(child,  CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2_0);

  /* Set stream dependency of child on parent. */
  curl_easy_setopt(child, CURLOPT_STREAM_DEPENDS, parent);

  curl_easy_reset(child);
  curl_easy_cleanup(child);

  curl_easy_cleanup(parent);

  return 0;
}
CEOF
fi

rm -f "$REPRO_VULN" "$REPRO_PATCHED" "$VULN_LOG" "$PATCHED_LOG"

echo "Compiling reproducer against vulnerable build..."
gcc -g -fsanitize=address \
  -I"$INSTALL_VULN/include" \
  "$REPRO_SRC" \
  -L"$INSTALL_VULN/lib" -lcurl -lnghttp2 -lssl -lcrypto -lz \
  -o "$REPRO_VULN"

echo "Running vulnerable reproducer (should crash with ASan UAF)..."
if ASAN_OPTIONS=detect_leaks=0 "$REPRO_VULN" >"$VULN_LOG" 2>&1; then
  echo "ERROR: vulnerable reproducer did not fail as expected."
  exit 1
fi
if grep -q "ERROR: AddressSanitizer: heap-use-after-free" "$VULN_LOG"; then
  echo "Vulnerable build confirmed: heap-use-after-free detected."
else
  echo "Vulnerable build did not produce expected ASan UAF output."
  cat "$VULN_LOG"
  exit 1
fi

echo "Compiling reproducer against patched build..."
gcc -g -fsanitize=address \
  -I"$INSTALL_PATCHED/include" \
  "$REPRO_SRC" \
  -L"$INSTALL_PATCHED/lib" -lcurl -lnghttp2 -lssl -lcrypto -lz \
  -o "$REPRO_PATCHED"

echo "Running patched reproducer (should exit cleanly)..."
if ASAN_OPTIONS=detect_leaks=0 "$REPRO_PATCHED" >"$PATCHED_LOG" 2>&1; then
  if grep -q "ERROR: AddressSanitizer" "$PATCHED_LOG"; then
    echo "ERROR: patched build still produced an ASan report."
    cat "$PATCHED_LOG"
    exit 1
  fi
  echo "Patched build verified: reproducer exits cleanly."
else
  echo "ERROR: patched reproducer failed."
  cat "$PATCHED_LOG"
  exit 1
fi

echo "=== Fix verification succeeded ==="
exit 0
