#!/bin/sh

# Kernel page fault with the following non-sleepable locks held:
# exclusive sleep mutex CAM device lock (CAM device lock) r = 0 (0xfffff8000365ecd0) locked @ cam/scsi/scsi_pass.c:1973
# stack backtrace:
# #0 0xffffffff80c4787c at witness_debugger+0x6c
# #1 0xffffffff80c49189 at witness_warn+0x4c9
# #2 0xffffffff81131d8c at trap_pfault+0x8c
# #3 0xffffffff811015a8 at calltrap+0x8
# #4 0xffffffff803d8e3e at passdoioctl+0x9be
# #5 0xffffffff803d8102 at passioctl+0x22
# #6 0xffffffff80a413b1 at devfs_ioctl+0xd1
# #7 0xffffffff81204821 at VOP_IOCTL_APV+0x51
# #8 0xffffffff80cf0890 at vn_ioctl+0x160
# #9 0xffffffff80a41a7e at devfs_ioctl_f+0x1e
# #10 0xffffffff80c4e3c1 at kern_ioctl+0x2a1
# #11 0xffffffff80c4e0bf at sys_ioctl+0x12f
# #12 0xffffffff811327d9 at amd64_syscall+0x169
# #13 0xffffffff81101e9b at fast_syscall_common+0xf8
# 
# 
# Fatal trap 12: page fault while in kernel mode
# cpuid = 11; apic id = 0b
# fault virtual address	= 0x50
# fault code		= supervisor read data, page not present
# instruction pointer	= 0x20:0xffffffff803a1e9c
# stack pointer	        = 0x28:0xfffffe01000d5af0
# frame pointer	        = 0x28:0xfffffe01000d5b30
# 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		= 4511 (syzkaller92)
# rdi: fffff8016ace27b8 rsi: fffff8016ace2f60 rdx: 0000000000000010
# rcx: 0000000000000010  r8: fffff8000602ad80  r9: ffffffff8226dee8
# rax: 0000000000000010 rbx: fffff8016ace27b8 rbp: fffffe01000d5b30
# r10: fffff8016ace27b8 r11: fffff80066e42cd0 r12: fffff8016ace27b8
# r13: 0000000000000016 r14: fffff80003676200 r15: 0000000000000000
# trap number		= 12
# panic: page fault
# cpuid = 11
# time = 1773833440
# KDB: stack backtrace:
# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe01000d5820
# vpanic() at vpanic+0x136/frame 0xfffffe01000d5950
# panic() at panic+0x43/frame 0xfffffe01000d59b0
# trap_pfault() at trap_pfault+0x422/frame 0xfffffe01000d5a20
# calltrap() at calltrap+0x8/frame 0xfffffe01000d5a20
# --- trap 0xc, rip = 0xffffffff803a1e9c, rsp = 0xfffffe01000d5af0, rbp = 0xfffffe01000d5b30 ---
# xpt_action_default() at xpt_action_default+0x80c/frame 0xfffffe01000d5b30
# passdoioctl() at passdoioctl+0x9be/frame 0xfffffe01000d5b80
# passioctl() at passioctl+0x22/frame 0xfffffe01000d5bc0
# devfs_ioctl() at devfs_ioctl+0xd1/frame 0xfffffe01000d5c10
# VOP_IOCTL_APV() at VOP_IOCTL_APV+0x51/frame 0xfffffe01000d5c40
# vn_ioctl() at vn_ioctl+0x160/frame 0xfffffe01000d5cb0
# devfs_ioctl_f() at devfs_ioctl_f+0x1e/frame 0xfffffe01000d5cd0
# kern_ioctl() at kern_ioctl+0x2a1/frame 0xfffffe01000d5d40
# sys_ioctl() at sys_ioctl+0x12f/frame 0xfffffe01000d5e00
# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe01000d5f30
# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe01000d5f30
# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x824057eca, rsp = 0x820f14468, rbp = 0x820f14490 ---
# KDB: enter: panic
# [ thread pid 4511 tid 100357 ]
# 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> reset

# Reproducer obtained from: Jiaming Zhang <r772577952@gmail.com>
# [Bug 293892] Fatal trap NUM: page fault while in kernel mode in passsendccb

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

. ../default.cfg
set -u
prog=$(basename "$0" .sh)
cat > /tmp/$prog.c <<EOF
// 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>

#ifndef SYS_aio_readv
#define SYS_aio_readv 579
#endif

