1*86db3c73SPeter Holm#!/bin/sh 2*86db3c73SPeter Holm 3*86db3c73SPeter Holm# 4*86db3c73SPeter Holm# Copyright (c) 2025 Peter Holm <pho@FreeBSD.org> 5*86db3c73SPeter Holm# 6*86db3c73SPeter Holm# SPDX-License-Identifier: BSD-2-Clause 7*86db3c73SPeter Holm# 8*86db3c73SPeter Holm 9*86db3c73SPeter Holm# Bug 289700 - unionfs: page fault in unionfs_find_node_status when closing a file within a socket's receive buffer 10*86db3c73SPeter Holm 11*86db3c73SPeter Holm# "Fatal trap 12: page fault while in kernel mode" seen: 12*86db3c73SPeter Holm# https://people.freebsd.org/~pho/stress/log/log0618.txt 13*86db3c73SPeter Holm 14*86db3c73SPeter Holm. ../default.cfg 15*86db3c73SPeter Holm 16*86db3c73SPeter Holmprog=$(basename "$0" .sh) 17*86db3c73SPeter Holmhere=`pwd` 18*86db3c73SPeter Holmlog=/tmp/$prog.log 19*86db3c73SPeter Holmmd1=$mdstart 20*86db3c73SPeter Holmmd2=$((md1 + 1)) 21*86db3c73SPeter Holmmp1=/mnt$md1 22*86db3c73SPeter Holmmp2=/mnt$md2 23*86db3c73SPeter Holm 24*86db3c73SPeter Holmset -eu 25*86db3c73SPeter Holmmdconfig -l | grep -q md$md1 && mdconfig -d -u $md1 26*86db3c73SPeter Holmmdconfig -l | grep -q md$md2 && mdconfig -d -u $md2 27*86db3c73SPeter Holm 28*86db3c73SPeter Holmmdconfig -s 2g -u $md1 29*86db3c73SPeter Holmnewfs $newfs_flags /dev/md$md1 > /dev/null 30*86db3c73SPeter Holmmdconfig -s 2g -u $md2 31*86db3c73SPeter Holmnewfs $newfs_flags /dev/md$md2 > /dev/null 32*86db3c73SPeter Holm 33*86db3c73SPeter Holmmkdir -p $mp1 $mp2 34*86db3c73SPeter Holmmount /dev/md$md1 $mp1 35*86db3c73SPeter Holmmount /dev/md$md2 $mp2 36*86db3c73SPeter Holmmount -t unionfs -o noatime $mp1 $mp2 37*86db3c73SPeter Holmset +e 38*86db3c73SPeter Holm 39*86db3c73SPeter Holmcd /tmp 40*86db3c73SPeter Holmsed '1,/^EOF/d' < $here/$0 > $prog.c 41*86db3c73SPeter Holmmycc -o $prog -Wall -Wextra -O2 $prog.c 42*86db3c73SPeter Holmrm -f $prog.c 43*86db3c73SPeter Holm[ -d $RUNDIR ] || mkdir -p $RUNDIR 44*86db3c73SPeter Holmcd $RUNDIR 45*86db3c73SPeter Holm 46*86db3c73SPeter Holmn=3 47*86db3c73SPeter Holmfor i in `jot $n`; do 48*86db3c73SPeter Holm mkdir $mp2/d$i 49*86db3c73SPeter Holmdone 50*86db3c73SPeter Holm(cd $here/../testcases/swap; ./swap -t 3m -i 20 -l 100 -h > /dev/null) & 51*86db3c73SPeter Holmsleep 2 52*86db3c73SPeter Holmfor i in `jot $n`; do 53*86db3c73SPeter Holm (cd $mp2/d$i; /tmp/$prog) & 54*86db3c73SPeter Holmdone 55*86db3c73SPeter Holmwhile pgrep -q $prog; do sleep .5; done 56*86db3c73SPeter Holmwhile pkill swap; do :; done 57*86db3c73SPeter Holmwait 58*86db3c73SPeter Holm 59*86db3c73SPeter Holmcd $here 60*86db3c73SPeter Holmumount $mp2 # The unionfs mount 61*86db3c73SPeter Holmumount $mp2 62*86db3c73SPeter Holmumount $mp1 63*86db3c73SPeter Holm 64*86db3c73SPeter Holmmdconfig -d -u $md1 65*86db3c73SPeter Holmmdconfig -d -u $md2 66*86db3c73SPeter Holmrm -f /tmp/$prog 67*86db3c73SPeter Holmexit 0 68*86db3c73SPeter HolmEOF 69*86db3c73SPeter Holm#include <sys/param.h> 70*86db3c73SPeter Holm#include <sys/mman.h> 71*86db3c73SPeter Holm#include <sys/socket.h> 72*86db3c73SPeter Holm#include <sys/uio.h> 73*86db3c73SPeter Holm#include <sys/wait.h> 74*86db3c73SPeter Holm 75*86db3c73SPeter Holm#include <stdio.h> 76*86db3c73SPeter Holm#include <errno.h> 77*86db3c73SPeter Holm#include <err.h> 78*86db3c73SPeter Holm#include <stdlib.h> 79*86db3c73SPeter Holm#include <time.h> 80*86db3c73SPeter Holm#include <unistd.h> 81*86db3c73SPeter Holm#include <fcntl.h> 82*86db3c73SPeter Holm#include <poll.h> 83*86db3c73SPeter Holm#include <stdatomic.h> 84*86db3c73SPeter Holm#include <string.h> 85*86db3c73SPeter Holm 86*86db3c73SPeter Holm#define PARALLEL 2 87*86db3c73SPeter Holm#define SYNC 0 88*86db3c73SPeter Holm 89*86db3c73SPeter Holmstatic int debug; 90*86db3c73SPeter Holmstatic _Atomic(int) *share; 91*86db3c73SPeter Holm 92*86db3c73SPeter Holmint 93*86db3c73SPeter Holmsend_fd(int socket, int fd_to_send) 94*86db3c73SPeter Holm{ 95*86db3c73SPeter Holm struct cmsghdr *cmsg; 96*86db3c73SPeter Holm struct msghdr msg = {0}; 97*86db3c73SPeter Holm struct iovec iov; 98*86db3c73SPeter Holm char buf[1] = {0}; // dummy data 99*86db3c73SPeter Holm char cmsgbuf[CMSG_SPACE(sizeof(fd_to_send))]; 100*86db3c73SPeter Holm 101*86db3c73SPeter Holm memset(cmsgbuf, 0, sizeof(cmsgbuf)); 102*86db3c73SPeter Holm 103*86db3c73SPeter Holm iov.iov_base = buf; 104*86db3c73SPeter Holm iov.iov_len = sizeof(buf); 105*86db3c73SPeter Holm msg.msg_iov = &iov; 106*86db3c73SPeter Holm msg.msg_iovlen = 1; 107*86db3c73SPeter Holm 108*86db3c73SPeter Holm msg.msg_control = cmsgbuf; 109*86db3c73SPeter Holm msg.msg_controllen = sizeof(cmsgbuf); 110*86db3c73SPeter Holm 111*86db3c73SPeter Holm cmsg = CMSG_FIRSTHDR(&msg); 112*86db3c73SPeter Holm cmsg->cmsg_level = SOL_SOCKET; 113*86db3c73SPeter Holm cmsg->cmsg_type = SCM_RIGHTS; 114*86db3c73SPeter Holm cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); 115*86db3c73SPeter Holm 116*86db3c73SPeter Holm memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(fd_to_send)); 117*86db3c73SPeter Holm 118*86db3c73SPeter Holm return (sendmsg(socket, &msg, 0)); 119*86db3c73SPeter Holm} 120*86db3c73SPeter Holm 121*86db3c73SPeter Holmint 122*86db3c73SPeter Holmrecv_fd(int socket) 123*86db3c73SPeter Holm{ 124*86db3c73SPeter Holm struct cmsghdr *cmsg; 125*86db3c73SPeter Holm struct msghdr msg = {0}; 126*86db3c73SPeter Holm struct iovec iov; 127*86db3c73SPeter Holm char buf[1]; 128*86db3c73SPeter Holm int received_fd; 129*86db3c73SPeter Holm char cmsgbuf[CMSG_SPACE(sizeof(received_fd))]; 130*86db3c73SPeter Holm 131*86db3c73SPeter Holm memset(cmsgbuf, 0, sizeof(cmsgbuf)); 132*86db3c73SPeter Holm 133*86db3c73SPeter Holm iov.iov_base = buf; 134*86db3c73SPeter Holm iov.iov_len = sizeof(buf); 135*86db3c73SPeter Holm msg.msg_iov = &iov; 136*86db3c73SPeter Holm msg.msg_iovlen = 1; 137*86db3c73SPeter Holm 138*86db3c73SPeter Holm msg.msg_control = cmsgbuf; 139*86db3c73SPeter Holm msg.msg_controllen = sizeof(cmsgbuf); 140*86db3c73SPeter Holm 141*86db3c73SPeter Holm if (recvmsg(socket, &msg, 0) < 0) 142*86db3c73SPeter Holm err(1, "recvmsg()"); 143*86db3c73SPeter Holm 144*86db3c73SPeter Holm cmsg = CMSG_FIRSTHDR(&msg); 145*86db3c73SPeter Holm if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(received_fd))) { 146*86db3c73SPeter Holm fprintf(stderr, "No passed fd\n"); 147*86db3c73SPeter Holm return (-1); 148*86db3c73SPeter Holm } 149*86db3c73SPeter Holm 150*86db3c73SPeter Holm if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 151*86db3c73SPeter Holm fprintf(stderr, "Invalid cmsg_level or cmsg_type\n"); 152*86db3c73SPeter Holm return (-1); 153*86db3c73SPeter Holm } 154*86db3c73SPeter Holm 155*86db3c73SPeter Holm memcpy(&received_fd, CMSG_DATA(cmsg), sizeof(received_fd)); 156*86db3c73SPeter Holm return (received_fd); 157*86db3c73SPeter Holm} 158*86db3c73SPeter Holm 159*86db3c73SPeter Holmint 160*86db3c73SPeter Holmmain(void) 161*86db3c73SPeter Holm{ 162*86db3c73SPeter Holm pid_t pid; 163*86db3c73SPeter Holm time_t start; 164*86db3c73SPeter Holm size_t len; 165*86db3c73SPeter Holm int fd, pair[2], status; 166*86db3c73SPeter Holm 167*86db3c73SPeter Holm fd = -1; 168*86db3c73SPeter Holm len = PAGE_SIZE; 169*86db3c73SPeter Holm if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 170*86db3c73SPeter Holm MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 171*86db3c73SPeter Holm err(1, "mmap"); 172*86db3c73SPeter Holm 173*86db3c73SPeter Holm if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, pair) == -1) 174*86db3c73SPeter Holm err(1, "socketpair"); 175*86db3c73SPeter Holm 176*86db3c73SPeter Holm start = time(NULL); 177*86db3c73SPeter Holm while (time(NULL) - start < 180) { 178*86db3c73SPeter Holm share[SYNC] = 0; 179*86db3c73SPeter Holm if ((pid = fork()) == -1) 180*86db3c73SPeter Holm err(1, "fork"); 181*86db3c73SPeter Holm if (pid == 0) { 182*86db3c73SPeter Holm close(pair[0]); 183*86db3c73SPeter Holm atomic_fetch_add(&share[SYNC], 1); 184*86db3c73SPeter Holm while (share[SYNC] != PARALLEL) 185*86db3c73SPeter Holm usleep(1000); 186*86db3c73SPeter Holm // Not calling recv_fd() triggers the issue 187*86db3c73SPeter Holm// fd = recv_fd(pair[1]); 188*86db3c73SPeter Holm if (debug) 189*86db3c73SPeter Holm fprintf(stderr, "Received fd=%d\n", fd); 190*86db3c73SPeter Holm _exit(0); 191*86db3c73SPeter Holm } 192*86db3c73SPeter Holm fd = open("foo", O_RDWR|O_CREAT|O_TRUNC, 0666); 193*86db3c73SPeter Holm if (fd == -1) 194*86db3c73SPeter Holm err(1, "open"); 195*86db3c73SPeter Holm if (debug) 196*86db3c73SPeter Holm fprintf(stderr, "Sending fd=%d\n", fd); 197*86db3c73SPeter Holm atomic_fetch_add(&share[SYNC], 1); 198*86db3c73SPeter Holm while (share[SYNC] != PARALLEL) 199*86db3c73SPeter Holm usleep(1000); 200*86db3c73SPeter Holm send_fd(pair[0], fd); 201*86db3c73SPeter Holm usleep(arc4random() % 1000); 202*86db3c73SPeter Holm wait(&status); 203*86db3c73SPeter Holm close(fd); 204*86db3c73SPeter Holm unlink("foo"); 205*86db3c73SPeter Holm } 206*86db3c73SPeter Holm} 207