diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index 308cfd22a0ec..143c13297585 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -1,120 +1,122 @@ .include PACKAGE= tests TESTSRC= ${SRCTOP}/contrib/netbsd-tests/kernel .PATH: ${SRCTOP}/sys/kern TESTSDIR= ${TESTSBASE}/sys/kern ATF_TESTS_C+= basic_signal .if ${MACHINE_ARCH} != "i386" && ${MACHINE_ARCH} != "powerpc" && \ ${MACHINE_ARCH} != "powerpcspe" # No support for atomic_load_64 on i386 or (32-bit) powerpc ATF_TESTS_C+= kcov .endif ATF_TESTS_C+= kern_copyin ATF_TESTS_C+= kern_descrip_test ATF_TESTS_C+= fdgrowtable_test ATF_TESTS_C+= kill_zombie .if ${MK_OPENSSL} != "no" ATF_TESTS_C+= ktls_test .endif ATF_TESTS_C+= module_test ATF_TESTS_C+= ptrace_test TEST_METADATA.ptrace_test+= timeout="15" ATF_TESTS_C+= reaper ATF_TESTS_C+= sched_affinity +ATF_TESTS_C+= shutdown_dgram ATF_TESTS_C+= sigaltstack ATF_TESTS_C+= sigwait ATF_TESTS_C+= socket_accept ATF_TESTS_C+= socket_accf ATF_TESTS_C+= socket_msg_trunc ATF_TESTS_C+= socket_msg_waitall TEST_METADATA.sigwait+= is_exclusive="true" .if ${MACHINE_ARCH} != "i386" && ${MACHINE_ARCH:Mpowerpc*} == "" ATF_TESTS_C+= subr_physmem_test .endif PLAIN_TESTS_C+= subr_unit_test ATF_TESTS_C+= sysctl_kern_proc ATF_TESTS_C+= sys_getrandom ATF_TESTS_C+= unix_dgram ATF_TESTS_C+= unix_passfd_dgram TEST_METADATA.unix_passfd_dgram+= is_exclusive="true" ATF_TESTS_C+= unix_passfd_stream TEST_METADATA.unix_passfd_stream+= is_exclusive="true" ATF_TESTS_C+= unix_seqpacket_test TEST_METADATA.unix_seqpacket_test+= timeout="15" ATF_TESTS_C+= unix_socketpair_test ATF_TESTS_C+= waitpid_nohang ATF_TESTS_C+= pdeathsig ATF_TESTS_C+= sigsys TEST_METADATA.sigsys+= is_exclusive="true" ATF_TESTS_SH+= coredump_phnum_test ATF_TESTS_SH+= sonewconn_overflow TEST_METADATA.sonewconn_overflow+= required_programs="python" TEST_METADATA.sonewconn_overflow+= required_user="root" ATF_TESTS_SH+= sendfile_test ${PACKAGE}FILES+= sonewconn_overflow.py ${PACKAGE}FILESMODE_sonewconn_overflow.py=0555 BINDIR= ${TESTSDIR} PROGS+= coredump_phnum_helper PROGS+= pdeathsig_helper PROGS+= sendfile_helper CFLAGS.sys_getrandom+= -I${SRCTOP}/sys/contrib/zstd/lib LIBADD.sys_getrandom+= zstd LIBADD.sys_getrandom+= c LIBADD.sys_getrandom+= pthread LIBADD.ptrace_test+= pthread LIBADD.unix_seqpacket_test+= pthread LIBADD.kcov+= pthread CFLAGS.ktls_test+= -DOPENSSL_API_COMPAT=0x10100000L LIBADD.ktls_test+= crypto util +LIBADD.shutdown_dgram+= pthread LIBADD.socket_msg_waitall+= pthread LIBADD.sendfile_helper+= pthread LIBADD.fdgrowtable_test+= util pthread kvm procstat LIBADD.sigwait+= rt NETBSD_ATF_TESTS_C+= lockf_test NETBSD_ATF_TESTS_C+= mqueue_test NETBSD_ATF_TESTS_C+= sysv_test CFLAGS.mqueue_test+= -I${SRCTOP}/tests LIBADD.mqueue_test+= rt ATF_TESTS_C+= libkern_crc32 SRCS.libkern_crc32+= libkern_crc32.c .PATH: ${SRCTOP}/sys/libkern SRCS.libkern_crc32+= gsb_crc32.c CFLAGS.libkern_crc32+= -DTESTING .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" .PATH: ${SRCTOP}/sys/libkern/x86 SRCS.libkern_crc32+= crc32_sse42.c .elif ${MACHINE_CPUARCH} == "aarch64" .PATH: ${SRCTOP}/sys/libkern/arm64 SRCS.libkern_crc32+= crc32c_armv8.S .endif CFLAGS.subr_physmem.c+= -D_WANT_FREEBSD_BITSET SRCS.subr_physmem_test+= subr_physmem_test.c subr_physmem.c # subr_unit.c contains functions whose prototypes lie in headers that cannot be # included in userland. But as far as subr_unit_test goes, they're effectively # static. So it's ok to disable -Wmissing-prototypes for this program. CFLAGS.subr_unit.c+= -Wno-missing-prototypes SRCS.subr_unit_test+= subr_unit.c WARNS?= 3 TESTS_SUBDIRS+= acct TESTS_SUBDIRS+= execve TESTS_SUBDIRS+= pipe .include .include diff --git a/tests/sys/kern/shutdown_dgram.c b/tests/sys/kern/shutdown_dgram.c new file mode 100644 index 000000000000..04382d14f48f --- /dev/null +++ b/tests/sys/kern/shutdown_dgram.c @@ -0,0 +1,111 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 Gleb Smirnoff + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * shutdown(2) on SOCK_DGRAM shall return ENOTCONN per POSIX. However, there + * is historical behavior of the shutdown(2) also unblocking any ongoing + * recv(2) syscall on the socket. It is known that some programs rely on this + * behavior, but exact list of problems isn't known. Neither we know if the + * "feature" is required on PF_UNIX sockets or on PF_INET/INET6 sockets or + * on both kinds. Feel free to improve this comment if you know any details. + * + * List of relevant commits, bug reports and reviews: + * 63649db04205 + * https://reviews.freebsd.org/D10351 + * b114aa79596c (regresses) + * https://reviews.freebsd.org/D3039 (regresses) + * kern/84761 c5cff17017f9 aada5cccd878 + */ + + +static void * +blocking_thread(void *arg) +{ + int *s = arg; + char buf[1]; + int error, rv; + + rv = recv(*s, buf, sizeof(buf), 0); + error = (rv == -1) ? errno : 0; + + return ((void *)(uintptr_t)error); +} + +static void +shutdown_thread(int s) +{ + pthread_t t; + int rv; + + ATF_REQUIRE(pthread_create(&t, NULL, blocking_thread, &s) == 0); + usleep(1000); + ATF_REQUIRE(shutdown(s, SHUT_RD) == -1); + ATF_REQUIRE(errno == ENOTCONN); + ATF_REQUIRE(pthread_join(t, (void *)&rv) == 0); + ATF_REQUIRE(rv == 0); + close(s); +} + +ATF_TC_WITHOUT_HEAD(unblock); +ATF_TC_BODY(unblock, tc) +{ + static const struct sockaddr_un sun = { + .sun_family = AF_LOCAL, + .sun_len = sizeof(sun), + .sun_path = "shutdown-dgram-test-sock", + }; + int s; + + ATF_REQUIRE((s = socket(PF_UNIX, SOCK_DGRAM, 0)) >= 0); + ATF_REQUIRE(bind(s, (struct sockaddr *)&sun, sizeof(sun)) == 0); + shutdown_thread(s); + + static const struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_len = sizeof(sin), + }; + ATF_REQUIRE((s = socket(PF_INET, SOCK_DGRAM, 0)) >= 0); + ATF_REQUIRE(bind(s, (struct sockaddr *)&sin, sizeof(sin)) == 0); + shutdown_thread(s); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, unblock); + + return (atf_no_error()); +}