#!/bin/sh

# cpuid = 4; apic id = 04
# instruction pointer     = 0x20:0xffffffff803a1e9c
# stack pointer           = 0x28:0xfffffe0202e4c930
# frame pointer           = 0x28:0xfffffe0202e4c970
# code segment            = base 0x0, limit 0xfffff, type 0x1b
#                         = DPL 0, pres 1, long 1, def32 0, gran 1
# processor eflags        = interrupt enabled, resume, IOPL = 0
# current process         = 90315 (repro20)
# rdi: fffff803157b7000 rsi: 0000000000000004 rdx: ffffffff81250a83
# rcx: 0000000000000010  r8: 000000000000000e  r9: 1627af6b9da6f5a7
# rax: 0000000000000010 rbx: fffff803157b7000 rbp: fffffe0202e4c970
# r10: fffff803157b70c8 r11: fffff807cf9bfcd0 r12: 0000000000000001
# r13: fffff803157b7048 r14: fffff800035e0ac0 r15: 6e3642f32a3ae6f2
# trap number             = 9
# panic: general protection fault
# cpuid = 4
# time = 1773820163
# KDB: stack backtrace:
# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe0202e4c6b0
# vpanic() at vpanic+0x136/frame 0xfffffe0202e4c7e0
# panic() at panic+0x43/frame 0xfffffe0202e4c840
# trap_fatal() at trap_fatal+0x68/frame 0xfffffe0202e4c860
# calltrap() at calltrap+0x8/frame 0xfffffe0202e4c860
# --- trap 0x9, rip = 0xffffffff803a1e9c, rsp = 0xfffffe0202e4c930, rbp = 0xfffffe0202e4c970 ---
# xpt_action_default() at xpt_action_default+0x80c/frame 0xfffffe0202e4c970
# cam_periph_runccb() at cam_periph_runccb+0xec/frame 0xfffffe0202e4cac0
# passsendccb() at passsendccb+0x160/frame 0xfffffe0202e4cb30
# passdoioctl() at passdoioctl+0x3a1/frame 0xfffffe0202e4cb80
# passioctl() at passioctl+0x22/frame 0xfffffe0202e4cbc0
# devfs_ioctl() at devfs_ioctl+0xd1/frame 0xfffffe0202e4cc10
# VOP_IOCTL_APV() at VOP_IOCTL_APV+0x51/frame 0xfffffe0202e4cc40
# vn_ioctl() at vn_ioctl+0x160/frame 0xfffffe0202e4ccb0
# devfs_ioctl_f() at devfs_ioctl_f+0x1e/frame 0xfffffe0202e4ccd0
# kern_ioctl() at kern_ioctl+0x2a1/frame 0xfffffe0202e4cd40
# sys_ioctl() at sys_ioctl+0x12f/frame 0xfffffe0202e4ce00
# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe0202e4cf30
# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe0202e4cf30
# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x823e9deca, rsp = 0x820edf228, rbp = 0x820edf250 ---
# KDB: enter: panic
# [ thread pid 90315 tid 851795 ]
# Stopped at      kdb_enter+0x33: movq    $0,0x15e9d32(%rip)
# db> x/s version
# version: FreeBSD 16.0-CURRENT #0 main-n284537-a8b9a05d3cad-dirty: Tue Mar 17 09:39:44 CET 2026
# pho@mercat1.netperf.freebsd.org:/usr/src/sys/amd64/compile/PHO
# db> 

# Reproducer obtained from: Jiaming Zhang <r772577952@gmail.com>
# Bug 293888 - Fatal trap NUM: general protection fault while in kernel mode in cam_periph_runccb

