xref: /freebsd/tests/sys/capsicum/ioctls_test.c (revision 6dced2c6358e467ac1dccd99f6f648d4f71957a8)
18ce99bb4SJohn Baldwin /*-
28ce99bb4SJohn Baldwin  * Copyright (c) 2018 John Baldwin <jhb@FreeBSD.org>
38ce99bb4SJohn Baldwin  *
48ce99bb4SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
58ce99bb4SJohn Baldwin  * modification, are permitted provided that the following conditions
68ce99bb4SJohn Baldwin  * are met:
78ce99bb4SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
88ce99bb4SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
98ce99bb4SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
108ce99bb4SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
118ce99bb4SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
128ce99bb4SJohn Baldwin  *
138ce99bb4SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
148ce99bb4SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158ce99bb4SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
168ce99bb4SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
178ce99bb4SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
188ce99bb4SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
198ce99bb4SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
208ce99bb4SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
218ce99bb4SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
228ce99bb4SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
238ce99bb4SJohn Baldwin  * SUCH DAMAGE.
248ce99bb4SJohn Baldwin  */
258ce99bb4SJohn Baldwin 
268ce99bb4SJohn Baldwin #include <sys/capsicum.h>
278ce99bb4SJohn Baldwin #include <sys/filio.h>
288ce99bb4SJohn Baldwin #include <sys/socket.h>
298ce99bb4SJohn Baldwin #include <sys/wait.h>
308ce99bb4SJohn Baldwin #include <netinet/in.h>
318ce99bb4SJohn Baldwin #include <stdio.h>
328ce99bb4SJohn Baldwin #include <stdlib.h>
338ce99bb4SJohn Baldwin #include <unistd.h>
348ce99bb4SJohn Baldwin 
358ce99bb4SJohn Baldwin #include <atf-c.h>
368ce99bb4SJohn Baldwin 
37*08e5c473SOlivier Cochard #include "freebsd_test_suite/macros.h"
38*08e5c473SOlivier Cochard 
398ce99bb4SJohn Baldwin /*
408ce99bb4SJohn Baldwin  * A variant of ATF_REQUIRE that is suitable for use in child
418ce99bb4SJohn Baldwin  * processes.  This only works if the parent process is tripped up by
428ce99bb4SJohn Baldwin  * the early exit and fails some requirement itself.
438ce99bb4SJohn Baldwin  */
448ce99bb4SJohn Baldwin #define	CHILD_REQUIRE(exp) do {						\
458ce99bb4SJohn Baldwin 		if (!(exp))						\
468ce99bb4SJohn Baldwin 			child_fail_require(__FILE__, __LINE__,		\
478ce99bb4SJohn Baldwin 			    #exp " not met");				\
488ce99bb4SJohn Baldwin 	} while (0)
498ce99bb4SJohn Baldwin 
508ce99bb4SJohn Baldwin static __dead2 void
child_fail_require(const char * file,int line,const char * str)518ce99bb4SJohn Baldwin child_fail_require(const char *file, int line, const char *str)
528ce99bb4SJohn Baldwin {
538ce99bb4SJohn Baldwin 	char buf[128];
548ce99bb4SJohn Baldwin 
558ce99bb4SJohn Baldwin 	snprintf(buf, sizeof(buf), "%s:%d: %s\n", file, line, str);
568ce99bb4SJohn Baldwin 	write(2, buf, strlen(buf));
578ce99bb4SJohn Baldwin 	_exit(32);
588ce99bb4SJohn Baldwin }
598ce99bb4SJohn Baldwin 
608ce99bb4SJohn Baldwin /*
618ce99bb4SJohn Baldwin  * Exercise the edge case of a custom ioctl list being copied from a
628ce99bb4SJohn Baldwin  * listen socket to an accepted socket.
638ce99bb4SJohn Baldwin  */
648ce99bb4SJohn Baldwin ATF_TC_WITHOUT_HEAD(cap_ioctls__listen_copy);
ATF_TC_BODY(cap_ioctls__listen_copy,tc)658ce99bb4SJohn Baldwin ATF_TC_BODY(cap_ioctls__listen_copy, tc)
668ce99bb4SJohn Baldwin {
678ce99bb4SJohn Baldwin 	struct sockaddr_in sin;
688ce99bb4SJohn Baldwin 	cap_rights_t rights;
698ce99bb4SJohn Baldwin 	u_long cmds[] = { FIONREAD };
708ce99bb4SJohn Baldwin 	socklen_t len;
718ce99bb4SJohn Baldwin 	pid_t pid;
728ce99bb4SJohn Baldwin 	char dummy;
738ce99bb4SJohn Baldwin 	int s[2], status;
748ce99bb4SJohn Baldwin 
75*08e5c473SOlivier Cochard 	ATF_REQUIRE_FEATURE("security_capabilities");
76*08e5c473SOlivier Cochard 
778ce99bb4SJohn Baldwin 	s[0] = socket(AF_INET, SOCK_STREAM, 0);
788ce99bb4SJohn Baldwin 	ATF_REQUIRE(s[0] > 0);
798ce99bb4SJohn Baldwin 
808ce99bb4SJohn Baldwin 	/* Bind to an arbitrary unused port. */
818ce99bb4SJohn Baldwin 	memset(&sin, 0, sizeof(sin));
828ce99bb4SJohn Baldwin 	sin.sin_len = sizeof(sin);
838ce99bb4SJohn Baldwin 	sin.sin_family = AF_INET;
848ce99bb4SJohn Baldwin 	sin.sin_port = 0;
858ce99bb4SJohn Baldwin 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
868ce99bb4SJohn Baldwin 	ATF_REQUIRE(bind(s[0], (struct sockaddr *)&sin, sizeof(sin)) == 0);
878ce99bb4SJohn Baldwin 
888ce99bb4SJohn Baldwin 	CHILD_REQUIRE(listen(s[0], 1) == 0);
898ce99bb4SJohn Baldwin 
908ce99bb4SJohn Baldwin 	len = sizeof(sin);
918ce99bb4SJohn Baldwin 	ATF_REQUIRE(getsockname(s[0], (struct sockaddr *)&sin, &len) == 0);
928ce99bb4SJohn Baldwin 	ATF_REQUIRE(len == sizeof(sin));
938ce99bb4SJohn Baldwin 
948ce99bb4SJohn Baldwin 	cap_rights_init(&rights, CAP_ACCEPT, CAP_IOCTL);
958ce99bb4SJohn Baldwin 	ATF_REQUIRE(cap_rights_limit(s[0], &rights) == 0);
968ce99bb4SJohn Baldwin 	ATF_REQUIRE(cap_ioctls_limit(s[0], cmds, nitems(cmds)) == 0);
978ce99bb4SJohn Baldwin 
988ce99bb4SJohn Baldwin 	pid = fork();
998ce99bb4SJohn Baldwin 	if (pid == 0) {
1008ce99bb4SJohn Baldwin 		s[1] = accept(s[0], NULL, NULL);
1018ce99bb4SJohn Baldwin 		CHILD_REQUIRE(s[1] > 0);
1028ce99bb4SJohn Baldwin 
1038ce99bb4SJohn Baldwin 		/* Close both sockets during exit(). */
1048ce99bb4SJohn Baldwin 		exit(0);
1058ce99bb4SJohn Baldwin 	}
1068ce99bb4SJohn Baldwin 
1078ce99bb4SJohn Baldwin 	ATF_REQUIRE(pid > 0);
1088ce99bb4SJohn Baldwin 
1098ce99bb4SJohn Baldwin 	ATF_REQUIRE(close(s[0]) == 0);
1108ce99bb4SJohn Baldwin 	s[1] = socket(AF_INET, SOCK_STREAM, 0);
1118ce99bb4SJohn Baldwin 	ATF_REQUIRE(s[1] > 0);
1128ce99bb4SJohn Baldwin 	ATF_REQUIRE(connect(s[1], (struct sockaddr *)&sin, sizeof(sin)) == 0);
1138ce99bb4SJohn Baldwin 	ATF_REQUIRE(read(s[1], &dummy, sizeof(dummy)) == 0);
1148ce99bb4SJohn Baldwin 	ATF_REQUIRE(close(s[1]) == 0);
1158ce99bb4SJohn Baldwin 
1168ce99bb4SJohn Baldwin 	ATF_REQUIRE(wait(&status) == pid);
1178ce99bb4SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
1188ce99bb4SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 0);
1198ce99bb4SJohn Baldwin }
1208ce99bb4SJohn Baldwin 
ATF_TP_ADD_TCS(tp)1218ce99bb4SJohn Baldwin ATF_TP_ADD_TCS(tp)
1228ce99bb4SJohn Baldwin {
1238ce99bb4SJohn Baldwin 
1248ce99bb4SJohn Baldwin 	ATF_TP_ADD_TC(tp, cap_ioctls__listen_copy);
1258ce99bb4SJohn Baldwin 
1268ce99bb4SJohn Baldwin 	return (atf_no_error());
1278ce99bb4SJohn Baldwin }
128