diff options
Diffstat (limited to 'regress/sys')
-rw-r--r-- | regress/sys/kern/pledge/sendrecvfd/Makefile | 72 | ||||
-rw-r--r-- | regress/sys/kern/pledge/sendrecvfd/sendrecvfd.c | 277 |
2 files changed, 349 insertions, 0 deletions
diff --git a/regress/sys/kern/pledge/sendrecvfd/Makefile b/regress/sys/kern/pledge/sendrecvfd/Makefile new file mode 100644 index 00000000000..e9b79bec83e --- /dev/null +++ b/regress/sys/kern/pledge/sendrecvfd/Makefile @@ -0,0 +1,72 @@ +# $OpenBSD: Makefile,v 1.1 2017/02/22 11:30:00 tb Exp $ +CFLAGS+= -Wall -Werror + +testtype= nopledge sendfd recvfd nosendfd norecvfd +vnodetype= VREG VDIR VBLK VCHR VLNK VSOCK VFIFO + +PASS_TARGETS= test-nopledge-VREG \ + test-nopledge-VDIR \ + test-nopledge-VBLK \ + test-nopledge-VCHR \ + test-nopledge-VLNK \ + test-nopledge-VSOCK \ + test-nopledge-VFIFO \ + \ + test-sendfd-VREG \ + test-sendfd-VBLK \ + test-sendfd-VCHR \ + test-sendfd-VLNK \ + test-sendfd-VSOCK \ + test-sendfd-VFIFO \ + \ + test-recvfd-VREG \ + test-recvfd-VBLK \ + test-recvfd-VCHR \ + test-recvfd-VLNK \ + test-recvfd-VSOCK \ + test-recvfd-VFIFO + +FAIL_TARGETS= test-sendfd-VDIR \ + test-recvfd-VDIR \ + \ + test-nosendfd-VREG \ + test-nosendfd-VDIR \ + test-nosendfd-VBLK \ + test-nosendfd-VCHR \ + test-nosendfd-VLNK \ + test-nosendfd-VSOCK \ + test-nosendfd-VFIFO \ + \ + test-norecvfd-VREG \ + test-norecvfd-VDIR \ + test-norecvfd-VBLK \ + test-norecvfd-VCHR \ + test-norecvfd-VLNK \ + test-norecvfd-VSOCK \ + test-norecvfd-VFIFO + +CLEANFILES+= sendrecvfd + +.for _test in ${testtype} +. for _vnode in ${vnodetype} +REGRESS_TARGETS+= test-${_test}-${_vnode} + +. if ${PASS_TARGETS:Mtest-${_test}-${_vnode}} +test-${_test}-${_vnode}: sendrecvfd + @echo test-${_test}-${_vnode}: expected PASS + @./sendrecvfd ${_test} ${_vnode} + +. elif ${FAIL_TARGETS:Mtest-${_test}-${_vnode}} +test-${_test}-${_vnode}: sendrecvfd + @echo test-${_test}-${_vnode}: expected FAIL + @if ./sendrecvfd ${_test} ${_vnode}; then false; else true; fi + +. else +test-${_test}-${_vnode}: + @echo "ERROR: test-${_test}-${_vnode} is missing" + @false +. endif +. endfor +.endfor + +.include <bsd.regress.mk> diff --git a/regress/sys/kern/pledge/sendrecvfd/sendrecvfd.c b/regress/sys/kern/pledge/sendrecvfd/sendrecvfd.c new file mode 100644 index 00000000000..80068cc9158 --- /dev/null +++ b/regress/sys/kern/pledge/sendrecvfd/sendrecvfd.c @@ -0,0 +1,277 @@ +/* $OpenBSD: sendrecvfd.c,v 1.1 2017/02/22 11:30:00 tb Exp $ */ +/* + * Copyright (c) 2017 Sebastien Marie <semarie@online.fr> + * + * 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. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +enum testtype { + nopledge, + sendfd, + recvfd, + nosendfd, + norecvfd, +}; + +static void do_receiver(enum testtype type, int sock); +static void do_sender(enum testtype type, int sock, int fd); +__dead static void usage(); + + +static void +do_receiver(enum testtype type, int sock) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + /* pledge */ + switch(type) { + case recvfd: + if (pledge("stdio recvfd", NULL) == -1) + err(EXIT_FAILURE, "receiver: pledge"); + break; + + case norecvfd: + if (pledge("stdio", NULL) == -1) + err(EXIT_FAILURE, "receiver: pledge"); + break; + + default: + /* no pledge */ + break; + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + if (recvmsg(sock, &msg, 0) == -1) + err(EXIT_FAILURE, "receiver: recvmsg"); + + if ((msg.msg_flags & MSG_TRUNC) || (msg.msg_flags & MSG_CTRUNC)) + errx(EXIT_FAILURE, "receiver: control message truncated"); + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && + cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + + int fd = *(int *)CMSG_DATA(cmsg); + struct stat sb; + + /* test received fd */ + if (fstat(fd, &sb) == -1) + err(EXIT_FAILURE, "receiver: fstat"); + } + } +} + +static void +do_sender(enum testtype type, int sock, int fd) +{ + struct msghdr msg; + struct cmsghdr *cmsg; + union { + struct cmsghdr hdr; + unsigned char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + + /* pledge */ + switch (type) { + case sendfd: + if (pledge("stdio sendfd", NULL) == -1) + err(EXIT_FAILURE, "sender: pledge"); + break; + + case nosendfd: + if (pledge("stdio", NULL) == -1) + err(EXIT_FAILURE, "sender: pledge"); + break; + + default: + /* no pledge */ + break; + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; + + if (sendmsg(sock, &msg, 0) == -1) + err(EXIT_FAILURE, "sender: sendmsg"); +} + +__dead static void +usage() +{ + printf("usage: %s testtype vnodetype\n", getprogname()); + printf(" testtype = nopledge sendfd recvfd nosendfd norecvfd\n"); + printf(" vnodetype = VREG VDIR VBLK VCHAR VLNK VSOCK VFIFO\n"); + exit(EXIT_FAILURE); +} + +int +main(int argc, char *argv[]) +{ + enum testtype type; + int fd; + int sv[2], status; + pid_t child; + + /* + * parse arguments + */ + + if (argc != 3) + usage(); + + if (strcmp(argv[1], "nopledge") == 0 ) { + /* test sendfd/recvfd without pledge */ + type = nopledge; + + } else if (strcmp(argv[1], "sendfd") == 0) { + /* test sendfd process with "stdio sendfd" */ + type = sendfd; + + } else if (strcmp(argv[1], "recvfd") == 0) { + /* test recvfd process with "stdio recvfd" */ + type = recvfd; + + } else if (strcmp(argv[1], "nosendfd") == 0) { + /* test sendfd process with "stdio" (without "sendfd") */ + type = nosendfd; + + } else if (strcmp(argv[1], "norecvfd") == 0) { + /* test recvfd process with "stdio" (without "recvfd") */ + type = norecvfd; + + } else + usage(); + + /* open a file descriptor according to vnodetype requested */ + if (strcmp(argv[2], "VREG") == 0) { + if ((fd = open("/etc/passwd", O_RDONLY)) == -1) + err(EXIT_FAILURE, "open: VREG: /etc/passwd"); + + } else if (strcmp(argv[2], "VDIR") == 0) { + if ((fd = open("/dev", O_RDONLY)) == -1) + err(EXIT_FAILURE, "open: VDIR: /dev"); + + } else if (strcmp(argv[2], "VBLK") == 0) { + if ((fd = open("/dev/vnd0c", O_RDONLY)) == -1) + err(EXIT_FAILURE, "open: VBLK: /dev/vnd0c"); + + } else if (strcmp(argv[2], "VCHR") == 0) { + if ((fd = open("/dev/null", O_RDONLY)) == -1) + err(EXIT_FAILURE, "open: VCHR: /dev/null"); + + } else if (strcmp(argv[2], "VLNK") == 0) { + if ((fd = open("/etc/termcap", O_RDONLY)) == -1) + err(EXIT_FAILURE, "open: VCHR: /etc/termcap"); + + } else if (strcmp(argv[2], "VSOCK") == 0) { + /* create socket */ + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + err(EXIT_FAILURE, "socket: VSOCK"); + + } else if (strcmp(argv[2], "VFIFO") == 0) { + /* unlink possibly existing file (from previous run) */ + unlink("fifo"); + + /* create a new named fifo */ + if (mkfifo("fifo", 0600) == -1) + err(EXIT_FAILURE, "mkfifo: VFIFO"); + + /* open it */ + if ((fd = open("fifo", O_RDONLY|O_NONBLOCK)) == -1) + err(EXIT_FAILURE, "open: VFIFO: fifo"); + + /* unlink the file now */ + unlink("fifo"); + } else + usage(); + + + /* + * do test + */ + + /* communication socket */ + if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, sv) == -1) + err(EXIT_FAILURE, "socketpair"); + + /* create two procs and pass fd from one to another */ + switch (child = fork()) { + case -1: /* error */ + err(EXIT_FAILURE, "fork"); + + case 0: /* child: receiver */ + close(fd); + close(sv[0]); + + do_receiver(type, sv[1]); + _exit(EXIT_SUCCESS); + + default: /* parent: sender */ + close(sv[1]); + + do_sender(type, sv[0], fd); + + /* wait for child */ + while (waitpid(child, &status, 0) < 0) { + if (errno == EAGAIN) + continue; + + err(EXIT_FAILURE, "waitpid"); + } + + if (! WIFEXITED(status)) { + if (WIFSIGNALED(status)) + errx(EXIT_FAILURE, + "child (receiver): WTERMSIG(): %d", + WTERMSIG(status)); + + errx(EXIT_FAILURE, "child (receiver): !WIFEXITED"); + } + + if (WEXITSTATUS(status) != 0) + errx(EXIT_FAILURE, "child(receiver): WEXITSTATUS(): %d", + WEXITSTATUS(status)); + + exit(EXIT_SUCCESS); + } +} |