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