#!/bin/sh

# Reproducer obtained from: Jiaming Zhang <r772577952@gmail.com>
# Bug 293901 - panic: mutex ACPI global lock owned at ../../../kern/kern_event.c:LINE

# No problems seen.

[ `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)) {
  }
  //  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 = 0x80000 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd_bpf
  memcpy((void*)0x200000000000, "/dev/bpf\000", 9);
  syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000000ul,
          /*flags=O_TTY_INIT*/ 0x80000, /*mode=*/0);
  //  openat\$consolectl_consolectl_devsw arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    file: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 63 6f 6e 73 6f 6c 65 63 74 6c 00} (length
  //      0x10)
  //    }
  //    flags: open_flags = 0x400000 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd
  memcpy((void*)0x200000000740, "/dev/consolectl\000", 16);
  syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000740ul,
          /*flags=O_PATH*/ 0x400000, /*mode=*/0);
  //  openat\$pvclock_pvclock_cdev_cdevsw arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    path: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 70 76 63 6c 6f 63 6b 00} (length 0xd)
  //    }
  //    flags: open_flags = 0x400000 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd
  memcpy((void*)0x200000000d00, "/dev/pvclock\000", 13);
  syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul, /*path=*/0x200000000d00ul,
          /*flags=O_PATH*/ 0x400000, /*mode=*/0);
  //  openat\$apm_apm_cdevsw arguments: [
  //    fd: const = 0xffffffffffffff9c (8 bytes)
  //    file: ptr[in, buffer] {
  //      buffer: {2f 64 65 76 2f 61 70 6d 00} (length 0x9)
  //    }
  //    flags: open_flags = 0x2000000 (4 bytes)
  //    mode: const = 0x0 (4 bytes)
  //  ]
  //  returns fd_apm_apm_cdevsw
  memcpy((void*)0x200000000b40, "/dev/apm\000", 9);
  syscall(SYS_openat, /*fd=*/0xffffffffffffff9cul, /*file=*/0x200000000b40ul,
          /*flags=O_EMPTY_PATH*/ 0x2000000, /*mode=*/0);
  //  kqueue arguments: [
  //  ]
  //  returns kqueue
  res = syscall(SYS_kqueue);
  if (res != -1)
    r[0] = res;
  //  kevent arguments: [
  //    kqueue: kqueue (resource)
  //    changelist: ptr[in, array[kevent]] {
  //      array[kevent] {
  //        kevent {
  //          ident: intptr = 0x6 (8 bytes)
  //          filter: filters = 0xfffffffffffffff3 (2 bytes)
  //          flags: evflags = 0x4035 (2 bytes)
  //          fflags: fflags = 0x0 (4 bytes)
  //          data: int64 = 0x5 (8 bytes)
  //          udata: intptr = 0x40000000007 (8 bytes)
  //          ext: array[int64] {
  //            int64 = 0x4 (8 bytes)
  //            int64 = 0x100000000 (8 bytes)
  //            int64 = 0x4 (8 bytes)
  //            int64 = 0x5 (8 bytes)
  //          }
  //        }
  //      }
  //    }
  //    nchanges: len = 0x1 (8 bytes)
  //    eventlist: nil
  //    nevents: len = 0x0 (8 bytes)
  //    timeout: nil
  //  ]
  *(uint64_t*)0x200000000400 = 6;
  *(uint16_t*)0x200000000408 = 0xfff3;
  *(uint16_t*)0x20000000040a = 0x4035;
  *(uint32_t*)0x20000000040c = 0;
  *(uint64_t*)0x200000000410 = 5;
  *(uint64_t*)0x200000000418 = 0x40000000007;
  *(uint64_t*)0x200000000420 = 4;
  *(uint64_t*)0x200000000428 = 0x100000000;
  *(uint64_t*)0x200000000430 = 4;
  *(uint64_t*)0x200000000438 = 5;
  syscall(SYS_kevent, /*kqueue=*/r[0], /*changelist=*/0x200000000400ul,
          /*nchanges=*/1ul, /*eventlist=*/0ul, /*nevents=*/0ul,
          /*timeout=*/0ul);
  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
