Path: blob/main/tools/regression/capsicum/syscalls/cap_ioctls_limit.c
48255 views
/*-1* Copyright (c) 2012 The FreeBSD Foundation2*3* This software was developed by Pawel Jakub Dawidek under sponsorship from4* the FreeBSD Foundation.5*6* Redistribution and use in source and binary forms, with or without7* modification, are permitted provided that the following conditions8* are met:9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11* 2. Redistributions in binary form must reproduce the above copyright12* notice, this list of conditions and the following disclaimer in the13* documentation and/or other materials provided with the distribution.14*15* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND16* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE17* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE18* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE19* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL20* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS21* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)22* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT23* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY24* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF25* SUCH DAMAGE.26*/2728#include <sys/param.h>29#include <sys/capsicum.h>30#include <sys/ioctl.h>31#include <sys/procdesc.h>32#include <sys/socket.h>33#include <sys/wait.h>3435#include <err.h>36#include <errno.h>37#include <limits.h>38#include <stdio.h>39#include <stdlib.h>40#include <unistd.h>4142#include "misc.h"4344static void45ioctl_tests_0(int fd)46{47unsigned long cmds[2];4849CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);5051CHECK(fcntl(fd, F_GETFD) == 0);52CHECK(ioctl(fd, FIOCLEX) == 0);53CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);54CHECK(ioctl(fd, FIONCLEX) == 0);55CHECK(fcntl(fd, F_GETFD) == 0);5657cmds[0] = FIOCLEX;58cmds[1] = FIONCLEX;59CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);60cmds[0] = cmds[1] = 0;61CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));62CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||63(cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));64cmds[0] = FIOCLEX;65cmds[1] = FIONCLEX;66CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);67cmds[0] = cmds[1] = 0;68CHECK(cap_ioctls_get(fd, cmds, 1) == nitems(cmds));69CHECK(cmds[0] == FIOCLEX || cmds[0] == FIONCLEX);70CHECK(cmds[1] == 0);7172CHECK(fcntl(fd, F_GETFD) == 0);73CHECK(ioctl(fd, FIOCLEX) == 0);74CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);75CHECK(ioctl(fd, FIONCLEX) == 0);76CHECK(fcntl(fd, F_GETFD) == 0);7778cmds[0] = FIOCLEX;79CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);80cmds[0] = cmds[1] = 0;81CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);82CHECK(cmds[0] == FIOCLEX);83cmds[0] = FIOCLEX;84cmds[1] = FIONCLEX;85errno = 0;86CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);87CHECK(errno == ENOTCAPABLE);88cmds[0] = cmds[1] = 0;89CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);90CHECK(cmds[0] == FIOCLEX);9192CHECK(fcntl(fd, F_GETFD) == 0);93CHECK(ioctl(fd, FIOCLEX) == 0);94CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);95errno = 0;96CHECK(ioctl(fd, FIONCLEX) == -1);97CHECK(errno == ENOTCAPABLE);98CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);99CHECK(fcntl(fd, F_SETFD, 0) == 0);100CHECK(fcntl(fd, F_GETFD) == 0);101102CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);103CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);104cmds[0] = FIOCLEX;105errno = 0;106CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);107CHECK(errno == ENOTCAPABLE);108CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);109110CHECK(fcntl(fd, F_GETFD) == 0);111errno = 0;112CHECK(ioctl(fd, FIOCLEX) == -1);113CHECK(errno == ENOTCAPABLE);114CHECK(fcntl(fd, F_GETFD) == 0);115CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);116CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);117errno = 0;118CHECK(ioctl(fd, FIONCLEX) == -1);119CHECK(errno == ENOTCAPABLE);120CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);121CHECK(fcntl(fd, F_SETFD, 0) == 0);122CHECK(fcntl(fd, F_GETFD) == 0);123}124125static void126ioctl_tests_1(int fd)127{128unsigned long cmds[2];129cap_rights_t rights;130131cmds[0] = FIOCLEX;132CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);133cmds[0] = cmds[1] = 0;134CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);135CHECK(cmds[0] == FIOCLEX);136CHECK(cmds[1] == 0);137138CAP_ALL(&rights);139cap_rights_clear(&rights, CAP_IOCTL);140141CHECK(cap_rights_limit(fd, &rights) == 0);142CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);143144cmds[0] = FIOCLEX;145cmds[1] = FIONCLEX;146errno = 0;147CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);148CHECK(errno == ENOTCAPABLE);149CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);150cmds[0] = FIOCLEX;151errno = 0;152CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);153CHECK(errno == ENOTCAPABLE);154CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);155156CHECK(fcntl(fd, F_GETFD) == 0);157errno = 0;158CHECK(ioctl(fd, FIOCLEX) == -1);159CHECK(errno == ENOTCAPABLE);160CHECK(fcntl(fd, F_GETFD) == 0);161CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);162CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);163errno = 0;164CHECK(ioctl(fd, FIONCLEX) == -1);165CHECK(errno == ENOTCAPABLE);166CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);167CHECK(fcntl(fd, F_SETFD, 0) == 0);168CHECK(fcntl(fd, F_GETFD) == 0);169}170171static void172ioctl_tests_2(int fd)173{174unsigned long cmds[2];175cap_rights_t rights;176177CAP_ALL(&rights);178cap_rights_clear(&rights, CAP_IOCTL);179180CHECK(cap_rights_limit(fd, &rights) == 0);181CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);182183cmds[0] = FIOCLEX;184cmds[1] = FIONCLEX;185errno = 0;186CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == -1);187CHECK(errno == ENOTCAPABLE);188CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);189cmds[0] = FIOCLEX;190errno = 0;191CHECK(cap_ioctls_limit(fd, cmds, 1) == -1);192CHECK(errno == ENOTCAPABLE);193CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);194195CHECK(fcntl(fd, F_GETFD) == 0);196errno = 0;197CHECK(ioctl(fd, FIOCLEX) == -1);198CHECK(errno == ENOTCAPABLE);199CHECK(fcntl(fd, F_GETFD) == 0);200CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);201CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);202errno = 0;203CHECK(ioctl(fd, FIONCLEX) == -1);204CHECK(errno == ENOTCAPABLE);205CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);206CHECK(fcntl(fd, F_SETFD, 0) == 0);207CHECK(fcntl(fd, F_GETFD) == 0);208}209210static void211ioctl_tests_send_0(int sock)212{213unsigned long cmds[2];214int fd;215216CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);217CHECK(descriptor_send(sock, fd) == 0);218CHECK(close(fd) == 0);219220CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);221cmds[0] = FIOCLEX;222cmds[1] = FIONCLEX;223CHECK(cap_ioctls_limit(fd, cmds, nitems(cmds)) == 0);224CHECK(descriptor_send(sock, fd) == 0);225CHECK(close(fd) == 0);226227CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);228cmds[0] = FIOCLEX;229CHECK(cap_ioctls_limit(fd, cmds, 1) == 0);230CHECK(descriptor_send(sock, fd) == 0);231CHECK(close(fd) == 0);232233CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);234CHECK(cap_ioctls_limit(fd, NULL, 0) == 0);235CHECK(descriptor_send(sock, fd) == 0);236CHECK(close(fd) == 0);237}238239static void240ioctl_tests_recv_0(int sock)241{242unsigned long cmds[2];243int fd;244245CHECK(descriptor_recv(sock, &fd) == 0);246247CHECK(cap_ioctls_get(fd, NULL, 0) == CAP_IOCTLS_ALL);248249CHECK(fcntl(fd, F_GETFD) == 0);250CHECK(ioctl(fd, FIOCLEX) == 0);251CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);252CHECK(ioctl(fd, FIONCLEX) == 0);253CHECK(fcntl(fd, F_GETFD) == 0);254255CHECK(close(fd) == 0);256257CHECK(descriptor_recv(sock, &fd) == 0);258259cmds[0] = cmds[1] = 0;260CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == nitems(cmds));261CHECK((cmds[0] == FIOCLEX && cmds[1] == FIONCLEX) ||262(cmds[0] == FIONCLEX && cmds[1] == FIOCLEX));263264CHECK(fcntl(fd, F_GETFD) == 0);265CHECK(ioctl(fd, FIOCLEX) == 0);266CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);267CHECK(ioctl(fd, FIONCLEX) == 0);268CHECK(fcntl(fd, F_GETFD) == 0);269270CHECK(close(fd) == 0);271272CHECK(descriptor_recv(sock, &fd) == 0);273274cmds[0] = cmds[1] = 0;275CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 1);276CHECK(cmds[0] == FIOCLEX);277278CHECK(fcntl(fd, F_GETFD) == 0);279CHECK(ioctl(fd, FIOCLEX) == 0);280CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);281errno = 0;282CHECK(ioctl(fd, FIONCLEX) == -1);283CHECK(errno == ENOTCAPABLE);284CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);285CHECK(fcntl(fd, F_SETFD, 0) == 0);286CHECK(fcntl(fd, F_GETFD) == 0);287288CHECK(close(fd) == 0);289290CHECK(descriptor_recv(sock, &fd) == 0);291292CHECK(cap_ioctls_get(fd, cmds, nitems(cmds)) == 0);293294CHECK(fcntl(fd, F_GETFD) == 0);295errno = 0;296CHECK(ioctl(fd, FIOCLEX) == -1);297CHECK(errno == ENOTCAPABLE);298CHECK(fcntl(fd, F_GETFD) == 0);299CHECK(fcntl(fd, F_SETFD, FD_CLOEXEC) == 0);300CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);301errno = 0;302CHECK(ioctl(fd, FIONCLEX) == -1);303CHECK(errno == ENOTCAPABLE);304CHECK(fcntl(fd, F_GETFD) == FD_CLOEXEC);305CHECK(fcntl(fd, F_SETFD, 0) == 0);306CHECK(fcntl(fd, F_GETFD) == 0);307308CHECK(close(fd) == 0);309}310311int312main(void)313{314int fd, pfd, sp[2];315pid_t pid;316317printf("1..607\n");318319CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);320ioctl_tests_0(fd);321CHECK(close(fd) == 0);322323CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);324ioctl_tests_1(fd);325CHECK(close(fd) == 0);326327CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);328ioctl_tests_2(fd);329CHECK(close(fd) == 0);330331/* Child inherits descriptor and operates on it first. */332CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);333pid = fork();334switch (pid) {335case -1:336err(1, "fork() failed");337case 0:338ioctl_tests_0(fd);339CHECK(close(fd) == 0);340exit(0);341default:342if (waitpid(pid, NULL, 0) == -1)343err(1, "waitpid() failed");344ioctl_tests_0(fd);345}346CHECK(close(fd) == 0);347348/* Child inherits descriptor, but operates on it after parent. */349CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);350pid = fork();351switch (pid) {352case -1:353err(1, "fork() failed");354case 0:355sleep(1);356ioctl_tests_0(fd);357CHECK(close(fd) == 0);358exit(0);359default:360ioctl_tests_0(fd);361if (waitpid(pid, NULL, 0) == -1)362err(1, "waitpid() failed");363}364CHECK(close(fd) == 0);365366/* Child inherits descriptor and operates on it first. */367CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);368pid = pdfork(&pfd, 0);369switch (pid) {370case -1:371err(1, "pdfork() failed");372case 0:373ioctl_tests_1(fd);374exit(0);375default:376if (pdwait(pfd) == -1)377err(1, "pdwait() failed");378close(pfd);379ioctl_tests_1(fd);380}381CHECK(close(fd) == 0);382383/* Child inherits descriptor, but operates on it after parent. */384CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);385pid = pdfork(&pfd, 0);386switch (pid) {387case -1:388err(1, "pdfork() failed");389case 0:390sleep(1);391ioctl_tests_1(fd);392exit(0);393default:394ioctl_tests_1(fd);395if (pdwait(pfd) == -1)396err(1, "pdwait() failed");397close(pfd);398}399CHECK(close(fd) == 0);400401/* Child inherits descriptor and operates on it first. */402CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);403pid = fork();404switch (pid) {405case -1:406err(1, "fork() failed");407case 0:408ioctl_tests_2(fd);409exit(0);410default:411if (waitpid(pid, NULL, 0) == -1)412err(1, "waitpid() failed");413ioctl_tests_2(fd);414}415CHECK(close(fd) == 0);416417/* Child inherits descriptor, but operates on it after parent. */418CHECK((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0);419pid = fork();420switch (pid) {421case -1:422err(1, "fork() failed");423case 0:424sleep(1);425ioctl_tests_2(fd);426exit(0);427default:428ioctl_tests_2(fd);429if (waitpid(pid, NULL, 0) == -1)430err(1, "waitpid() failed");431}432CHECK(close(fd) == 0);433434/* Send descriptors from parent to child. */435CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);436CHECK((pid = fork()) >= 0);437if (pid == 0) {438CHECK(close(sp[0]) == 0);439ioctl_tests_recv_0(sp[1]);440CHECK(close(sp[1]) == 0);441exit(0);442} else {443CHECK(close(sp[1]) == 0);444ioctl_tests_send_0(sp[0]);445CHECK(waitpid(pid, NULL, 0) == pid);446CHECK(close(sp[0]) == 0);447}448449/* Send descriptors from child to parent. */450CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sp) == 0);451CHECK((pid = fork()) >= 0);452if (pid == 0) {453CHECK(close(sp[0]) == 0);454ioctl_tests_send_0(sp[1]);455CHECK(close(sp[1]) == 0);456exit(0);457} else {458CHECK(close(sp[1]) == 0);459ioctl_tests_recv_0(sp[0]);460CHECK(waitpid(pid, NULL, 0) == pid);461CHECK(close(sp[0]) == 0);462}463464exit(0);465}466467468