[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1

. ../default.cfg
set -u
prog=$(basename "$0" .sh)
cat > /tmp/$prog.c <<EOF
// Bug 293888 - Fatal trap NUM: general protection fault while in kernel mode in cam_periph_runccb 
// autogenerated by syzkaller (https://github.com/google/syzkaller)

#define _GNU_SOURCE

#include <pwd.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/endian.h>
#include <sys/syscall.h>
#include <unistd.h>

uint64_t r[1] = {0xffffffffffffffff};

int main(void)
{
  syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
          /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
          /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul,
          /*fd=*/(intptr_t)-1, /*offset=*/0ul);
  const char* reason;
  (void)reason;
  intptr_t res = 0;
  if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
  }
  //  openat\$pass_pass_cdevsw arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    file: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 70 61 73 73 30 00} (length 0xb)
  //    }
  //    flags: open_flags = 0x2 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd_pass_pass_cdevsw
  memcpy((void*)0x200000000000, "/dev/pass0\000", 11);
  res = syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul,
                /*file=*/0x200000000000ul, /*flags=O_RDWR*/ 2, /*mode=*/0);
  if (res != -1)
    r[0] = res;
  //  ioctl\$CAMIOCOMMAND_pass_cdevsw arguments: [
  //    fd: fd_pass_pass_cdevsw (resource)
  //    cmd: const = 0xc4e01a02 (8 bytes)
  //    arg: ptr[inout, ccb\$pass_cdevsw] {
  //      union ccb\$pass_cdevsw {
  //        nvmeio: ccb_nvmeio\$pass_cdevsw {
  //          ccb_h: ccb_hdr\$pass_cdevsw {
  //            pinfo: cam_pinfo\$pass_cdevsw {
  //              priority: int32 = 0x8 (4 bytes)
  //              generation: int32 = 0x6 (4 bytes)
  //              index: int32 = 0xb406 (4 bytes)
  //            }
  //            pad = 0x0 (4 bytes)
  //            xpt_links: camq_entry\$pass_cdevsw {
  //              links_next: intptr = 0x100000000 (8 bytes)
  //              priority: int32 = 0x70 (4 bytes)
  //              pad = 0x0 (4 bytes)
  //            }
  //            sim_links: camq_entry\$pass_cdevsw {
  //              links_next: intptr = 0x7 (8 bytes)
  //              priority: int32 = 0x81 (4 bytes)
  //              pad = 0x0 (4 bytes)
  //            }
  //            periph_links: camq_entry\$pass_cdevsw {
  //              links_next: intptr = 0x8000000000000000 (8 bytes)
  //              priority: int32 = 0xffffffc0 (4 bytes)
  //              pad = 0x0 (4 bytes)
  //            }
  //            retry_count: int16 = 0xa5f (2 bytes)
  //            alloc_flags: int16 = 0xb (2 bytes)
  //            pad = 0x0 (4 bytes)
  //            cbfcnp: intptr = 0x3ff (8 bytes)
  //            func_code: int32 = 0x10 (4 bytes)
  //            status: int32 = 0x3 (4 bytes)
  //            path: intptr = 0xe10 (8 bytes)
  //            path_id: int32 = 0x8 (4 bytes)
  //            target_id: int32 = 0x7fffffff (4 bytes)
  //            target_lun: int64 = 0x4 (8 bytes)
  //            flags: int32 = 0xe (4 bytes)
  //            xflags: int32 = 0x130d (4 bytes)
  //            periph_priv: buffer: {5c d8 48 b0 e1 42 d0 a6 b0 73 4f 56 fb 07
  //            08 b5} (length 0x10) sim_priv: buffer: {0f c0 f1 57 fc dc a5 76
  //            71 ad 9f 46 0c eb b2 fc} (length 0x10) qos: buffer: {7a 6f cd f8
  //            b3 f0 65 53 2e 65 18 29 70 c1 63 f1} (length 0x10) timeout:
  //            int32 = 0x8000 (4 bytes) pad = 0x0 (4 bytes) softtimeout:
  //            timeval {
  //              sec: intptr = 0x6 (8 bytes)
  //              usec: intptr = 0x9 (8 bytes)
  //            }
  //          }
  //          payload: buffer: {ec d6 eb 0c 55 29 7e 1e f2 e6 3a 2a f3 42 36 6e
  //          a7 f5 a6 9d 6b af 27 16 0d 12 f7 c7 a6 d3 dc 8d 89 88 c3 75 c4 2c
  //          a8 fb 0a 90 70 3d c6 5a 63 b8 ac 32 e2 21 4b 36 13 0e 64 c1 86 b2
  //          38 66 cc bf 6d c9 86 33 8c eb a1 fa b5 dd 55 c8 76 04 6d c2 b8 20
  //          31 11 5f 24 8b f4 d7 00 7c 7a 4f 00 4e fd 2f 0f 57 bc c2 00 22 b1
  //          23 4f 4b 19 c7 9a 47 1e b0 ea 60 87 f3 88 71 9d d1 e4 dd 15 da bf
  //          0d 03 34 d9 32 bf b5 80 9f 72 80 dc 37 b2 0e 79 d3 96 93 12 50 0c
  //          77 0b d9 9d 0c 93 0c b2 c8 03 bc 75 14 5a c0 50 dc 3f d3 92 ee 07
  //          b5 a9 f2 85 76 a7 36 8d 6f 71 fb 8a cb ee 8c 0c 77 8d 81 b0 02 38
  //          70 4a 3d c9 1a f5 4f 91 e6 a1 14 93 3e be a0 e8 7a 69 33 cc e4 d2
  //          8c 88 af c9 05 d4 74 b0 87 a3 34 3b 0c 9e d4 42 bd 8e 03 24 91 2c
  //          94 1f 5b 88 7c 0c b2 07 af 68 43 d0 5b cb f9 b2 64 ce b6 c9}
  //          (length 0x100)
  //        }
  //      }
  //    }
  //  ]
  *(uint32_t*)0x200000000140 = 8;
  *(uint32_t*)0x200000000144 = 6;
  *(uint32_t*)0x200000000148 = 0xb406;
  *(uint64_t*)0x200000000150 = 0x100000000;
  *(uint32_t*)0x200000000158 = 0x70;
  *(uint64_t*)0x200000000160 = 7;
  *(uint32_t*)0x200000000168 = 0x81;
  *(uint64_t*)0x200000000170 = 0x8000000000000000;
  *(uint32_t*)0x200000000178 = 0xffffffc0;
  *(uint16_t*)0x200000000180 = 0xa5f;
  *(uint16_t*)0x200000000182 = 0xb;
  *(uint64_t*)0x200000000188 = 0x3ff;
  *(uint32_t*)0x200000000190 = 0x10;
  *(uint32_t*)0x200000000194 = 3;
  *(uint64_t*)0x200000000198 = 0xe10;
  *(uint32_t*)0x2000000001a0 = 8;
  *(uint32_t*)0x2000000001a4 = 0x7fffffff;
  *(uint64_t*)0x2000000001a8 = 4;
  *(uint32_t*)0x2000000001b0 = 0xe;
  *(uint32_t*)0x2000000001b4 = 0x130d;
  memcpy((void*)0x2000000001b8,
         "\x5c\xd8\x48\xb0\xe1\x42\xd0\xa6\xb0\x73\x4f\x56\xfb\x07\x08\xb5",
         16);
  memcpy((void*)0x2000000001c8,
         "\x0f\xc0\xf1\x57\xfc\xdc\xa5\x76\x71\xad\x9f\x46\x0c\xeb\xb2\xfc",
         16);
  memcpy((void*)0x2000000001d8,
         "\x7a\x6f\xcd\xf8\xb3\xf0\x65\x53\x2e\x65\x18\x29\x70\xc1\x63\xf1",
         16);
  *(uint32_t*)0x2000000001e8 = 0x8000;
  *(uint64_t*)0x2000000001f0 = 6;
  *(uint64_t*)0x2000000001f8 = 9;
  memcpy(
      (void*)0x200000000200,
      "\xec\xd6\xeb\x0c\x55\x29\x7e\x1e\xf2\xe6\x3a\x2a\xf3\x42\x36\x6e\xa7\xf5"
      "\xa6\x9d\x6b\xaf\x27\x16\x0d\x12\xf7\xc7\xa6\xd3\xdc\x8d\x89\x88\xc3\x75"
      "\xc4\x2c\xa8\xfb\x0a\x90\x70\x3d\xc6\x5a\x63\xb8\xac\x32\xe2\x21\x4b\x36"
      "\x13\x0e\x64\xc1\x86\xb2\x38\x66\xcc\xbf\x6d\xc9\x86\x33\x8c\xeb\xa1\xfa"
      "\xb5\xdd\x55\xc8\x76\x04\x6d\xc2\xb8\x20\x31\x11\x5f\x24\x8b\xf4\xd7\x00"
      "\x7c\x7a\x4f\x00\x4e\xfd\x2f\x0f\x57\xbc\xc2\x00\x22\xb1\x23\x4f\x4b\x19"
      "\xc7\x9a\x47\x1e\xb0\xea\x60\x87\xf3\x88\x71\x9d\xd1\xe4\xdd\x15\xda\xbf"
      "\x0d\x03\x34\xd9\x32\xbf\xb5\x80\x9f\x72\x80\xdc\x37\xb2\x0e\x79\xd3\x96"
      "\x93\x12\x50\x0c\x77\x0b\xd9\x9d\x0c\x93\x0c\xb2\xc8\x03\xbc\x75\x14\x5a"
      "\xc0\x50\xdc\x3f\xd3\x92\xee\x07\xb5\xa9\xf2\x85\x76\xa7\x36\x8d\x6f\x71"
      "\xfb\x8a\xcb\xee\x8c\x0c\x77\x8d\x81\xb0\x02\x38\x70\x4a\x3d\xc9\x1a\xf5"
      "\x4f\x91\xe6\xa1\x14\x93\x3e\xbe\xa0\xe8\x7a\x69\x33\xcc\xe4\xd2\x8c\x88"
      "\xaf\xc9\x05\xd4\x74\xb0\x87\xa3\x34\x3b\x0c\x9e\xd4\x42\xbd\x8e\x03\x24"
      "\x91\x2c\x94\x1f\x5b\x88\x7c\x0c\xb2\x07\xaf\x68\x43\xd0\x5b\xcb\xf9\xb2"
      "\x64\xce\xb6\xc9",
      256);
  syscall(SYS_ioctl, /*fd=*/r[0], /*cmd=*/0xc4e01a02ul,
          /*arg=*/0x200000000140ul);
  return 0;
}
EOF
mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1

timeout 3m /tmp/$prog > /dev/null 2>&1

rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core
exit 0
