/* DF-1661: IPMI IPMICTL_RECEIVE_MSG_TRUNC size_t underflow harness.
 *   len = kreq->ir_replylen + 1;             (e.g., 64)
 *   // EMSGSIZE guard SKIPPED for TRUNC
 *   len = min(recv->msg.data_len, len);       (data_len=0 -> len=0)
 *   copyout(ir_reply, data+1, len-1);          (len-1 underflows -> SIZE_MAX)
 */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>

static int fixed = 0;
static size_t copyout_len;

static int copyout_mock(const void *k, void *u, size_t n) {
    copyout_len = n;
    if (n > 1024*1024) {
        printf("COPYOUT: %zu bytes (would leak kernel heap until page fault)\n", n);
        return 14; /* EFAULT */
    }
    return 0;
}

int main(int argc, char **argv) {
    if (argc > 1 && !strcmp(argv[1], "--fixed")) fixed = 1;

    /* simulate TRUNC path with data_len=0 */
    int ir_replylen = 64;
    int data_len = 0;
    char ir_reply[64] = {0};

    int len = ir_replylen + 1;
    /* TRUNC skips EMSGSIZE guard */
    len = (data_len < len) ? data_len : len;
    char data_buf[16];

    int error;
    if (fixed) {
        /* patched: guard each copyout */
        error = copyout_mock("addr", data_buf, sizeof(int));
        if (error == 0 && len >= 1)
            error = copyout_mock("\0", data_buf, 1);
        if (error == 0 && len > 1)
            error = copyout_mock(ir_reply, data_buf, len - 1);
    } else {
        /* buggy: unconditional compcode copyout + len-1 underflow */
        error = copyout_mock("addr", data_buf, sizeof(int));
        if (error == 0)
            error = copyout_mock("\0", data_buf, 1);
        if (error == 0)
            error = copyout_mock(ir_reply, data_buf, len - 1);
    }

    if (fixed)
        printf("RESULT: PATCHED - no copyout underflow (len=%d)\n", len);
    else
        printf("RESULT: BUGGY - copyout size=%zu (underflowed len-1)\n", copyout_len);
    return 0;
}
