summaryrefslogtreecommitdiff
path: root/regress/sys
diff options
context:
space:
mode:
Diffstat (limited to 'regress/sys')
-rw-r--r--regress/sys/kern/pledge/sendrecvfd/Makefile72
-rw-r--r--regress/sys/kern/pledge/sendrecvfd/sendrecvfd.c277
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);
+ }
+}