#!/bin/sh

# 806.906239 [ 653] nm_os_extmem_delete       freeing 1000000 bytes
# panic: dst_m 0xfffffe00130fd920 is not wired
# cpuid = 7
# time = 1773855806
# KDB: stack backtrace:
# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe010022eb00
# vpanic() at vpanic+0x136/frame 0xfffffe010022ec30
# panic() at panic+0x43/frame 0xfffffe010022ec90
# vm_fault_copy_entry() at vm_fault_copy_entry+0x54e/frame 0xfffffe010022ed60
# vm_map_protect() at vm_map_protect+0x714/frame 0xfffffe010022edf0
# sys_mprotect() at sys_mprotect+0x9f/frame 0xfffffe010022ee00
# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe010022ef30
# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe010022ef30
# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x822fa9eca, rsp = 0x820c270e8, rbp = 0x820c27110 ---
# KDB: enter: panic
# [ thread pid 4510 tid 100369 ]
# 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 293900 - panic: dst_m ADDR is not wired

[ `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)) {
  }
  //  mlock arguments: [
  //    addr: VMA[0x1000]
  //    size: len = 0x1000 (8 bytes)
  //  ]
  syscall(SYS_mlock, /*addr=*/0x200000ffc000ul, /*size=*/0x1000ul);
  //  munlock arguments: [
  //    addr: VMA[0x4000]
  //    size: len = 0x4000 (8 bytes)
  //  ]
  syscall(SYS_munlock, /*addr=*/0x200000ff9000ul, /*size=*/0x4000ul);
  //  fork arguments: [
  //  ]
  //  returns pid
  syscall(SYS_fork);
  //  mkdir arguments: [
  //    path: ptr[in, buffer] {
  //      buffer: {2e 2f 66 69 6c 65 30 00} (length 0x8)
  //    }
  //    mode: open_mode = 0x109 (8 bytes)
  //  ]
  memcpy((void*)0x200000000300, "./file0\000", 8);
  syscall(SYS_mkdir, /*path=*/0x200000000300ul,
          /*mode=S_IXOTH|S_IXGRP|S_IRUSR*/ 0x109ul);
  //  mprotect arguments: [
  //    addr: VMA[0x4000]
  //    len: len = 0x4000 (8 bytes)
  //    prot: mmap_prot = 0x4 (8 bytes)
  //  ]
  syscall(SYS_mprotect, /*addr=*/0x200000ffc000ul, /*len=*/0x4000ul,
          /*prot=PROT_EXEC*/ 4ul);
  //  mlock arguments: [
  //    addr: VMA[0x4000]
  //    size: len = 0x4000 (8 bytes)
  //  ]
  syscall(SYS_mlock, /*addr=*/0x200000ffb000ul, /*size=*/0x4000ul);
  //  mount\$nfs_newnfs_vnodeops_nosig arguments: [
  //    fstype: nil
  //    dir: nil
  //    mnt_flags: mount_flags = 0x58000000 (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 = 0x4 (4 bytes)
  //        proto: int32 = 0xb (4 bytes)
  //        pad = 0x0 (4 bytes)
  //        fh: nil
  //        fhsize: len = 0x0 (4 bytes)
  //        nfs_flags: nfs_mount_flags_newnfs_vnodeops_nosig = 0x8 (4 bytes)
  //        wsize: int32 = 0x5 (4 bytes)
  //        rsize: int32 = 0x6 (4 bytes)
  //        readdirsize: int32 = 0x0 (4 bytes)
  //        timeo: int32 = 0x8 (4 bytes)
  //        retrans: int32 = 0x1 (4 bytes)
  //        maxgrouplist: int32 = 0x4 (4 bytes)
  //        readahead: int32 = 0x800 (4 bytes)
  //        wcommitsize: int32 = 0x4 (4 bytes)
  //        deadthresh: int32 = 0x200 (4 bytes)
  //        pad = 0x0 (4 bytes)
  //        hostname: nil
  //        acregmin: int32 = 0x80 (4 bytes)
  //        acregmax: int32 = 0x1 (4 bytes)
  //        acdirmin: int32 = 0x2 (4 bytes)
  //        acdirmax: int32 = 0xa92 (4 bytes)
  //      }
  //    }
  //  ]
  *(uint32_t*)0x200000000240 = 3;
  *(uint64_t*)0x200000000248 = 0;
  *(uint32_t*)0x200000000250 = 0;
  *(uint32_t*)0x200000000254 = 4;
  *(uint32_t*)0x200000000258 = 0xb;
  *(uint64_t*)0x200000000260 = 0;
  *(uint32_t*)0x200000000268 = 0;
  *(uint32_t*)0x20000000026c = 8;
  *(uint32_t*)0x200000000270 = 5;
  *(uint32_t*)0x200000000274 = 6;
  *(uint32_t*)0x200000000278 = 0;
  *(uint32_t*)0x20000000027c = 8;
  *(uint32_t*)0x200000000280 = 1;
  *(uint32_t*)0x200000000284 = 4;
  *(uint32_t*)0x200000000288 = 0x800;
  *(uint32_t*)0x20000000028c = 4;
  *(uint32_t*)0x200000000290 = 0x200;
  *(uint64_t*)0x200000000298 = 0;
  *(uint32_t*)0x2000000002a0 = 0x80;
  *(uint32_t*)0x2000000002a4 = 1;
  *(uint32_t*)0x2000000002a8 = 2;
  *(uint32_t*)0x2000000002ac = 0xa92;
  syscall(SYS_mount, /*fstype=*/0ul, /*dir=*/0ul,
          /*mnt_flags=MNT_ACLS|MNT_NOCLUSTERR|MNT_NOATIME*/ 0x58000000,
          /*data=*/0x200000000240ul);
  //  openat\$netmap_netmap_cdevsw arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    file: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 6e 65 74 6d 61 70 00} (length 0xc)
  //    }
  //    flags: open_flags = 0x8 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd_netmap_netmap_cdevsw
  memcpy((void*)0x200000000080, "/dev/netmap\000", 12);
  res = syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul,
                /*file=*/0x200000000080ul, /*flags=O_APPEND*/ 8, /*mode=*/0);
  if (res != -1)
    r[0] = res;
  //  ioctl\$NIOCCTRL_netmap_cdevsw arguments: [
  //    fd: fd_netmap_netmap_cdevsw (resource)
  //    cmd: const = 0xc0586997 (8 bytes)
  //    arg: ptr[inout, nmreq_header\$netmap_cdevsw] {
  //      nmreq_header\$netmap_cdevsw {
  //        nr_version: const = 0xe (2 bytes)
  //        nr_reqtype: netmap_req_types_netmap_cdevsw = 0x1 (2 bytes)
  //        nr_reserved: const = 0x0 (4 bytes)
  //        nr_name: buffer: {fd dc df f0 57 4f 3c 7c e4 5f 8c a0 60 dd 3e f8 85
  //        76 39 53 90 de 06 ef fd a7 de 31 18 a2 d4 3a c7 d3 2a a5 0a c1 17 23
  //        6a fe eb 89 29 84 f2 62 d2 83 53 b7 67 c7 b2 ee 8c 39 68 f1 3f 73 52
  //        b4} (length 0x40) nr_options: ptr[inout,
  //        nmreq_option_types\$netmap_cdevsw] {
  //          union nmreq_option_types\$netmap_cdevsw {
  //            kloop_fds: nmreq_opt_sync_kloop_eventfds\$netmap_cdevsw {
  //              nro_next: ptr[in, nmreq_option_types\$netmap_cdevsw] {
  //                union nmreq_option_types\$netmap_cdevsw {
  //                  extmem: nmreq_opt_extmem\$netmap_cdevsw {
  //                    nro_next: nil
  //                    nro_reqtype: const = 0x1 (4 bytes)
  //                    nro_status: int32 = 0x80000000 (4 bytes)
  //                    nro_size: len = 0x28 (8 bytes)
  //                    nro_usrptr: VMA[0x3000]
  //                    nro_info: int32 = 0x100000 (4 bytes)
  //                    nro_size_ptr: len = 0x3000 (4 bytes)
  //                  }
  //                }
  //              }
  //              nro_reqtype: const = 0x2 (4 bytes)
  //              nro_status: int32 = 0x0 (4 bytes)
  //              nro_size: len = 0x18 (8 bytes)
  //              eventfds:
  //              array[nmreq_opt_sync_kloop_eventfd_pair\$netmap_cdevsw] {
  //              }
  //            }
  //          }
  //        }
  //        nr_body: ptr[inout, nmreq_body\$netmap_cdevsw] {
  //          union nmreq_body\$netmap_cdevsw {
  //            reg: nmreq_register\$netmap_cdevsw {
  //              nr_name: buffer: {c4 c0 99 4a 5e 6e 71 96 98 b6 cc 78 3c 37 aa
  //              7c} (length 0x10) nr_mode: nmreq_register_mode_netmap_cdevsw =
  //              0x1 (4 bytes) nr_ringid: nmreq_register_ringid_netmap_cdevsw =
  //              0x2000 (4 bytes) nr_flags: nmreq_register_flags_netmap_cdevsw
  //              = 0x0 (4 bytes) nr_mem_id: int32 = 0x9 (4 bytes) nr_spare:
  //              buffer: {00 00 00 00 00 00 00 00} (length 0x8)
  //            }
  //          }
  //        }
  //      }
  //    }
  //  ]
  *(uint16_t*)0x200000000140 = 0xe;
  *(uint16_t*)0x200000000142 = 1;
  *(uint32_t*)0x200000000144 = 0;
  memcpy((void*)0x200000000148,
         "\xfd\xdc\xdf\xf0\x57\x4f\x3c\x7c\xe4\x5f\x8c\xa0\x60\xdd\x3e\xf8\x85"
         "\x76\x39\x53\x90\xde\x06\xef\xfd\xa7\xde\x31\x18\xa2\xd4\x3a\xc7\xd3"
         "\x2a\xa5\x0a\xc1\x17\x23\x6a\xfe\xeb\x89\x29\x84\xf2\x62\xd2\x83\x53"
         "\xb7\x67\xc7\xb2\xee\x8c\x39\x68\xf1\x3f\x73\x52\xb4",
         64);
  *(uint64_t*)0x200000000188 = 0x200000000340;
  *(uint64_t*)0x200000000340 = 0x200000000240;
  *(uint64_t*)0x200000000240 = 0;
  *(uint32_t*)0x200000000248 = 1;
  *(uint32_t*)0x20000000024c = 0x80000000;
  *(uint64_t*)0x200000000250 = 0x28;
  *(uint64_t*)0x200000000258 = 0x200000ffa000;
  *(uint32_t*)0x200000000260 = 0x100000;
  *(uint32_t*)0x200000000264 = 0x3000;
  *(uint32_t*)0x200000000348 = 2;
  *(uint64_t*)0x200000000350 = 0x18;
  *(uint64_t*)0x200000000190 = 0x200000000040;
  memcpy((void*)0x200000000040,
         "\xc4\xc0\x99\x4a\x5e\x6e\x71\x96\x98\xb6\xcc\x78\x3c\x37\xaa\x7c",
         16);
  *(uint32_t*)0x200000000050 = 1;
  *(uint32_t*)0x200000000054 = 0x2000;
  *(uint32_t*)0x200000000058 = 0;
  *(uint32_t*)0x20000000005c = 9;
  memset((void*)0x200000000060, 0, 8);
  syscall(SYS_ioctl, /*fd=*/r[0], /*cmd=*/0xc0586997ul,
          /*arg=*/0x200000000140ul);
  //  mprotect arguments: [
  //    addr: VMA[0x4000]
  //    len: len = 0x4000 (8 bytes)
  //    prot: mmap_prot = 0x6 (8 bytes)
  //  ]
  syscall(SYS_mprotect, /*addr=*/0x200000ffc000ul, /*len=*/0x4000ul,
          /*prot=PROT_WRITE|PROT_EXEC*/ 6ul);
  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
