1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5# 6# Copyright (c) 2019 Dell EMC Isilon 7# 8# Redistribution and use in source and binary forms, with or without 9# modification, are permitted provided that the following conditions 10# are met: 11# 1. Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# 2. Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in the 15# documentation and/or other materials provided with the distribution. 16# 17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27# SUCH DAMAGE. 28# 29 30# No problems seen. 31# Test scenario inspired by: 32# syzbot+6532e9aab8911f58beeb@syzkaller.appspotmail.com 33 34. ../default.cfg 35[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1 36[ `uname -m` = "i386" ] && exit 0 # OOM killing 37 38dir=/tmp 39odir=`pwd` 40cd $dir 41sed '1,/^EOF/d' < $odir/$0 > $dir/indir_trunc.c 42mycc -o indir_trunc -Wall -Wextra -O0 -g indir_trunc.c -lpthread || exit 1 43rm -f indir_trunc.c 44cd $odir 45 46set -e 47mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint 48[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart 49mdconfig -a -t swap -s 40g -u $mdstart 50newfs $newfs_flags -n md$mdstart > /dev/null 51mount /dev/md$mdstart $mntpoint 52set +e 53 54###(cd ../testcases/swap; ./swap -t 5m -i 20) & 55cd $mntpoint 56$dir/indir_trunc 57s=$? 58while pkill swap; do :; done 59wait 60[ -f indir_trunc.core -a $s -eq 0 ] && 61 { ls -l indir_trunc.core; mv indir_trunc.core $dir; s=1; } 62cd $odir 63 64for i in `jot 6`; do 65 mount | grep -q "on $mntpoint " || break 66 umount $mntpoint && break || sleep 10 67 [ $i -eq 6 ] && 68 { echo FATAL; fstat -mf $mntpoint; exit 1; } 69done 70mdconfig -d -u $mdstart 71rm -rf $dir/indir_trunc 72exit $s 73 74EOF 75#include <sys/param.h> 76#include <sys/mman.h> 77#include <sys/stat.h> 78#include <sys/wait.h> 79 80#include <machine/atomic.h> 81 82#include <err.h> 83#include <errno.h> 84#include <fcntl.h> 85#include <pthread.h> 86#include <stdio.h> 87#include <stdlib.h> 88#include <time.h> 89#include <unistd.h> 90 91static volatile u_int *share; 92 93#if defined(__LP64__) 94#define MASK 0x7ffffffffffffULL 95#else 96#define MASK 0xffffffff 97#endif 98#define PARALLEL 64 99#define RUNTIME (5 * 60) 100#define SYNC 0 101 102static int fd; 103 104static void * 105t1(void *data __unused) 106{ 107 off_t offset; 108 time_t start; 109 char *cmdline[] = { "/usr/bin/true", NULL }; 110 111 start = time(NULL); 112 while (time(NULL) - start < 60) { 113 offset = arc4random(); 114 offset = (offset << 32) | arc4random(); 115 offset &= MASK; 116 if (lseek(fd, offset, SEEK_SET) == -1) 117 err(1, "lseek(%jd)", offset); 118 if (write(fd, "a", 1) != 1) 119 err(1, "write"); 120 usleep(10); 121 if (arc4random() % 1000 < 2) { 122 if (execve(cmdline[0], cmdline, NULL) == -1) 123 err(1, "execve"); 124 } 125 } 126 127 return (NULL); 128} 129static void * 130t2(void *data __unused) 131{ 132 off_t offset, old; 133 time_t start; 134 void *p; 135 char *c; 136 137 old = 0; 138 start = time(NULL); 139 while (time(NULL) - start < 60) { 140 if (old != 0) 141 munmap(p, old); 142 offset = arc4random(); 143 offset = (offset << 32) | arc4random(); 144 offset &= MASK; 145 if (ftruncate(fd, offset) == -1) 146 err(1, "ftruncate(%jd)", offset); 147 write(fd, "b", 1); 148 p = mmap(NULL, offset, PROT_READ | PROT_WRITE, MAP_SHARED, 149 fd, 0); 150 if (p == MAP_FAILED) 151 old = 0; 152 else { 153 old = offset; 154 c = p; 155 c[offset / 2] = 1; 156 if (offset > 0) 157 c[offset - 1] = 2; 158 } 159 usleep(10); 160 } 161 return (NULL); 162} 163 164static void 165test(void) 166{ 167 pthread_t tid[2]; 168 int r; 169 char file[80]; 170 171 atomic_add_int(&share[SYNC], 1); 172 while (share[SYNC] != PARALLEL) 173 ; 174 175 snprintf(file, sizeof(file), "file.%d", getpid()); 176 if ((fd = open(file, O_RDWR | O_CREAT, DEFFILEMODE)) == -1) 177 err(1, "open(%s)", file); 178 179 if ((r = pthread_create(&tid[0], NULL, t1, NULL)) != 0) 180 errc(1, r, "pthread_create"); 181 if ((r = pthread_create(&tid[1], NULL, t2, NULL)) != 0) 182 errc(1, r, "pthread_create"); 183 184 if ((r = pthread_join(tid[0], NULL)) != 0) 185 errc(1, r, "pthread_join"); 186 if ((r = pthread_join(tid[1], NULL)) != 0) 187 errc(1, r, "pthread_join"); 188 close(fd); 189 unlink(file); 190 191 _exit(0); 192} 193 194int 195main(void) 196{ 197 pid_t pids[PARALLEL]; 198 size_t len; 199 time_t start; 200 int e, i, status; 201 202 e = 0; 203 len = PAGE_SIZE; 204 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 205 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 206 err(1, "mmap"); 207 208 start = time(NULL); 209 while ((time(NULL) - start) < RUNTIME && e == 0) { 210 share[SYNC] = 0; 211 for (i = 0; i < PARALLEL; i++) { 212 if ((pids[i] = fork()) == 0) 213 test(); 214 if (pids[i] == -1) 215 err(1, "fork()"); 216 } 217 for (i = 0; i < PARALLEL; i++) { 218 if (waitpid(pids[i], &status, 0) == -1) 219 err(1, "waitpid(%d)", pids[i]); 220 if (status != 0) { 221 if (WIFSIGNALED(status)) 222 fprintf(stderr, 223 "pid %d exit signal %d\n", 224 pids[i], WTERMSIG(status)); 225 } 226 e += status == 0 ? 0 : 1; 227 } 228 } 229 230 return (e); 231} 232