xref: /freebsd/tests/sys/vfs/lookup_cap_dotdot.c (revision 6dced2c6)
19f0136cbSConrad Meyer /*-
29f0136cbSConrad Meyer  * Copyright (c) 2016 Ed Maste <emaste@FreeBSD.org>
39f0136cbSConrad Meyer  * Copyright (c) 2016 Conrad Meyer <cem@FreeBSD.org>
49f0136cbSConrad Meyer  *
59f0136cbSConrad Meyer  * Redistribution and use in source and binary forms, with or without
69f0136cbSConrad Meyer  * modification, are permitted provided that the following conditions
79f0136cbSConrad Meyer  * are met:
89f0136cbSConrad Meyer  * 1. Redistributions of source code must retain the above copyright
99f0136cbSConrad Meyer  *    notice, this list of conditions and the following disclaimer.
109f0136cbSConrad Meyer  * 2. Redistributions in binary form must reproduce the above copyright
119f0136cbSConrad Meyer  *    notice, this list of conditions and the following disclaimer in the
129f0136cbSConrad Meyer  *    documentation and/or other materials provided with the distribution.
139f0136cbSConrad Meyer  *
149f0136cbSConrad Meyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
159f0136cbSConrad Meyer  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
169f0136cbSConrad Meyer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
179f0136cbSConrad Meyer  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
189f0136cbSConrad Meyer  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199f0136cbSConrad Meyer  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
209f0136cbSConrad Meyer  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
219f0136cbSConrad Meyer  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
229f0136cbSConrad Meyer  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
239f0136cbSConrad Meyer  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
249f0136cbSConrad Meyer  * SUCH DAMAGE.
259f0136cbSConrad Meyer  */
269f0136cbSConrad Meyer 
279f0136cbSConrad Meyer #include <sys/param.h>
289f0136cbSConrad Meyer #include <sys/capsicum.h>
299f0136cbSConrad Meyer #include <sys/sysctl.h>
309f0136cbSConrad Meyer #include <sys/stat.h>
319f0136cbSConrad Meyer 
329f0136cbSConrad Meyer #include <atf-c.h>
339f0136cbSConrad Meyer #include <errno.h>
349f0136cbSConrad Meyer #include <stdlib.h>
359f0136cbSConrad Meyer #include <string.h>
369f0136cbSConrad Meyer 
379f0136cbSConrad Meyer #include "freebsd_test_suite/macros.h"
389f0136cbSConrad Meyer 
397f9785e8SEnji Cooper static int dirfd = -1;
4047f2efe4SConrad Meyer static char *abspath;
419f0136cbSConrad Meyer 
429f0136cbSConrad Meyer static void
touchat(int _dirfd,const char * name)4302820e5eSEnji Cooper touchat(int _dirfd, const char *name)
449f0136cbSConrad Meyer {
459f0136cbSConrad Meyer 	int fd;
469f0136cbSConrad Meyer 
4702820e5eSEnji Cooper 	ATF_REQUIRE((fd = openat(_dirfd, name, O_CREAT | O_TRUNC | O_WRONLY,
489f0136cbSConrad Meyer 	    0777)) >= 0);
499f0136cbSConrad Meyer 	ATF_REQUIRE(close(fd) == 0);
509f0136cbSConrad Meyer }
519f0136cbSConrad Meyer 
529f0136cbSConrad Meyer static void
prepare_dotdot_tests(void)539f0136cbSConrad Meyer prepare_dotdot_tests(void)
549f0136cbSConrad Meyer {
559f0136cbSConrad Meyer 	char cwd[MAXPATHLEN];
569f0136cbSConrad Meyer 
579f0136cbSConrad Meyer 	ATF_REQUIRE(getcwd(cwd, sizeof(cwd)) != NULL);
589f0136cbSConrad Meyer 	asprintf(&abspath, "%s/testdir/d1/f1", cwd);
599f0136cbSConrad Meyer 
609f0136cbSConrad Meyer 	ATF_REQUIRE(mkdir("testdir", 0777) == 0);
619f0136cbSConrad Meyer 	ATF_REQUIRE((dirfd = open("testdir", O_RDONLY)) >= 0);
629f0136cbSConrad Meyer 
639f0136cbSConrad Meyer 	ATF_REQUIRE(mkdirat(dirfd, "d1", 0777) == 0);
649f0136cbSConrad Meyer 	ATF_REQUIRE(mkdirat(dirfd, "d1/d2", 0777) == 0);
659f0136cbSConrad Meyer 	ATF_REQUIRE(mkdirat(dirfd, "d1/d2/d3", 0777) == 0);
669f0136cbSConrad Meyer 	touchat(dirfd, "d1/f1");
679f0136cbSConrad Meyer 	touchat(dirfd, "d1/d2/f2");
689f0136cbSConrad Meyer 	touchat(dirfd, "d1/d2/d3/f3");
699f0136cbSConrad Meyer 	ATF_REQUIRE(symlinkat("d1/d2/d3", dirfd, "l3") == 0);
709f0136cbSConrad Meyer 	ATF_REQUIRE(symlinkat("../testdir/d1", dirfd, "lup") == 0);
719f0136cbSConrad Meyer 	ATF_REQUIRE(symlinkat("../..", dirfd, "d1/d2/d3/ld1") == 0);
729f0136cbSConrad Meyer 	ATF_REQUIRE(symlinkat("../../f1", dirfd, "d1/d2/d3/lf1") == 0);
739f0136cbSConrad Meyer }
749f0136cbSConrad Meyer 
759f0136cbSConrad Meyer static void
check_capsicum(void)769f0136cbSConrad Meyer check_capsicum(void)
779f0136cbSConrad Meyer {
789f0136cbSConrad Meyer 	ATF_REQUIRE_FEATURE("security_capabilities");
799f0136cbSConrad Meyer 	ATF_REQUIRE_FEATURE("security_capability_mode");
808a271827SMark Johnston 	ATF_REQUIRE_SYSCTL_BOOL("kern.trap_enotcap", false);
819f0136cbSConrad Meyer }
829f0136cbSConrad Meyer 
839f0136cbSConrad Meyer /*
849f0136cbSConrad Meyer  * Positive tests
859f0136cbSConrad Meyer  */
869f0136cbSConrad Meyer ATF_TC(openat__basic_positive);
ATF_TC_HEAD(openat__basic_positive,tc)879f0136cbSConrad Meyer ATF_TC_HEAD(openat__basic_positive, tc)
889f0136cbSConrad Meyer {
899f0136cbSConrad Meyer 	atf_tc_set_md_var(tc, "descr", "Basic positive openat testcases");
909f0136cbSConrad Meyer }
919f0136cbSConrad Meyer 
ATF_TC_BODY(openat__basic_positive,tc)929f0136cbSConrad Meyer ATF_TC_BODY(openat__basic_positive, tc)
939f0136cbSConrad Meyer {
949f0136cbSConrad Meyer 	prepare_dotdot_tests();
959f0136cbSConrad Meyer 
969f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "d1/d2/d3/f3", O_RDONLY) >= 0);
979f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "d1/d2/d3/../../f1", O_RDONLY) >= 0);
989f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/f3", O_RDONLY) >= 0);
999f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/../../f1", O_RDONLY) >= 0);
1009f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "../testdir/d1/f1", O_RDONLY) >= 0);
1019f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "lup/f1", O_RDONLY) >= 0);
1029f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/ld1", O_RDONLY) >= 0);
1039f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/lf1", O_RDONLY) >= 0);
1049f0136cbSConrad Meyer 	ATF_REQUIRE(open(abspath, O_RDONLY) >= 0);
1059f0136cbSConrad Meyer 	ATF_REQUIRE(openat(dirfd, abspath, O_RDONLY) >= 0);
1069f0136cbSConrad Meyer }
1079f0136cbSConrad Meyer 
1089f0136cbSConrad Meyer ATF_TC(lookup_cap_dotdot__basic);
ATF_TC_HEAD(lookup_cap_dotdot__basic,tc)1099f0136cbSConrad Meyer ATF_TC_HEAD(lookup_cap_dotdot__basic, tc)
1109f0136cbSConrad Meyer {
1119f0136cbSConrad Meyer 	atf_tc_set_md_var(tc, "descr",
1129f0136cbSConrad Meyer 	    "Validate cap-mode (testdir)/d1/.. lookup");
1139f0136cbSConrad Meyer }
1149f0136cbSConrad Meyer 
ATF_TC_BODY(lookup_cap_dotdot__basic,tc)1157f9785e8SEnji Cooper ATF_TC_BODY(lookup_cap_dotdot__basic, tc)
1167f9785e8SEnji Cooper {
11747f2efe4SConrad Meyer 	cap_rights_t rights;
1187f9785e8SEnji Cooper 
11947f2efe4SConrad Meyer 	check_capsicum();
12047f2efe4SConrad Meyer 	prepare_dotdot_tests();
12147f2efe4SConrad Meyer 
12247f2efe4SConrad Meyer 	cap_rights_init(&rights, CAP_LOOKUP, CAP_READ);
12347f2efe4SConrad Meyer 	ATF_REQUIRE(cap_rights_limit(dirfd, &rights) >= 0);
12447f2efe4SConrad Meyer 
12547f2efe4SConrad Meyer 	ATF_REQUIRE(cap_enter() >= 0);
12647f2efe4SConrad Meyer 
12747f2efe4SConrad Meyer 	ATF_REQUIRE_MSG(openat(dirfd, "d1/..", O_RDONLY) >= 0, "%s",
12847f2efe4SConrad Meyer 	    strerror(errno));
1299f0136cbSConrad Meyer }
1309f0136cbSConrad Meyer 
1319f0136cbSConrad Meyer ATF_TC(lookup_cap_dotdot__advanced);
ATF_TC_HEAD(lookup_cap_dotdot__advanced,tc)1329f0136cbSConrad Meyer ATF_TC_HEAD(lookup_cap_dotdot__advanced, tc)
1339f0136cbSConrad Meyer {
1349f0136cbSConrad Meyer 	atf_tc_set_md_var(tc, "descr",
1359f0136cbSConrad Meyer 	    "Validate cap-mode (testdir)/d1/.. lookup");
1369f0136cbSConrad Meyer }
1379f0136cbSConrad Meyer 
ATF_TC_BODY(lookup_cap_dotdot__advanced,tc)1387f9785e8SEnji Cooper ATF_TC_BODY(lookup_cap_dotdot__advanced, tc)
1397f9785e8SEnji Cooper {
14047f2efe4SConrad Meyer 	cap_rights_t rights;
1417f9785e8SEnji Cooper 
14247f2efe4SConrad Meyer 	check_capsicum();
14347f2efe4SConrad Meyer 	prepare_dotdot_tests();
14447f2efe4SConrad Meyer 
14547f2efe4SConrad Meyer 	cap_rights_init(&rights, CAP_LOOKUP, CAP_READ);
14647f2efe4SConrad Meyer 	ATF_REQUIRE(cap_rights_limit(dirfd, &rights) >= 0);
14747f2efe4SConrad Meyer 
14847f2efe4SConrad Meyer 	ATF_REQUIRE(cap_enter() >= 0);
14947f2efe4SConrad Meyer 
15047f2efe4SConrad Meyer 	ATF_REQUIRE(openat(dirfd, "d1/d2/d3/../../f1", O_RDONLY) >= 0);
15147f2efe4SConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/../../f1", O_RDONLY) >= 0);
15247f2efe4SConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/ld1", O_RDONLY) >= 0);
15347f2efe4SConrad Meyer 	ATF_REQUIRE(openat(dirfd, "l3/lf1", O_RDONLY) >= 0);
1549f0136cbSConrad Meyer }
1559f0136cbSConrad Meyer 
1569f0136cbSConrad Meyer /*
1579f0136cbSConrad Meyer  * Negative tests
1589f0136cbSConrad Meyer  */
1599f0136cbSConrad Meyer ATF_TC(openat__basic_negative);
ATF_TC_HEAD(openat__basic_negative,tc)1609f0136cbSConrad Meyer ATF_TC_HEAD(openat__basic_negative, tc)
1619f0136cbSConrad Meyer {
1629f0136cbSConrad Meyer 	atf_tc_set_md_var(tc, "descr", "Basic negative openat testcases");
1639f0136cbSConrad Meyer }
1649f0136cbSConrad Meyer 
ATF_TC_BODY(openat__basic_negative,tc)1659f0136cbSConrad Meyer ATF_TC_BODY(openat__basic_negative, tc)
1669f0136cbSConrad Meyer {
1679f0136cbSConrad Meyer 	prepare_dotdot_tests();
1689f0136cbSConrad Meyer 
1699f0136cbSConrad Meyer 	ATF_REQUIRE_ERRNO(ENOENT,
1709f0136cbSConrad Meyer 	    openat(dirfd, "does-not-exist", O_RDONLY) < 0);
1719f0136cbSConrad Meyer 	ATF_REQUIRE_ERRNO(ENOENT,
1729f0136cbSConrad Meyer 	    openat(dirfd, "l3/does-not-exist", O_RDONLY) < 0);
1739f0136cbSConrad Meyer }
1749f0136cbSConrad Meyer 
1759f0136cbSConrad Meyer ATF_TC(capmode__negative);
ATF_TC_HEAD(capmode__negative,tc)1769f0136cbSConrad Meyer ATF_TC_HEAD(capmode__negative, tc)
1779f0136cbSConrad Meyer {
1789f0136cbSConrad Meyer 	atf_tc_set_md_var(tc, "descr", "Negative Capability mode testcases");
1799f0136cbSConrad Meyer }
1809f0136cbSConrad Meyer 
ATF_TC_BODY(capmode__negative,tc)18147f2efe4SConrad Meyer ATF_TC_BODY(capmode__negative, tc)
1829f0136cbSConrad Meyer {
1839f0136cbSConrad Meyer 	int subdirfd;
1849f0136cbSConrad Meyer 
18547f2efe4SConrad Meyer 	check_capsicum();
18647f2efe4SConrad Meyer 	prepare_dotdot_tests();
18747f2efe4SConrad Meyer 
18847f2efe4SConrad Meyer 	ATF_REQUIRE(cap_enter() == 0);
1899f0136cbSConrad Meyer 
1909f0136cbSConrad Meyer 	/* open() not permitted in capability mode */
19147f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ECAPMODE, open("testdir", O_RDONLY) < 0);
1929f0136cbSConrad Meyer 
1939f0136cbSConrad Meyer 	/* AT_FDCWD not permitted in capability mode */
19447f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ECAPMODE, openat(AT_FDCWD, "d1/f1", O_RDONLY) < 0);
1959f0136cbSConrad Meyer 
1969f0136cbSConrad Meyer 	/* Relative path above dirfd not capable */
19747f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dirfd, "..", O_RDONLY) < 0);
19847f2efe4SConrad Meyer 	ATF_REQUIRE((subdirfd = openat(dirfd, "l3", O_RDONLY)) >= 0);
19947f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE,
20047f2efe4SConrad Meyer 	    openat(subdirfd, "../../f1", O_RDONLY) < 0);
2019f0136cbSConrad Meyer 
2029f0136cbSConrad Meyer 	/* Absolute paths not capable */
20347f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dirfd, abspath, O_RDONLY) < 0);
2049f0136cbSConrad Meyer 
2059f0136cbSConrad Meyer 	/* Symlink above dirfd */
20647f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dirfd, "lup/f1", O_RDONLY) < 0);
2079f0136cbSConrad Meyer }
2089f0136cbSConrad Meyer 
2099f0136cbSConrad Meyer ATF_TC(lookup_cap_dotdot__negative);
ATF_TC_HEAD(lookup_cap_dotdot__negative,tc)2109f0136cbSConrad Meyer ATF_TC_HEAD(lookup_cap_dotdot__negative, tc)
2119f0136cbSConrad Meyer {
2129f0136cbSConrad Meyer 	atf_tc_set_md_var(tc, "descr",
2139f0136cbSConrad Meyer 	    "Validate cap-mode (testdir)/.. lookup fails");
2149f0136cbSConrad Meyer }
2159f0136cbSConrad Meyer 
ATF_TC_BODY(lookup_cap_dotdot__negative,tc)2167f9785e8SEnji Cooper ATF_TC_BODY(lookup_cap_dotdot__negative, tc)
2177f9785e8SEnji Cooper {
21847f2efe4SConrad Meyer 	cap_rights_t rights;
2197f9785e8SEnji Cooper 
22047f2efe4SConrad Meyer 	check_capsicum();
22147f2efe4SConrad Meyer 	prepare_dotdot_tests();
22247f2efe4SConrad Meyer 
22347f2efe4SConrad Meyer 	cap_rights_init(&rights, CAP_LOOKUP, CAP_READ);
22447f2efe4SConrad Meyer 	ATF_REQUIRE(cap_rights_limit(dirfd, &rights) >= 0);
22547f2efe4SConrad Meyer 
22647f2efe4SConrad Meyer 	ATF_REQUIRE(cap_enter() >= 0);
22747f2efe4SConrad Meyer 
22847f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dirfd, "..", O_RDONLY) < 0);
22947f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dirfd, "d1/../..", O_RDONLY) < 0);
23047f2efe4SConrad Meyer 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dirfd, "../testdir/d1/f1", O_RDONLY) < 0);
2319f0136cbSConrad Meyer }
2329f0136cbSConrad Meyer 
2332d252934SMark Johnston ATF_TC(lookup_cap_dotdot__root);
ATF_TC_HEAD(lookup_cap_dotdot__root,tc)2342d252934SMark Johnston ATF_TC_HEAD(lookup_cap_dotdot__root, tc)
2352d252934SMark Johnston {
2362d252934SMark Johnston 	atf_tc_set_md_var(tc, "descr", "Validate cap-mode /.. lookup fails");
2372d252934SMark Johnston }
2382d252934SMark Johnston 
ATF_TC_BODY(lookup_cap_dotdot__root,tc)2392d252934SMark Johnston ATF_TC_BODY(lookup_cap_dotdot__root, tc)
2402d252934SMark Johnston {
2412d252934SMark Johnston 	int dfd, dfd2;
2422d252934SMark Johnston 
2432d252934SMark Johnston 	check_capsicum();
2442d252934SMark Johnston 
2452d252934SMark Johnston 	dfd = open("/", O_DIRECTORY);
2462d252934SMark Johnston 	ATF_REQUIRE(dfd >= 0);
2472d252934SMark Johnston 
2482d252934SMark Johnston 	dfd2 = openat(dfd, "..", O_DIRECTORY);
2492d252934SMark Johnston 	ATF_REQUIRE(dfd2 >= 0);
2502d252934SMark Johnston 	ATF_REQUIRE(close(dfd2) == 0);
2512d252934SMark Johnston 
2522d252934SMark Johnston 	ATF_REQUIRE(cap_enter() >= 0);
2532d252934SMark Johnston 
2542d252934SMark Johnston 	dfd2 = openat(dfd, "..", O_DIRECTORY);
2552d252934SMark Johnston 	ATF_REQUIRE_ERRNO(ENOTCAPABLE, openat(dfd, "..", O_DIRECTORY));
2562d252934SMark Johnston }
2572d252934SMark Johnston 
ATF_TP_ADD_TCS(tp)2589f0136cbSConrad Meyer ATF_TP_ADD_TCS(tp)
2599f0136cbSConrad Meyer {
2609f0136cbSConrad Meyer 
2619f0136cbSConrad Meyer 	ATF_TP_ADD_TC(tp, openat__basic_positive);
2629f0136cbSConrad Meyer 	ATF_TP_ADD_TC(tp, openat__basic_negative);
2639f0136cbSConrad Meyer 
2649f0136cbSConrad Meyer 	ATF_TP_ADD_TC(tp, capmode__negative);
2659f0136cbSConrad Meyer 
2669f0136cbSConrad Meyer 	ATF_TP_ADD_TC(tp, lookup_cap_dotdot__basic);
2679f0136cbSConrad Meyer 	ATF_TP_ADD_TC(tp, lookup_cap_dotdot__advanced);
2689f0136cbSConrad Meyer 	ATF_TP_ADD_TC(tp, lookup_cap_dotdot__negative);
2692d252934SMark Johnston 	ATF_TP_ADD_TC(tp, lookup_cap_dotdot__root);
2709f0136cbSConrad Meyer 
2719f0136cbSConrad Meyer 	return (atf_no_error());
2729f0136cbSConrad Meyer }
273