#!/bin/sh

# panic: ata_action: ccb 0xfffff80347e777b8, func_code 0x1 should not be allocated from UMA zone
# cpuid = 1
# time = 1773837671
# KDB: stack backtrace:
# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe0100044980
# vpanic() at vpanic+0x136/frame 0xfffffe0100044ab0
# panic() at panic+0x43/frame 0xfffffe0100044b10
# ata_action() at ata_action+0x3bd/frame 0xfffffe0100044b30
# passdoioctl() at passdoioctl+0x9be/frame 0xfffffe0100044b80
# passioctl() at passioctl+0x22/frame 0xfffffe0100044bc0
# devfs_ioctl() at devfs_ioctl+0xd1/frame 0xfffffe0100044c10
# VOP_IOCTL_APV() at VOP_IOCTL_APV+0x51/frame 0xfffffe0100044c40
# vn_ioctl() at vn_ioctl+0x160/frame 0xfffffe0100044cb0
# devfs_ioctl_f() at devfs_ioctl_f+0x1e/frame 0xfffffe0100044cd0
# kern_ioctl() at kern_ioctl+0x2a1/frame 0xfffffe0100044d40
# sys_ioctl() at sys_ioctl+0x12f/frame 0xfffffe0100044e00
# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe0100044f30
# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe0100044f30
# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x823bc5eca, rsp = 0x820d83df8, rbp = 0x820d83e20 ---
# KDB: enter: panic
# [ thread pid 4628 tid 100215 ]
# 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 293895 - panic: ata_action: ccb ADDR, func_code XXX should not be allocated from UMA zone

[ `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>

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)) {
  }
  //  sigaction arguments: [
  //    signo: int32 = 0x68 (4 bytes)
  //    act: ptr[in, sigaction] {
  //      sigaction {
  //        sigaction_u: nil
  //        sa_flags: sigaction_flags = 0x2 (4 bytes)
  //        sa_mask: sigset {
  //          mask: array[int32] {
  //            int32 = 0xe4 (4 bytes)
  //            int32 = 0x1 (4 bytes)
  //            int32 = 0x4000a (4 bytes)
  //            int32 = 0xe (4 bytes)
  //          }
  //        }
  //        pad = 0x0 (4 bytes)
  //      }
  //    }
  //    oact: nil
  //  ]
  *(uint64_t*)0x200000000040 = 0;
  *(uint32_t*)0x200000000048 = 2;
  *(uint32_t*)0x20000000004c = 0xe4;
  *(uint32_t*)0x200000000050 = 1;
  *(uint32_t*)0x200000000054 = 0x4000a;
  *(uint32_t*)0x200000000058 = 0xe;
  syscall(SYS_sigaction, /*signo=*/0x68, /*act=*/0x200000000040ul,
          /*oact=*/0ul);
  //  mount\$nfs_newnfs_vnodeops_nosig arguments: [
  //    fstype: ptr[in, buffer] {
  //      buffer: {6e 66 73 00} (length 0x4)
  //    }
  //    dir: ptr[in, buffer] {
  //      buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
  //    }
  //    mnt_flags: mount_flags = 0x0 (4 bytes)
  //    data: ptr[in, nfs_args\$newnfs_vnodeops_nosig] {
  //      nfs_args\$newnfs_vnodeops_nosig {
  //        version: const = 0x3 (4 bytes)
  //        pad = 0x0 (4 bytes)
  //        addr: nil
  //        addrlen: len = 0x0 (4 bytes)
  //        sotype: sock_type_newnfs_vnodeops_nosig = 0x2 (4 bytes)
  //        proto: int32 = 0x4010003 (4 bytes)
  //        pad = 0x0 (4 bytes)
  //        fh: nil
  //        fhsize: len = 0x0 (4 bytes)
  //        nfs_flags: nfs_mount_flags_newnfs_vnodeops_nosig = 0x8cc006 (4
  //        bytes) wsize: int32 = 0x7fff (4 bytes) rsize: int32 = 0xaf8 (4
  //        bytes) readdirsize: int32 = 0x9 (4 bytes) timeo: int32 = 0x3 (4
  //        bytes) retrans: int32 = 0x800 (4 bytes) maxgrouplist: int32 = 0x9 (4
  //        bytes) readahead: int32 = 0x1 (4 bytes) wcommitsize: int32 = 0x7 (4
  //        bytes) deadthresh: int32 = 0x1 (4 bytes) pad = 0x0 (4 bytes)
  //        hostname: nil
  //        acregmin: int32 = 0x204 (4 bytes)
  //        acregmax: int32 = 0x0 (4 bytes)
  //        acdirmin: int32 = 0xfffffff6 (4 bytes)
  //        acdirmax: int32 = 0x3 (4 bytes)
  //      }
  //    }
  //  ]
  memcpy((void*)0x200000000040, "nfs\000", 4);
  memcpy((void*)0x200000000080, "./file0\000", 8);
  *(uint32_t*)0x200000000200 = 3;
  *(uint64_t*)0x200000000208 = 0;
  *(uint32_t*)0x200000000210 = 0;
  *(uint32_t*)0x200000000214 = 2;
  *(uint32_t*)0x200000000218 = 0x4010003;
  *(uint64_t*)0x200000000220 = 0;
  *(uint32_t*)0x200000000228 = 0;
  *(uint32_t*)0x20000000022c = 0x8cc006;
  *(uint32_t*)0x200000000230 = 0x7fff;
  *(uint32_t*)0x200000000234 = 0xaf8;
  *(uint32_t*)0x200000000238 = 9;
  *(uint32_t*)0x20000000023c = 3;
  *(uint32_t*)0x200000000240 = 0x800;
  *(uint32_t*)0x200000000244 = 9;
  *(uint32_t*)0x200000000248 = 1;
  *(uint32_t*)0x20000000024c = 7;
  *(uint32_t*)0x200000000250 = 1;
  *(uint64_t*)0x200000000258 = 0;
  *(uint32_t*)0x200000000260 = 0x204;
  *(uint32_t*)0x200000000264 = 0;
  *(uint32_t*)0x200000000268 = 0xfffffff6;
  *(uint32_t*)0x20000000026c = 3;
  syscall(SYS_mount, /*fstype=*/0x200000000040ul, /*dir=*/0x200000000080ul,
          /*mnt_flags=*/0, /*data=*/0x200000000200ul);
  //  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[0] = 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[0], /*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
