/*- * Copyright (c) 2020 Mariusz Zaborski * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #define TEST_DOMAIN_0 "example.com" #define TEST_DOMAIN_1 "freebsd.org" #define TEST_IPV4 "1.1.1.1" #define TEST_IPV6 "2001:4860:4860::8888" #define TEST_BIND_IPV4 "127.0.0.1" static cap_channel_t * create_network_service(void) { cap_channel_t *capcas, *capnet; capcas = cap_init(); ATF_REQUIRE(capcas != NULL); capnet = cap_service_open(capcas, "system.net"); ATF_REQUIRE(capnet != NULL); cap_close(capcas); return (capnet); } static int test_getnameinfo_v4(cap_channel_t *chan, int family, const char *ip) { struct sockaddr_in ipaddr; char capfn[MAXHOSTNAMELEN]; char origfn[MAXHOSTNAMELEN]; int ret; memset(&ipaddr, 0, sizeof(ipaddr)); ipaddr.sin_family = family; inet_pton(family, ip, &ipaddr.sin_addr); ret = cap_getnameinfo(chan, (struct sockaddr *)&ipaddr, sizeof(ipaddr), capfn, sizeof(capfn), NULL, 0, NI_NAMEREQD); if (ret != 0) { return (ret); } ret = getnameinfo((struct sockaddr *)&ipaddr, sizeof(ipaddr), origfn, sizeof(origfn), NULL, 0, NI_NAMEREQD); ATF_REQUIRE(ret == 0); ATF_REQUIRE(strcmp(origfn, capfn) == 0); return (0); } static int test_getnameinfo_v6(cap_channel_t *chan, const char *ip) { struct sockaddr_in6 ipaddr; char capfn[MAXHOSTNAMELEN]; char origfn[MAXHOSTNAMELEN]; int ret; memset(&ipaddr, 0, sizeof(ipaddr)); ipaddr.sin6_family = AF_INET6; inet_pton(AF_INET6, ip, &ipaddr.sin6_addr); ret = cap_getnameinfo(chan, (struct sockaddr *)&ipaddr, sizeof(ipaddr), capfn, sizeof(capfn), NULL, 0, NI_NAMEREQD); if (ret != 0) { return (ret); } ret = getnameinfo((struct sockaddr *)&ipaddr, sizeof(ipaddr), origfn, sizeof(origfn), NULL, 0, NI_NAMEREQD); ATF_REQUIRE(ret == 0); ATF_REQUIRE(strcmp(origfn, capfn) == 0); return (0); } static int test_getnameinfo(cap_channel_t *chan, int family, const char *ip) { if (family == AF_INET6) { return (test_getnameinfo_v6(chan, ip)); } return (test_getnameinfo_v4(chan, family, ip)); } static int test_gethostbyaddr_v4(cap_channel_t *chan, int family, const char *ip) { struct in_addr ipaddr; struct hostent *caphp, *orighp; memset(&ipaddr, 0, sizeof(ipaddr)); inet_pton(AF_INET, ip, &ipaddr); caphp = cap_gethostbyaddr(chan, &ipaddr, sizeof(ipaddr), family); if (caphp == NULL) { return (h_errno); } orighp = gethostbyaddr(&ipaddr, sizeof(ipaddr), family); ATF_REQUIRE(orighp != NULL); ATF_REQUIRE(strcmp(caphp->h_name, caphp->h_name) == 0); return (0); } static int test_gethostbyaddr_v6(cap_channel_t *chan, const char *ip) { struct in6_addr ipaddr; struct hostent *caphp, *orighp; memset(&ipaddr, 0, sizeof(ipaddr)); inet_pton(AF_INET6, ip, &ipaddr); caphp = cap_gethostbyaddr(chan, &ipaddr, sizeof(ipaddr), AF_INET6); if (caphp == NULL) return (h_errno); orighp = gethostbyaddr(&ipaddr, sizeof(ipaddr), AF_INET6); ATF_REQUIRE(orighp != NULL); ATF_REQUIRE(strcmp(caphp->h_name, caphp->h_name) == 0); return (0); } static int test_gethostbyaddr(cap_channel_t *chan, int family, const char *ip) { if (family == AF_INET6) { return (test_gethostbyaddr_v6(chan, ip)); } else { return (test_gethostbyaddr_v4(chan, family, ip)); } } static int test_getaddrinfo(cap_channel_t *chan, int family, const char *domain, const char *servname) { struct addrinfo hints, *capres, *origres, *res0, *res1; bool found; int ret; memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; ret = cap_getaddrinfo(chan, domain, servname, &hints, &capres); if (ret != 0) { return (ret); } ret = getaddrinfo(domain, servname, &hints, &origres); ATF_REQUIRE(ret == 0); for (res0 = capres; res0 != NULL; res0 = res0->ai_next) { found = false; for (res1 = origres; res1 != NULL; res1 = res1->ai_next) { if (res1->ai_addrlen == res0->ai_addrlen && memcmp(res1->ai_addr, res0->ai_addr, res0->ai_addrlen) == 0) { found = true; break; } } ATF_REQUIRE(found); } freeaddrinfo(capres); freeaddrinfo(origres); return (0); } static int test_gethostbyname(cap_channel_t *chan, int family, const char *domain) { struct hostent *caphp, *orighp; caphp = cap_gethostbyname2(chan, domain, family); if (caphp == NULL) { return (h_errno); } orighp = gethostbyname2(domain, family); ATF_REQUIRE(orighp != NULL); ATF_REQUIRE(strcmp(caphp->h_name, orighp->h_name) == 0); return (0); } static int test_bind(cap_channel_t *chan, const char *ip) { struct sockaddr_in ipv4; int capfd, ret, serrno; capfd = socket(AF_INET, SOCK_STREAM, 0); ATF_REQUIRE(capfd > 0); memset(&ipv4, 0, sizeof(ipv4)); ipv4.sin_family = AF_INET; inet_pton(AF_INET, ip, &ipv4.sin_addr); ret = cap_bind(chan, capfd, (struct sockaddr *)&ipv4, sizeof(ipv4)); serrno = errno; close(capfd); return (ret < 0 ? serrno : 0); } static int test_connect(cap_channel_t *chan, const char *ip, unsigned short port) { struct sockaddr_in ipv4; int capfd, ret, serrno; capfd = socket(AF_INET, SOCK_STREAM, 0); ATF_REQUIRE(capfd > 0); memset(&ipv4, 0, sizeof(ipv4)); ipv4.sin_family = AF_INET; ipv4.sin_port = htons(port); inet_pton(AF_INET, ip, &ipv4.sin_addr); ret = cap_connect(chan, capfd, (struct sockaddr *)&ipv4, sizeof(ipv4)); serrno = errno; close(capfd); return (ret < 0 ? serrno : 0); } static void test_extend_mode(cap_channel_t *capnet, int current) { cap_net_limit_t *limit; const int rights[] = { CAPNET_ADDR2NAME, CAPNET_NAME2ADDR, CAPNET_DEPRECATED_ADDR2NAME, CAPNET_DEPRECATED_NAME2ADDR, CAPNET_CONNECT, CAPNET_BIND, CAPNET_CONNECTDNS }; size_t i; for (i = 0; i < nitems(rights); i++) { if (current == rights[i]) continue; limit = cap_net_limit_init(capnet, current | rights[i]); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) != 0); } } ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name_mode); ATF_TC_BODY(capnet__limits_addr2name_mode, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* LIMIT */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); /* ALLOWED */ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0); /* DISALLOWED */ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE); test_extend_mode(capnet, CAPNET_ADDR2NAME); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name_family); ATF_TC_BODY(capnet__limits_addr2name_family, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; int family[] = { AF_INET6, AF_INET }; capnet = create_network_service(); /* Limit to AF_INET6 and AF_INET. */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name_family(limit, family, nitems(family)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0); /* Limit to AF_INET6 and AF_INET. */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name_family(limit, &family[0], 1); cap_net_limit_addr2name_family(limit, &family[1], 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0); /* Limit to AF_INET6. */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name_family(limit, family, 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name); ATF_TC_BODY(capnet__limits_addr2name, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; struct sockaddr_in ipaddrv4; struct sockaddr_in6 ipaddrv6; capnet = create_network_service(); /* Limit to TEST_IPV4 and TEST_IPV6. */ memset(&ipaddrv4, 0, sizeof(ipaddrv4)); memset(&ipaddrv6, 0, sizeof(ipaddrv6)); ipaddrv4.sin_family = AF_INET; inet_pton(AF_INET, TEST_IPV4, &ipaddrv4.sin_addr); ipaddrv6.sin6_family = AF_INET6; inet_pton(AF_INET6, TEST_IPV6, &ipaddrv6.sin6_addr); limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4, sizeof(ipaddrv4)); cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv6, sizeof(ipaddrv6)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, "127.0.0.1") == ENOTCAPABLE); /* Limit to AF_INET. */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4, sizeof(ipaddrv4)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET6, TEST_IPV6) == ENOTCAPABLE); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, "127.0.0.1") == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_ADDR2NAME); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name_mode); ATF_TC_BODY(capnet__limits_deprecated_addr2name_mode, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* LIMIT */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); /* ALLOWED */ ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0); /* DISALLOWED */ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name_family); ATF_TC_BODY(capnet__limits_deprecated_addr2name_family, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; int family[] = { AF_INET6, AF_INET }; capnet = create_network_service(); /* Limit to AF_INET6 and AF_INET. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name_family(limit, family, nitems(family)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, PF_LINK, TEST_IPV4) == ENOTCAPABLE); /* Limit to AF_INET6 and AF_INET. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name_family(limit, &family[0], 1); cap_net_limit_addr2name_family(limit, &family[1], 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, PF_LINK, TEST_IPV4) == ENOTCAPABLE); /* Limit to AF_INET6. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name_family(limit, family, 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, PF_LINK, TEST_IPV4) == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name); ATF_TC_BODY(capnet__limits_deprecated_addr2name, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; struct in_addr ipaddrv4; struct in6_addr ipaddrv6; capnet = create_network_service(); /* Limit to TEST_IPV4 and TEST_IPV6. */ memset(&ipaddrv4, 0, sizeof(ipaddrv4)); memset(&ipaddrv6, 0, sizeof(ipaddrv6)); inet_pton(AF_INET, TEST_IPV4, &ipaddrv4); inet_pton(AF_INET6, TEST_IPV6, &ipaddrv6); limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4, sizeof(ipaddrv4)); cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv6, sizeof(ipaddrv6)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, "127.0.0.1") == ENOTCAPABLE); /* Limit to AF_INET. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(limit != NULL); cap_net_limit_addr2name(limit, (struct sockaddr *)&ipaddrv4, sizeof(ipaddrv4)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == 0); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET6, TEST_IPV6) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, "127.0.0.1") == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_ADDR2NAME); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_mode); ATF_TC_BODY(capnet__limits_name2addr_mode, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* LIMIT */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); /* ALLOWED */ ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); /* DISALLOWED */ ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE); test_extend_mode(capnet, CAPNET_ADDR2NAME); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts); ATF_TC_BODY(capnet__limits_name2addr_hosts, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* Limit to TEST_DOMAIN_0 and localhost only. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr(limit, "localhost", NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, "localhost", NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, NULL) == ENOTCAPABLE); /* Limit to TEST_DOMAIN_0 only. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, "localhost", NULL) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts_servnames_strict); ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_strict, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* * Limit to TEST_DOMAIN_0 and HTTP service. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, "http"); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "http") == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "snmp") == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "http") == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts_servnames_mix); ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_mix, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* * Limit to TEST_DOMAIN_0 and any servnamex, and any domain with * servname HTTP. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr(limit, NULL, "http"); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "http") == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "http") == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "snmp") == ENOTCAPABLE); /* Limit to HTTTP servname only. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, NULL, "http"); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, "http") == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "http") == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_1, "snmp") == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_family); ATF_TC_BODY(capnet__limits_name2addr_family, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; int family[] = { AF_INET6, AF_INET }; capnet = create_network_service(); /* Limit to AF_INET and AF_INET6. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr_family(limit, family, nitems(family)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET6, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, PF_LINK, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); /* Limit to AF_INET and AF_INET6. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr_family(limit, &family[0], 1); cap_net_limit_name2addr_family(limit, &family[1], 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET6, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, PF_LINK, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); /* Limit to AF_INET6 only. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr_family(limit, family, 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET6, TEST_DOMAIN_0, NULL) == 0); ATF_REQUIRE(test_getaddrinfo(capnet, PF_LINK, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_NAME2ADDR); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_mode); ATF_TC_BODY(capnet__limits_deprecated_name2addr_mode, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* LIMIT */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); /* ALLOWED */ ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0); /* DISALLOWED */ ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE); test_extend_mode(capnet, CAPNET_ADDR2NAME); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_hosts); ATF_TC_BODY(capnet__limits_deprecated_name2addr_hosts, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* Limit to TEST_DOMAIN_0 and localhost only. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr(limit, "localhost", NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, "localhost") == 0); ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_1) == ENOTCAPABLE); /* Limit to TEST_DOMAIN_0 only. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, "localhost") == ENOTCAPABLE); ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_1) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_family); ATF_TC_BODY(capnet__limits_deprecated_name2addr_family, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; int family[] = { AF_INET6, AF_INET }; capnet = create_network_service(); /* Limit to AF_INET and AF_INET6. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr_family(limit, family, nitems(family)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET6, TEST_DOMAIN_0) == 0); ATF_REQUIRE( test_gethostbyname(capnet, PF_LINK, TEST_DOMAIN_0) == ENOTCAPABLE); /* Limit to AF_INET and AF_INET6. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr_family(limit, &family[0], 1); cap_net_limit_name2addr_family(limit, &family[1], 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == 0); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET6, TEST_DOMAIN_0) == 0); ATF_REQUIRE( test_gethostbyname(capnet, PF_LINK, TEST_DOMAIN_0) == ENOTCAPABLE); /* Limit to AF_INET6 only. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_DOMAIN_0, NULL); cap_net_limit_name2addr_family(limit, family, 1); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyname(capnet, AF_INET6, TEST_DOMAIN_0) == 0); ATF_REQUIRE( test_gethostbyname(capnet, PF_LINK, TEST_DOMAIN_0) == ENOTCAPABLE); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_bind_mode); ATF_TC_BODY(capnet__limits_bind_mode, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* LIMIT */ limit = cap_net_limit_init(capnet, CAPNET_BIND); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); /* ALLOWED */ ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == 0); /* DISALLOWED */ ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == ENOTCAPABLE); test_extend_mode(capnet, CAPNET_ADDR2NAME); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_bind); ATF_TC_BODY(capnet__limits_bind, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; struct sockaddr_in ipv4; capnet = create_network_service(); limit = cap_net_limit_init(capnet, CAPNET_BIND); ATF_REQUIRE(limit != NULL); memset(&ipv4, 0, sizeof(ipv4)); ipv4.sin_family = AF_INET; inet_pton(AF_INET, TEST_BIND_IPV4, &ipv4.sin_addr); cap_net_limit_bind(limit, (struct sockaddr *)&ipv4, sizeof(ipv4)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == 0); ATF_REQUIRE(test_bind(capnet, "127.0.0.2") == ENOTCAPABLE); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_connect_mode); ATF_TC_BODY(capnet__limits_connect_mode, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; capnet = create_network_service(); /* LIMIT */ limit = cap_net_limit_init(capnet, CAPNET_CONNECT); ATF_REQUIRE(limit != NULL); ATF_REQUIRE(cap_net_limit(limit) == 0); /* ALLOWED */ ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == 0); /* DISALLOWED */ ATF_REQUIRE( test_gethostbyname(capnet, AF_INET, TEST_DOMAIN_0) == ENOTCAPABLE); ATF_REQUIRE(test_getnameinfo(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_gethostbyaddr(capnet, AF_INET, TEST_IPV4) == ENOTCAPABLE); ATF_REQUIRE(test_getaddrinfo(capnet, AF_INET, TEST_DOMAIN_0, NULL) == ENOTCAPABLE); ATF_REQUIRE(test_bind(capnet, TEST_BIND_IPV4) == ENOTCAPABLE); test_extend_mode(capnet, CAPNET_ADDR2NAME); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_connect); ATF_TC_BODY(capnet__limits_connect, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; struct sockaddr_in ipv4; capnet = create_network_service(); /* Limit only to TEST_IPV4 on port 80 and 443. */ limit = cap_net_limit_init(capnet, CAPNET_CONNECT); ATF_REQUIRE(limit != NULL); memset(&ipv4, 0, sizeof(ipv4)); ipv4.sin_family = AF_INET; ipv4.sin_port = htons(80); inet_pton(AF_INET, TEST_IPV4, &ipv4.sin_addr); cap_net_limit_connect(limit, (struct sockaddr *)&ipv4, sizeof(ipv4)); ipv4.sin_port = htons(443); cap_net_limit_connect(limit, (struct sockaddr *)&ipv4, sizeof(ipv4)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 80) == 0); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 80) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 443) == 0); /* Limit only to TEST_IPV4 on port 443. */ limit = cap_net_limit_init(capnet, CAPNET_CONNECT); cap_net_limit_connect(limit, (struct sockaddr *)&ipv4, sizeof(ipv4)); ATF_REQUIRE(cap_net_limit(limit) == 0); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 433) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 80) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE); ATF_REQUIRE(test_connect(capnet, TEST_IPV4, 443) == 0); /* Unable to set empty limits. Empty limits means full access. */ limit = cap_net_limit_init(capnet, CAPNET_CONNECT); ATF_REQUIRE(cap_net_limit(limit) != 0); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_connecttodns); ATF_TC_BODY(capnet__limits_connecttodns, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; struct addrinfo hints, *capres, *res; int family[] = { AF_INET }; capnet = create_network_service(); limit = cap_net_limit_init(capnet, CAPNET_CONNECTDNS | CAPNET_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_IPV4, "80"); cap_net_limit_name2addr_family(limit, family, 1); ATF_REQUIRE(cap_net_limit(limit) == 0); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE); ATF_REQUIRE(cap_getaddrinfo(capnet, TEST_IPV4, "80", &hints, &capres) == 0); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE); for (res = capres; res != NULL; res = res->ai_next) { int s; ATF_REQUIRE(res->ai_family == AF_INET); ATF_REQUIRE(res->ai_socktype == SOCK_STREAM); s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); ATF_REQUIRE(s >= 0); ATF_REQUIRE(cap_connect(capnet, s, res->ai_addr, res->ai_addrlen) == 0); close(s); } freeaddrinfo(capres); cap_close(capnet); } ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_connecttodns); ATF_TC_BODY(capnet__limits_deprecated_connecttodns, tc) { cap_channel_t *capnet; cap_net_limit_t *limit; struct hostent *caphp; struct in_addr ipaddr; struct sockaddr_in connaddr; int family[] = { AF_INET }; int i; capnet = create_network_service(); limit = cap_net_limit_init(capnet, CAPNET_CONNECTDNS | CAPNET_DEPRECATED_NAME2ADDR); ATF_REQUIRE(limit != NULL); cap_net_limit_name2addr(limit, TEST_IPV4, NULL); cap_net_limit_name2addr_family(limit, family, 1); ATF_REQUIRE(cap_net_limit(limit) == 0); memset(&ipaddr, 0, sizeof(ipaddr)); inet_pton(AF_INET, TEST_IPV4, &ipaddr); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE); caphp = cap_gethostbyname2(capnet, TEST_IPV4, AF_INET); ATF_REQUIRE(caphp != NULL); ATF_REQUIRE(caphp->h_addrtype == AF_INET); ATF_REQUIRE(test_connect(capnet, "8.8.8.8", 433) == ENOTCAPABLE); for (i = 0; caphp->h_addr_list[i] != NULL; i++) { int s; s = socket(AF_INET, SOCK_STREAM, 0); ATF_REQUIRE(s >= 0); memset(&connaddr, 0, sizeof(connaddr)); connaddr.sin_family = AF_INET; memcpy((char *)&connaddr.sin_addr.s_addr, (char *)caphp->h_addr_list[i], caphp->h_length); connaddr.sin_port = htons(80); ATF_REQUIRE(cap_connect(capnet, s, (struct sockaddr *)&connaddr, sizeof(connaddr)) == 0); close(s); } cap_close(capnet); } ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, capnet__limits_addr2name_mode); ATF_TP_ADD_TC(tp, capnet__limits_addr2name_family); ATF_TP_ADD_TC(tp, capnet__limits_addr2name); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_addr2name_mode); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_addr2name_family); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_addr2name); ATF_TP_ADD_TC(tp, capnet__limits_name2addr_mode); ATF_TP_ADD_TC(tp, capnet__limits_name2addr_hosts); ATF_TP_ADD_TC(tp, capnet__limits_name2addr_hosts_servnames_strict); ATF_TP_ADD_TC(tp, capnet__limits_name2addr_hosts_servnames_mix); ATF_TP_ADD_TC(tp, capnet__limits_name2addr_family); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_name2addr_mode); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_name2addr_hosts); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_name2addr_family); ATF_TP_ADD_TC(tp, capnet__limits_bind_mode); ATF_TP_ADD_TC(tp, capnet__limits_bind); ATF_TP_ADD_TC(tp, capnet__limits_connect_mode); ATF_TP_ADD_TC(tp, capnet__limits_connect); ATF_TP_ADD_TC(tp, capnet__limits_connecttodns); ATF_TP_ADD_TC(tp, capnet__limits_deprecated_connecttodns); return (atf_no_error()); }