uint64_t r[2] = {0xffffffffffffffff, 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)) {
  }
  //  rfork arguments: [
  //    flags: rfork_flags = 0x14014 (8 bytes)
  //  ]
  syscall(SYS_rfork, /*flags=RFLINUXTHPN|RFSIGSHARE|RFFDG|RFPROC*/ 0x14014ul);
  //  freebsd11_fhstatfs arguments: [
  //    fhp: nil
  //    buf: nil
  //  ]
  syscall(SYS_freebsd11_fhstatfs, /*fhp=*/0ul, /*buf=*/0ul);
  //  socket\$inet_tcp arguments: [
  //    domain: const = 0x2 (8 bytes)
  //    type: const = 0x1 (8 bytes)
  //    proto: const = 0x0 (1 bytes)
  //  ]
  //  returns sock_tcp
  syscall(SYS_socket, /*domain=*/2ul, /*type=*/1ul, /*proto=*/0);
  //  openat\$bpf arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    file: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 62 70 66 00} (length 0x9)
  //    }
  //    flags: open_flags = 0x8408 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd_bpf
  memcpy((void*)0x200000000980, "/dev/bpf\000", 9);
  res = syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul,
                /*file=*/0x200000000980ul,
                /*flags=O_TRUNC|O_NOCTTY|O_APPEND*/ 0x8408, /*mode=*/0);
  if (res != -1)
    r[0] = res;
  //  aio_readv arguments: [
  //    iocb: ptr[in, aiocb] {
  //      aiocb {
  //        aio_fildes: fd (resource)
  //        pad = 0x0 (4 bytes)
  //        aio_offset: int64 = 0x81 (8 bytes)
  //        aio_buf: ptr[in, buffer] {
  //          buffer: {fa} (length 0x1)
  //        }
  //        aio_nbytes: len = 0x1 (8 bytes)
  //        spare: array[int32] {
  //          int32 = 0xffff (4 bytes)
  //          int32 = 0x7 (4 bytes)
  //        }
  //        spare2: intptr = 0x1 (8 bytes)
  //        aio_lio_opcode: lio_opcodes = 0x18 (4 bytes)
  //        aio_reqprio: int32 = 0x1ff (4 bytes)
  //        aiocb_private: aiocb_private {
  //          status: intptr = 0x37 (8 bytes)
  //          error: intptr = 0x24 (8 bytes)
  //          kernelinfo: nil
  //        }
  //        aio_sigevent: sigevent {
  //          notify: sigev_notify = 0x0 (4 bytes)
  //          signo: int32 = 0x13 (4 bytes)
  //          val: union sigval {
  //            sigval_int: int32 = 0x6 (4 bytes)
  //          }
  //          u: union sigevent_u {
  //            ke_flags: evflags = 0x8000 (2 bytes)
  //          }
  //        }
  //      }
  //    }
  //  ]
  *(uint32_t*)0x200000000040 = r[0];
  *(uint64_t*)0x200000000048 = 0x81;
  *(uint64_t*)0x200000000050 = 0x200000000000;
  memset((void*)0x200000000000, 250, 1);
  *(uint64_t*)0x200000000058 = 1;
  *(uint32_t*)0x200000000060 = 0xffff;
  *(uint32_t*)0x200000000064 = 7;
  *(uint64_t*)0x200000000068 = 1;
  *(uint32_t*)0x200000000070 = 0x18;
  *(uint32_t*)0x200000000074 = 0x1ff;
  *(uint64_t*)0x200000000078 = 0x37;
  *(uint64_t*)0x200000000080 = 0x24;
  *(uint64_t*)0x200000000088 = 0;
  *(uint32_t*)0x200000000090 = 0;
  *(uint32_t*)0x200000000094 = 0x13;
  *(uint32_t*)0x200000000098 = 6;
  *(uint16_t*)0x2000000000a0 = 0x8000;
  syscall(SYS_aio_readv, /*iocb=*/0x200000000040ul);
  //  openat\$bpf arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    file: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 62 70 66 00} (length 0x9)
  //    }
  //    flags: open_flags = 0x800 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd_bpf
  memcpy((void*)0x200000000040, "/dev/bpf\000", 9);
  syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000040ul,
          /*flags=O_EXCL*/ 0x800, /*mode=*/0);
  //  sigaction arguments: [
  //    signo: int32 = 0x6b (4 bytes)
  //    act: ptr[in, sigaction] {
  //      sigaction {
  //        sigaction_u: nil
  //        sa_flags: sigaction_flags = 0x0 (4 bytes)
  //        sa_mask: sigset {
  //          mask: array[int32] {
  //            int32 = 0x4 (4 bytes)
  //            int32 = 0x10 (4 bytes)
  //            int32 = 0x492d (4 bytes)
  //            int32 = 0x3 (4 bytes)
  //          }
  //        }
  //        pad = 0x0 (4 bytes)
  //      }
  //    }
  //    oact: nil
  //  ]
  *(uint64_t*)0x200000000040 = 0;
  *(uint32_t*)0x200000000048 = 0;
  *(uint32_t*)0x20000000004c = 4;
  *(uint32_t*)0x200000000050 = 0x10;
  *(uint32_t*)0x200000000054 = 0x492d;
  *(uint32_t*)0x200000000058 = 3;
  syscall(SYS_sigaction, /*signo=*/0x6b, /*act=*/0x200000000040ul,
          /*oact=*/0ul);
  //  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*)0x200000000100, "/dev/pass0\000", 11);
  res = syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul,
                /*file=*/0x200000000100ul, /*flags=O_RDWR*/ 2, /*mode=*/0);
  if (res != -1)
    r[1] = res;
  //  ioctl\$CAMIOQUEUE_pass_cdevsw arguments: [
  //    fd: fd_pass_pass_cdevsw (resource)
  //    cmd: const = 0x20001a04 (8 bytes)
  //    arg: ptr[in, ptr[in, ccb\$pass_cdevsw]] {
  //      nil
  //    }
  //  ]
  *(uint64_t*)0x200000000000 = 0;
  syscall(SYS_ioctl, /*fd=*/r[1], /*cmd=*/0x20001a04ul,
          /*arg=*/0x200000000000ul);
  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
