diff --git a/tools/test/stress2/misc/setrlimit.sh b/tools/test/stress2/misc/setrlimit.sh new file mode 100755 index 000000000000..ea679f987510 --- /dev/null +++ b/tools/test/stress2/misc/setrlimit.sh @@ -0,0 +1,193 @@ +#!/bin/sh + +# +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2022 Peter Holm +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 + +# Test setrlimit() max file size and ftruncate() + +# Problem seen: +# Testing UFS -O1 +# setrlimit: ftruncate(5413) did not fail. limit = 2791 +# Testing FFS -U +# setrlimit: ftruncate(9956) did not fail. limit = 7880 +# Testing msdosfs +# setrlimit: ftruncate(9033) did not fail. limit = 5884 +# Testing tmpfs +# setrlimit: ftruncate(123) did not fail. limit = 86 + +. ../default.cfg + +cat > /tmp/setrlimit.c < +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int signals; + +static void +handler(int sig __unused) +{ +#if defined(DEBUG) + fprintf(stderr, "Got signal SIGXFSZ\n"); +#endif + signals++; +} + +void +test(int argc, char *argv[]) +{ + struct rlimit rlim; + rlim_t limit, sz; + struct sigaction act; + long pos; + int e, expected, fd; + char file[] = "setrlimit.file"; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + expected = signals = 0; + sz = atol(argv[1]); + arc4random_buf(&limit, sizeof(limit)); + if (limit < 0) + limit = -limit; + limit = limit % sz + 1; + rlim.rlim_cur = rlim.rlim_max = limit; + if (setrlimit(RLIMIT_FSIZE, &rlim) == -1) + err(1, "setrlimit(%ld)", limit); + + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGXFSZ, &act, NULL) != 0) + err(1, "sigaction"); + + if ((fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE)) == -1) + err(1, "open(%s)", file); + + e = 0; + arc4random_buf(&pos, sizeof(pos)); + if (pos < 0) + pos = -pos; + pos = pos % (limit * 2); + if (pos > limit) + expected = 1; + if (ftruncate(fd, pos) == -1) { + e = errno; + if (pos <= limit) + errc(1, e, "ftruncate(%ld), limit = %ld", pos, limit); + } else { + if (pos > limit) + errx(1, "ftruncate(%ld) did not fail. limit = %ld", pos, limit); + } + + if (lseek(fd, limit - 1, SEEK_SET) == -1) + err(1, "lseek(limit - 1)"); + if (write(fd, "a", 1) != 1) + err(1, "write() at limit - 1. limit = %ld", limit); + + if (write(fd, "b", 1) != -1) + err(1, "write() at limit. limit = %ld", limit); + expected++; + + /* Partial write test. No signal is expected */ + if (lseek(fd, limit - 1, SEEK_SET) == -1) + err(1, "lseek(limit - 1)"); + if (write(fd, "12", 2) != 1) + err(1, "write() at limit - 1. limit = %ld", limit); + + if (signals != expected) + errx(1, "Expected %d signals, got %d", expected, signals); + + close(fd); + unlink(file); +} + +int +main(int argc, char *argv[]) +{ + int i; + + for (i = 0; i < 100; i++) + test(argc, argv); + +} +EOF + +here=`pwd` +s=0 +cc -o /tmp/setrlimit -Wall -Wextra -O0 -g /tmp/setrlimit.c || exit 1 + +mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint +[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart + +echo "Testing UFS -O1" +mdconfig -t swap -s 1g -u $mdstart +newfs -O1 /dev/md$mdstart > /dev/null +mount /dev/md$mdstart $mntpoint +cd $mntpoint; /tmp/setrlimit 10000 || s=1 +cd $here +umount $mntpoint +mdconfig -d -u $mdstart + +echo "Testing FFS -U" +mdconfig -t swap -s 1g -u $mdstart +newfs -U /dev/md$mdstart > /dev/null +mount /dev/md$mdstart $mntpoint +cd $mntpoint; /tmp/setrlimit 10000 || s=$((s + 2)) +cd $here +umount $mntpoint +mdconfig -d -u $mdstart + +echo "Testing msdosfs" +mdconfig -t swap -s 1g -u $mdstart +newfs_msdos -F 32 -b 8192 /dev/md$mdstart > /dev/null 2>&1 +mount -t msdosfs /dev/md$mdstart $mntpoint +cd $mntpoint; /tmp/setrlimit 10000 || s=$((s + 4)) +cd $here +umount $mntpoint +mdconfig -d -u $mdstart + +echo "Testing tmpfs" +mount -o size=20000 -t tmpfs dummy $mntpoint +cd $mntpoint; /tmp/setrlimit 10000 || s=$((s + 8)) +cd $here +umount $mntpoint + +rm -f /tmp/setrlimit /tmp/setrlimit.c +exit $s diff --git a/tools/test/stress2/misc/setrlimit2.sh b/tools/test/stress2/misc/setrlimit2.sh new file mode 100755 index 000000000000..f0b933158393 --- /dev/null +++ b/tools/test/stress2/misc/setrlimit2.sh @@ -0,0 +1,118 @@ +#!/bin/sh + +# +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2022 Peter Holm +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Demonstrate that a mapped SHARED file can be updated past past LIMIT_FSIZE + +# Kostik wrote: +# This one should be reproducible when you +# - have file larger than e.g. RLIMIT_FSIZE +# - mmaped it without closing the file descriptor +# - dirty its pages beyond the limit +# - then unmap +# - then close the file descriptor. + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 + +. ../default.cfg + +cat > /tmp/setrlimit2.c < +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static int signals; + +static void +handler(int sig __unused) +{ + signals++; +} + +int +main(int argc, char *argv[]) +{ + struct rlimit rlim; + struct sigaction act; + struct stat st; + size_t len; + int error, fd, ps; + char *file, *p; + + if (argc != 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset(&act.sa_mask); + if (sigaction(SIGXFSZ, &act, NULL) != 0) + err(1, "sigaction"); + + file = argv[1]; + ps = getpagesize(); + if ((fd = open(file, O_RDWR)) == -1) + err(1, "open(%s)", file); + if ((error = fstat(fd, &st)) == -1) + err(1, "stat(%s)", file); + len = round_page(st.st_size); + if ((p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) + err(1, "mmap"); + rlim.rlim_cur = rlim.rlim_max = len / 2;; + if (setrlimit(RLIMIT_FSIZE, &rlim) == -1) + err(1, "setrlimit(%ld)", len / 2); + + p[len / 2 + ps] = 'a'; + + if (munmap(p, len) == -1) + err(1, "unmap()"); + close(fd); + +} +EOF +here=`pwd` +cd /tmp +mycc -o setrlimit2 -Wall -Wextra -O0 -g setrlimit2.c || exit 1 +data=/tmp/setrlimit2.data +dd if=/dev/zero of=$data bs=1m count=1 status=none +h1=`md5 < $data` + +./setrlimit2 $data + +h2=`md5 < $data` +rm -f /tmp/setrlimit2 /tmp/setrlimit2.c +[ $h1 = $h2 ] && exit 1 || exit 0 diff --git a/tools/test/stress2/misc/sigreturn3.sh b/tools/test/stress2/misc/sigreturn3.sh new file mode 100755 index 000000000000..1070876539b6 --- /dev/null +++ b/tools/test/stress2/misc/sigreturn3.sh @@ -0,0 +1,182 @@ +#!/bin/sh + +# +# SPDX-License-Identifier: BSD-2-Clause-FreeBSD +# +# Copyright (c) 2022 Peter Holm +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# Fatal trap -4186856: UNKNOWN while in kernel mode +# cpuid = 1; apic id = 01 +# error code = 0xfbafcf8c +# instruction pointer = 0x79e4:0x4 +# stack pointer = 0x28:0xffc0aff0 +# frame pointer = 0x28:0x204620d4 +# code segment = base 0x0, limit 0x0, type 0x0 +# = DPL 0, pres 0, def32 0, gran 0 +# processor eflags = trace trap, at 0x3b/frame 0xffc0340c +# KDB: enter: panic +# [ thread pid 15631 tid 114622 ] +# Stopped at kdb_enter+0x34: movl $0,kdb_why +# db> + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 +prog=sigreturn3 + +cat > /tmp/$prog.c < +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define N 4096 +#define RUNTIME 120 +#define THREADS 1 + +static uint32_t r[N]; + +static void +hand(int i __unused) { /* handler */ + exit(1); +} + +static void * +churn(void *arg __unused) +{ + time_t start; + + pthread_set_name_np(pthread_self(), __func__); + start = time(NULL); + while (time(NULL) - start < 10) { + arc4random_buf(r, sizeof(r)); + usleep(100); + } + return(NULL); +} + +static void * +calls(void *arg __unused) +{ + time_t start; + int i; + + start = time(NULL); + for (i = 0; time(NULL) - start < 10; i++) { + arc4random_buf(r, sizeof(r)); + alarm(1); + syscall(SYS_sigreturn, r); + } + + return (NULL); +} + +int +main(int argc, char **argv) +{ + struct passwd *pw; + struct rlimit limit; + pid_t pid; + pthread_t rp, cp[THREADS]; + time_t start; + int e, j; + + if ((pw = getpwnam("nobody")) == NULL) + err(1, "failed to resolve nobody"); + + if (getenv("USE_ROOT") && argc == 2) + fprintf(stderr, "Running syscall4 as root for %s.\n", + argv[1]); + else { + if (setgroups(1, &pw->pw_gid) || + setegid(pw->pw_gid) || setgid(pw->pw_gid) || + seteuid(pw->pw_uid) || setuid(pw->pw_uid)) + err(1, "Can't drop privileges to \"nobody\""); + endpwent(); + } + + limit.rlim_cur = limit.rlim_max = 1000; +#if defined(RLIMIT_NPTS) + if (setrlimit(RLIMIT_NPTS, &limit) < 0) + err(1, "setrlimit"); +#endif + + signal(SIGALRM, hand); + signal(SIGILL, hand); + signal(SIGFPE, hand); + signal(SIGSEGV, hand); + signal(SIGBUS, hand); + signal(SIGURG, hand); + signal(SIGSYS, hand); + signal(SIGTRAP, hand); + + if (daemon(1, 1) == -1) + err(1, "daemon()"); + + start = time(NULL); + while ((time(NULL) - start) < RUNTIME) { + if ((pid = fork()) == 0) { + if ((e = pthread_create(&rp, NULL, churn, NULL)) != 0) + errc(1, e, "pthread_create"); + for (j = 0; j < THREADS; j++) + if ((e = pthread_create(&cp[j], NULL, calls, + NULL)) != 0) + errc(1, e, "pthread_create"); + for (j = 0; j < THREADS; j++) + pthread_join(cp[j], NULL); + + if ((e = pthread_kill(rp, SIGINT)) != 0) + errc(1, e, "pthread_kill"); + if ((e = pthread_join(rp, NULL)) != 0) + errc(1, e, "pthread_join"); + _exit(0); + } + waitpid(pid, NULL, 0); + } + + return (0); +} +EOF + +cd /tmp +cc -o $prog -Wall -Wextra -O0 $prog.c -lpthread || exit 1 +start=`date +%s` +while [ $((`date +%s` - start)) -lt 300 ]; do + ./$prog > /dev/null 2>&1 + date +%T +done +rm -f /tmp/$prog /tmp/$ptog.c /tmp/$prog.core +exit 0 diff --git a/tools/test/stress2/misc/sigreturn4.sh b/tools/test/stress2/misc/sigreturn4.sh new file mode 100755 index 000000000000..f7916dc3b1ee --- /dev/null +++ b/tools/test/stress2/misc/sigreturn4.sh @@ -0,0 +1,208 @@ +#!/bin/sh + +# panic: vm_fault_lookup: fault on nofault entry, addr: 0 +# cpuid = 2 +# time = 1661698922 +# KDB: stack backtrace: +# db_trace_self_wrapper(b,2931e740,2931e742,ffc0ddb8,190431,...) at db_trace_self_wrapper+0x28/frame 0xffc0dd24 +# vpanic(150acba,ffc0dd60,ffc0dd60,ffc0de20,12cc155,...) at vpanic+0xf4/frame 0xffc0dd40 +# panic(150acba,14ec1ab,0,146253d,1430,...) at panic+0x14/frame 0xffc0dd54 +# vm_fault(1e360c8,0,4,0,0) at vm_fault+0x1725/frame 0xffc0de20 +# vm_fault_trap(1e360c8,3b,4,0,0,0) at vm_fault_trap+0x52/frame 0xffc0de48 +# trap_pfault(3b,0,0) at trap_pfault+0x176/frame 0xffc0de94 +# trap(ffc0df6c,8,28,28,19156000,...) at trap+0x2d9/frame 0xffc0df60 +# calltrap() at 0xffc031ef/frame 0xffc0df60 +# --- trap 0xc, eip = 0x3b, esp = 0xffc0dfac, ebp = 0xffc0340c --- +# (null)() at 0x3b/frame 0xffc0340c +# KDB: enter: panic +# [ thread pid 54680 tid 102765 ] +# Stopped at kdb_enter+0x34: movl $0,kdb_why +# db> x/s version +# version: FreeBSD 14.0-CURRENT #0 main-n257606-9ea2716b775-dirty: Thu Aug 25 10:47:45 CEST 2022 +# pho@mercat1.netperf.freebsd.org:/media/ob +# j/usr/src/i386.i386/sys/PHO\012 +# db> show proc +# Process 54680 (date) at 0x28905d50: +# state: NORMAL +# uid: 0 gids: 0, 0, 5 +# parent: pid 785 at 0x26c14000 +# ABI: FreeBSD ELF32 +# flag: 0x10004002 flag2: 0 +# arguments: date +%s +# reaper: 0x18c710a4 reapsubtree: 1 +# sigparent: 20 +# vmspace: 0x29332100 +# (map 0x29332100) +# (map.pmap 0x29332174) +# (pmap 0x293321b0) +# threads: 1 +# 102765 Run CPU 2 date +# db> + +[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 +prog=sigreturn4 + +cat > /tmp/$prog.c < +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RUNTIME 120 +#define THREADS 1 + +static void +hand(int i __unused) { /* handler */ + _exit(1); +} + +static long +random_long(long mi, long ma) +{ + return (arc4random() % (ma - mi + 1) + mi); +} + +static void +flip(void *ap, size_t len) +{ + unsigned char *cp; + int byte; + unsigned char bit, buf, mask, old __unused; + + cp = (unsigned char *)ap; + byte = random_long(0, len); + bit = random_long(0,7); + mask = ~(1 << bit); + buf = cp[byte]; + old = cp[byte]; + buf = (buf & mask) | (~buf & ~mask); + cp[byte] = buf; +} + +static void * +churn(void *arg __unused) +{ + time_t start; + + start = time(NULL); + while (time(NULL) - start < 10) { + usleep(100); + } + return(NULL); +} + +static void * +calls(void *arg __unused) +{ + time_t start; + ucontext_t uc; + int i, n; + + start = time(NULL); + for (i = 0; time(NULL) - start < 10; i++) { + n = 0; + if (getcontext(&uc) == -1) + err(1, "getcontext"); + n++; + + if (n == 1) { + flip(&uc, sizeof(uc)); + alarm(1); + if (sigreturn(&uc) == -1) + err(1, "sigreturn()"); + } else + break; + } + return (NULL); +} + +int +main(int argc, char **argv) +{ + struct passwd *pw; + struct rlimit limit; + pid_t pid; + pthread_t rp, cp[THREADS]; + time_t start; + int e, j; + + if ((pw = getpwnam("nobody")) == NULL) + err(1, "failed to resolve nobody"); + + if (getenv("USE_ROOT") && argc == 2) + fprintf(stderr, "Running sigreturn4 as root for %s.\n", + argv[1]); + else { + if (setgroups(1, &pw->pw_gid) || + setegid(pw->pw_gid) || setgid(pw->pw_gid) || + seteuid(pw->pw_uid) || setuid(pw->pw_uid)) + err(1, "Can't drop privileges to \"nobody\""); + endpwent(); + } + + limit.rlim_cur = limit.rlim_max = 1000; +#if defined(RLIMIT_NPTS) + if (setrlimit(RLIMIT_NPTS, &limit) < 0) + err(1, "setrlimit"); +#endif + + signal(SIGALRM, hand); + signal(SIGILL, hand); + signal(SIGFPE, hand); + signal(SIGSEGV, hand); + signal(SIGBUS, hand); + signal(SIGURG, hand); + signal(SIGSYS, hand); + signal(SIGTRAP, hand); + + if (daemon(1, 1) == -1) + err(1, "daemon()"); + + start = time(NULL); + while ((time(NULL) - start) < RUNTIME) { + if ((pid = fork()) == 0) { + if ((e = pthread_create(&rp, NULL, churn, NULL)) != 0) + errc(1, e, "pthread_create"); + for (j = 0; j < THREADS; j++) + if ((e = pthread_create(&cp[j], NULL, calls, + NULL)) != 0) + errc(1, e, "pthread_create"); + for (j = 0; j < THREADS; j++) + pthread_join(cp[j], NULL); + + if ((e = pthread_kill(rp, SIGINT)) != 0) + errc(1, e, "pthread_kill"); + if ((e = pthread_join(rp, NULL)) != 0) + errc(1, e, "pthread_join"); + _exit(0); + } + waitpid(pid, NULL, 0); + } + + return (0); +} +EOF + +cd /tmp +cc -o $prog -Wall -Wextra -O0 $prog.c -lpthread || exit 1 +start=`date +%s` +while [ $((`date +%s` - start)) -lt 300 ]; do + ./$prog > /dev/null 2>&1 + date +%T +done +rm -f /tmp/$prog /tmp/$ptog.c /tmp/$prog.core +exit 0