#!/bin/sh

# panic: attempt to create an sbuf of negative length (-812160735)
# cpuid = 17
# time = 1618331215
# KDB: stack backtrace:
# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe01af75b610
# vpanic() at vpanic+0x181/frame 0xfffffe01af75b660
# panic() at panic+0x43/frame 0xfffffe01af75b6c0
# sbuf_new() at sbuf_new+0x191/frame 0xfffffe01af75b6f0
# sbuf_uionew() at sbuf_uionew+0x29/frame 0xfffffe01af75b720
# pfs_write() at pfs_write+0xc8/frame 0xfffffe01af75b7c0
# VOP_WRITE_APV() at VOP_WRITE_APV+0xcf/frame 0xfffffe01af75b8d0
# vn_write() at vn_write+0x2eb/frame 0xfffffe01af75b960
# vn_io_fault() at vn_io_fault+0x13a/frame 0xfffffe01af75b9e0
# dofilewrite() at dofilewrite+0x81/frame 0xfffffe01af75ba30
# kern_pwritev() at kern_pwritev+0x62/frame 0xfffffe01af75ba70
# sys_pwrite() at sys_pwrite+0x8a/frame 0xfffffe01af75bac0
# amd64_syscall() at amd64_syscall+0x147/frame 0xfffffe01af75bbf0
# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe01af75bbf0
# --- syscall (476, FreeBSD ELF64, sys_pwrite), rip = 0x800384d2a, rsp = 0x7fffffffe868, rbp = 0x7fffffffe8a0 ---
# KDB: enter: panic
# [ thread pid 3011 tid 100788 ]
# Stopped at      kdb_enter+0x37: movq    $0,0x1284cce(%rip)
# db> x/s version
# version: FreeBSD 14.0-CURRENT #0 main-n245908-243000b19f8: Fri Apr  9 09:43:54 CEST 2021
# pho@t2.osted.lan:/usr/src/sys/amd64/compile/PHO
# db>

. ../default.cfg

mount | grep -q "procfs on /proc"  || exit 0

cat > /tmp/pwrite.c <<EOF
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/uio.h>

#include <err.h>
#include <fcntl.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

static char *files[] = {
	"/proc/curproc/dbregs",
	"/proc/curproc/fpregs",
	"/proc/curproc/mem",
	"/proc/curproc/osrel",
	"/proc/curproc/regs",
};

static char p[4096];

static unsigned long
makearg(void)
{
	unsigned int i;
	unsigned long val;

	val = arc4random();
	i   = arc4random() % 100;
	if (i < 20)
		val = val & 0xff;
	if (i >= 20 && i < 40)
		val = val & 0xffff;
#if defined(__LP64__)
	if (i >= 40) {
		val = (val << 32) | arc4random();
		if (i > 80)
			val = val & 0x00007fffffffffffUL;
	}
#endif

	return(val);
}

int
main(void)
{
	off_t off;
	size_t len;
	time_t start;
	int fd, i;

	alarm(120);

	i = arc4random() % 5;
	if ((fd = open(files[i], O_RDWR)) == -1)
		err(1, "%s", files[i]);

	start = time(NULL);
	while (time(NULL) - start < 120) {

		len = makearg();
		off = makearg();
		pwrite(fd, p, len, off);
	}

	close(fd);
}
EOF
cc -o /tmp/pwrite -Wall -Wextra -O2 /tmp/pwrite.c || exit 1

for i in `jot 10`; do
	/tmp/pwrite &
done
wait

rm /tmp/pwrite /tmp/pwrite.c
exit 0
