From: mvs Date: Tue, 14 Dec 2021 16:12:48 +0000 (+0000) Subject: Add new 'unsopassgc' test. This test tries to beak unix(4) sockets garbage X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=6767823d56342a3900d5027f912282c867226f74;p=openbsd Add new 'unsopassgc' test. This test tries to beak unix(4) sockets garbage collector and make it to clean `so_rcv' buffer of alive socket. Successful breakage should produce kernel panic. ok bluhm@ mpi@ --- diff --git a/regress/sys/kern/unixsockets/Makefile b/regress/sys/kern/unixsockets/Makefile index c39225c2ad5..6d1847e3717 100644 --- a/regress/sys/kern/unixsockets/Makefile +++ b/regress/sys/kern/unixsockets/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.7 2021/12/14 15:57:57 mvs Exp $ +# $OpenBSD: Makefile,v 1.8 2021/12/14 16:12:48 mvs Exp $ # Copyright (c) 2021 Makkoveev Vitaliy # @@ -30,6 +30,9 @@ LDADD_unfdpassfail = -lpthread PROGS += unsendrecvthr LDADD_unsendrecvthr = -lpthread +PROGS += unsopassgc +LDADD_unsopassgc = -lpthread + CLEANFILES += *.socket .include diff --git a/regress/sys/kern/unixsockets/unsopassgc.c b/regress/sys/kern/unixsockets/unsopassgc.c new file mode 100644 index 00000000000..f67ad9f5c9f --- /dev/null +++ b/regress/sys/kern/unixsockets/unsopassgc.c @@ -0,0 +1,291 @@ +/* $OpenBSD: unsopassgc.c,v 1.1 2021/12/14 16:12:48 mvs Exp $ */ + +/* + * Copyright (c) 2021 Vitaliy Makkoveev + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Try to beak unix(4) sockets garbage collector and make it to clean + * `so_rcv' buffer of alive socket. Successful breakage should produce + * kernel panic. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static pthread_mutex_t therr_mtx = PTHREAD_MUTEX_INITIALIZER; + +static void +therr(int eval, const char *fmt, ...) +{ + va_list ap; + + pthread_mutex_lock(&therr_mtx); + + va_start(ap, fmt); + verr(eval, fmt, ap); + va_end(ap); +} + +static void +therrx(int eval, const char *fmt, ...) +{ + va_list ap; + + pthread_mutex_lock(&therr_mtx); + + va_start(ap, fmt); + verrx(eval, fmt, ap); + va_end(ap); +} + +static void +therrc(int eval, int code, const char *fmt, ...) +{ + va_list ap; + + pthread_mutex_lock(&therr_mtx); + + va_start(ap, fmt); + verrc(eval, code, fmt, ap); + va_end(ap); +} + +#define PASSFD_NUM (4) + +union msg_control { + struct cmsghdr cmsgh; + char control[CMSG_SPACE(sizeof(int) * PASSFD_NUM)]; +}; + +static struct thr_pass_arg { + int s[2]; + int passfd; +} *thr_pass_args; + +static struct thr_gc_arg { + int passfd; +} *thr_gc_arg; + +static void * +thr_send(void *arg) +{ + union msg_control msg_control; + int iov_buf; + struct iovec iov; + struct msghdr msgh; + struct cmsghdr *cmsgh; + int *s = ((struct thr_pass_arg *)arg)->s; + int passfd = ((struct thr_pass_arg *)arg)->passfd; + + while (1) { + iov_buf = 0; + iov.iov_base = &iov_buf; + iov.iov_len = sizeof(iov_buf); + msgh.msg_control = msg_control.control; + msgh.msg_controllen = sizeof(msg_control.control); + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + cmsgh = CMSG_FIRSTHDR(&msgh); + cmsgh->cmsg_len = CMSG_LEN(sizeof(int) * PASSFD_NUM); + cmsgh->cmsg_level = SOL_SOCKET; + cmsgh->cmsg_type = SCM_RIGHTS; + *((int *)CMSG_DATA(cmsgh) + 0) = s[0]; + *((int *)CMSG_DATA(cmsgh) + 1) = s[1]; + *((int *)CMSG_DATA(cmsgh) + 2) = passfd; + *((int *)CMSG_DATA(cmsgh) + 3) = passfd; + + if (sendmsg(s[0], &msgh, 0) < 0) { + switch (errno) { + case EMFILE: + case ENOBUFS: + break; + default: + therr(1, "sendmsg"); + } + } + } + + return NULL; +} + +static void * +thr_recv(void *arg) +{ + union msg_control msg_control; + int iov_buf; + struct iovec iov; + struct msghdr msgh; + struct cmsghdr *cmsgh; + int i, fd; + int *s = ((struct thr_pass_arg *)arg)->s; + + while (1) { + msg_control.cmsgh.cmsg_level = SOL_SOCKET; + msg_control.cmsgh.cmsg_type = SCM_RIGHTS; + msg_control.cmsgh.cmsg_len = + CMSG_LEN(sizeof(int) * PASSFD_NUM); + + iov.iov_base = &iov_buf; + iov.iov_len = sizeof(iov_buf); + + msgh.msg_control = msg_control.control; + msgh.msg_controllen = sizeof(msg_control.control); + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + if(recvmsg(s[1], &msgh, 0) < 0) + therr(1, "recvmsg"); + + if(!(cmsgh = CMSG_FIRSTHDR(&msgh))) + therrx(1, "bad cmsg header"); + if(cmsgh->cmsg_level != SOL_SOCKET) + therrx(1, "bad cmsg level"); + if(cmsgh->cmsg_type != SCM_RIGHTS) + therrx(1, "bad cmsg type"); + if(cmsgh->cmsg_len != CMSG_LEN(sizeof(fd) * PASSFD_NUM)) + therrx(1, "bad cmsg length"); + + for (i = 0; i < PASSFD_NUM; ++i) { + fd = *((int *)CMSG_DATA(cmsgh) + i); + close(fd); + } + } + + return NULL; +} + +static void * +thr_gc(void *arg) +{ + union msg_control msg_control; + int iov_buf; + struct iovec iov; + struct msghdr msgh; + struct cmsghdr *cmsgh; + int s[2], passfd = ((struct thr_gc_arg *)arg)->passfd; + + while (1) { + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, s) < 0) + therr(1, "socketpair"); + + iov_buf = 0; + iov.iov_base = &iov_buf; + iov.iov_len = sizeof(iov_buf); + msgh.msg_control = msg_control.control; + msgh.msg_controllen = sizeof(msg_control.control); + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + cmsgh = CMSG_FIRSTHDR(&msgh); + cmsgh->cmsg_len = CMSG_LEN(sizeof(int) * PASSFD_NUM); + cmsgh->cmsg_level = SOL_SOCKET; + cmsgh->cmsg_type = SCM_RIGHTS; + *((int *)CMSG_DATA(cmsgh) + 0) = s[0]; + *((int *)CMSG_DATA(cmsgh) + 1) = s[1]; + *((int *)CMSG_DATA(cmsgh) + 2) = passfd; + *((int *)CMSG_DATA(cmsgh) + 3) = passfd; + + if (sendmsg(s[0], &msgh, 0) < 0) { + switch (errno) { + case EMFILE: + case ENOBUFS: + break; + default: + therr(1, "sendmsg"); + } + } + + close(s[0]); + close(s[1]); + } + + return NULL; +} + +int +main(int argc, char *argv[]) +{ + struct timespec testtime = { + .tv_sec = 60, + .tv_nsec = 0, + }; + + int mib[2], ncpu; + size_t len; + + pthread_t thr; + int i, error; + + if (argc == 2 && !strcmp(argv[1], "--infinite")) + testtime.tv_sec = (10 * 365 * 86400); + + mib[0] = CTL_HW; + mib[1] = HW_NCPUONLINE; + len = sizeof(ncpu); + + if (sysctl(mib, 2, &ncpu, &len, NULL, 0) < 0) + err(1, "sysctl"); + if (ncpu <= 0) + errx(1, "Wrong number of CPUs online: %d", ncpu); + + if (!(thr_pass_args = calloc(ncpu, sizeof(*thr_pass_args)))) + err(1, "malloc"); + if (!(thr_gc_arg = malloc(sizeof(*thr_gc_arg)))) + err(1, "malloc"); + + for (i = 0; i < ncpu; ++i) { + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, thr_pass_args[i].s) < 0) + err(1, "socketpair"); + thr_pass_args[i].passfd = thr_pass_args[i].s[0]; + } + + thr_gc_arg->passfd = thr_pass_args[i].s[0]; + + for (i = 0; i < ncpu; ++i) { + error = pthread_create(&thr, NULL, + thr_send, &thr_pass_args[i]); + if (error) + therrc(1, error, "pthread_create"); + error = pthread_create(&thr, NULL, + thr_recv, &thr_pass_args[i]); + if (error) + therrc(1, error, "pthread_create"); + } + + if ((error = pthread_create(&thr, NULL, thr_gc, thr_gc_arg))) + therrc(1, error, "pthread_create"); + + nanosleep(&testtime, NULL); + + return 0; +}