Date: Fri, 6 Sep 2019 19:46:27 +0000 (UTC) From: Alan Somers <asomers@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r351962 - stable/12/sbin/ping6 Message-ID: <201909061946.x86JkRSv074074@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: asomers Date: Fri Sep 6 19:46:27 2019 New Revision: 351962 URL: https://svnweb.freebsd.org/changeset/base/351962 Log: MFC r350556: Capsicumize ping6 Add capsicum support to ping6, mostly copying the strategy used for ping. Submitted by: Ján Sučan <jansucan@gmail.com> Reviewed by: markj Sponsored by: Google, inc. (Google Summer of Code 2019) Differential Revision: https://reviews.freebsd.org/D21050 Modified: stable/12/sbin/ping6/Makefile stable/12/sbin/ping6/ping6.c Directory Properties: stable/12/ (props changed) Modified: stable/12/sbin/ping6/Makefile ============================================================================== --- stable/12/sbin/ping6/Makefile Fri Sep 6 19:40:11 2019 (r351961) +++ stable/12/sbin/ping6/Makefile Fri Sep 6 19:46:27 2019 (r351962) @@ -1,5 +1,7 @@ # $FreeBSD$ +.include <src.opts.mk> + PACKAGE=runtime PROG= ping6 MAN= ping6.8 @@ -11,5 +13,13 @@ BINOWN= root BINMODE=4555 LIBADD= ipsec m md + +.if ${MK_DYNAMICROOT} == "no" +.warning ${PROG} built without libcasper support +.elif ${MK_CASPER} != "no" && !defined(RESCUE) +LIBADD+= casper +LIBADD+= cap_dns +CFLAGS+=-DWITH_CASPER +.endif .include <bsd.prog.mk> Modified: stable/12/sbin/ping6/ping6.c ============================================================================== --- stable/12/sbin/ping6/ping6.c Fri Sep 6 19:40:11 2019 (r351961) +++ stable/12/sbin/ping6/ping6.c Fri Sep 6 19:46:27 2019 (r351962) @@ -104,6 +104,7 @@ __FBSDID("$FreeBSD$"); */ #include <sys/param.h> +#include <sys/capsicum.h> #include <sys/uio.h> #include <sys/socket.h> #include <sys/time.h> @@ -118,6 +119,10 @@ __FBSDID("$FreeBSD$"); #include <arpa/nameser.h> #include <netdb.h> +#include <capsicum_helpers.h> +#include <casper/cap_dns.h> +#include <libcasper.h> + #include <ctype.h> #include <err.h> #include <errno.h> @@ -214,7 +219,8 @@ static struct sockaddr_in6 dst; /* who to ping6 */ static struct sockaddr_in6 src; /* src addr of this packet */ static socklen_t srclen; static size_t datalen = DEFDATALEN; -static int s; /* socket file descriptor */ +static int ssend; /* send socket file descriptor */ +static int srecv; /* receive socket file descriptor */ static u_char outpack[MAXPACKETLEN]; static char BSPACE = '\b'; /* characters written for flood */ static char BBELL = '\a'; /* characters written for AUDIBLE */ @@ -224,6 +230,7 @@ static int ident; /* process id to identify our packe static u_int8_t nonce[8]; /* nonce field for node information */ static int hoplimit = -1; /* hoplimit */ static u_char *packet = NULL; +static cap_channel_t *capdns; /* counters */ static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ @@ -256,6 +263,7 @@ static volatile sig_atomic_t seeninfo; #endif int main(int, char *[]); +static cap_channel_t *capdns_setup(void); static void fill(char *, char *); static int get_hoplim(struct msghdr *); static int get_pathmtu(struct msghdr *); @@ -318,6 +326,9 @@ main(int argc, char *argv[]) #ifdef IPV6_USE_MIN_MTU int mflag = 0; #endif + cap_rights_t rights_srecv; + cap_rights_t rights_ssend; + cap_rights_t rights_stdin; /* just to be sure */ memset(&smsghdr, 0, sizeof(smsghdr)); @@ -325,6 +336,7 @@ main(int argc, char *argv[]) alarmtimeout = preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; + capdns = capdns_setup(); #ifndef IPSEC #define ADDOPTS #else @@ -503,7 +515,7 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - error = getaddrinfo(optarg, NULL, &hints, &res); + error = cap_getaddrinfo(capdns, optarg, NULL, &hints, &res); if (error) { errx(1, "invalid source address: %s", gai_strerror(error)); @@ -619,14 +631,14 @@ main(int argc, char *argv[]) } else target = argv[argc - 1]; - /* getaddrinfo */ + /* cap_getaddrinfo */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - error = getaddrinfo(target, NULL, &hints, &res); + error = cap_getaddrinfo(capdns, target, NULL, &hints, &res); if (error) errx(1, "%s", gai_strerror(error)); if (res->ai_canonname) @@ -635,13 +647,16 @@ main(int argc, char *argv[]) hostname = target; if (!res->ai_addr) - errx(1, "getaddrinfo failed"); + errx(1, "cap_getaddrinfo failed"); (void)memcpy(&dst, res->ai_addr, res->ai_addrlen); - if ((s = socket(res->ai_family, res->ai_socktype, + if ((ssend = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) - err(1, "socket"); + err(1, "socket ssend"); + if ((srecv = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + err(1, "socket srecv"); freeaddrinfo(res); /* set the source address if specified. */ @@ -656,7 +671,7 @@ main(int argc, char *argv[]) if (dst.sin6_scope_id == 0) dst.sin6_scope_id = src.sin6_scope_id; } - if (bind(s, (struct sockaddr *)&src, srclen) != 0) + if (bind(ssend, (struct sockaddr *)&src, srclen) != 0) err(1, "bind"); } /* set the gateway (next hop) if specified */ @@ -666,15 +681,15 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - error = getaddrinfo(gateway, NULL, &hints, &res); + error = cap_getaddrinfo(capdns, gateway, NULL, &hints, &res); if (error) { - errx(1, "getaddrinfo for the gateway %s: %s", + errx(1, "cap_getaddrinfo for the gateway %s: %s", gateway, gai_strerror(error)); } if (res->ai_next && (options & F_VERBOSE)) warnx("gateway resolves to multiple addresses"); - if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_NEXTHOP, res->ai_addr, res->ai_addrlen)) { err(1, "setsockopt(IPV6_NEXTHOP)"); } @@ -690,25 +705,25 @@ main(int argc, char *argv[]) int opton = 1; #ifdef IPV6_RECVHOPOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVHOPOPTS)"); #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_HOPOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_HOPOPTS)"); #endif #ifdef IPV6_RECVDSTOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVDSTOPTS)"); #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_DSTOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_DSTOPTS)"); #endif #ifdef IPV6_RECVRTHDRDSTOPTS - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)"); #endif @@ -751,31 +766,34 @@ main(int argc, char *argv[]) arc4random_buf(nonce, sizeof(nonce)); optval = 1; if (options & F_DONTFRAG) - if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_DONTFRAG, &optval, sizeof(optval)) == -1) err(1, "IPV6_DONTFRAG"); hold = 1; - if (options & F_SO_DEBUG) - (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, + if (options & F_SO_DEBUG) { + (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold)); + (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold, + sizeof(hold)); + } optval = IPV6_DEFHLIM; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_HOPS"); #ifdef IPV6_USE_MIN_MTU if (mflag != 1) { optval = mflag > 1 ? 0 : 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_USE_MIN_MTU, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_USE_MIN_MTU)"); } #ifdef IPV6_RECVPATHMTU else { optval = 1; - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVPATHMTU, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_RECVPATHMTU)"); } @@ -785,29 +803,38 @@ main(int argc, char *argv[]) #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC if (options & F_POLICY) { - if (setpolicy(s, policy_in) < 0) + if (setpolicy(srecv, policy_in) < 0) errx(1, "%s", ipsec_strerror()); - if (setpolicy(s, policy_out) < 0) + if (setpolicy(ssend, policy_out) < 0) errx(1, "%s", ipsec_strerror()); } #else if (options & F_AUTHHDR) { optval = IPSEC_LEVEL_REQUIRE; #ifdef IPV6_AUTH_TRANS_LEVEL - if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)"); #else /* old def */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_AUTH_LEVEL)"); + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_AUTH_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_AUTH_LEVEL)"); #endif } if (options & F_ENCRYPT) { optval = IPSEC_LEVEL_REQUIRE; - if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &optval, sizeof(optval)) == -1) err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, + &optval, sizeof(optval)) == -1) + err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)"); } #endif /*IPSEC_POLICY_IPSEC*/ #endif @@ -825,7 +852,7 @@ main(int argc, char *argv[]) } else { ICMP6_FILTER_SETPASSALL(&filt); } - if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, + if (setsockopt(srecv, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) < 0) err(1, "setsockopt(ICMP6_FILTER)"); } @@ -836,11 +863,11 @@ main(int argc, char *argv[]) int opton = 1; #ifdef IPV6_RECVRTHDR - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RECVRTHDR)"); #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RTHDR, &opton, sizeof(opton))) err(1, "setsockopt(IPV6_RTHDR)"); #endif @@ -849,7 +876,7 @@ main(int argc, char *argv[]) /* optval = 1; if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr)) - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &optval, sizeof(optval)) == -1) err(1, "IPV6_MULTICAST_LOOP"); */ @@ -916,7 +943,7 @@ main(int argc, char *argv[]) memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET6; - if ((error = getaddrinfo(argv[hops], NULL, &hints, + if ((error = cap_getaddrinfo(capdns, argv[hops], NULL, &hints, &res))) errx(1, "%s", gai_strerror(error)); if (res->ai_addr->sa_family != AF_INET6) @@ -931,6 +958,15 @@ main(int argc, char *argv[]) scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp); } + /* From now on we will use only reverse DNS lookups. */ + if (capdns != NULL) { + const char *types[1]; + + types[0] = "ADDR2NAME"; + if (cap_dns_type_limit(capdns, types, nitems(types)) < 0) + err(1, "unable to limit access to system.dns service"); + } + if (!(options & F_SRCADDR)) { /* * get the source address. XXX since we revoked the root @@ -976,14 +1012,36 @@ main(int argc, char *argv[]) close(dummy); } + if (connect(ssend, (struct sockaddr *)&dst, sizeof(dst)) != 0) + err(1, "connect() ssend"); + + caph_cache_catpages(); + if (caph_enter_casper() < 0) + err(1, "caph_enter_casper"); + + cap_rights_init(&rights_stdin); + if (cap_rights_limit(STDIN_FILENO, &rights_stdin) < 0) + err(1, "cap_rights_limit stdin"); + if (caph_limit_stdout() < 0) + err(1, "caph_limit_stdout"); + if (caph_limit_stderr() < 0) + err(1, "caph_limit_stderr"); + + cap_rights_init(&rights_srecv, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); + if (caph_rights_limit(srecv, &rights_srecv) < 0) + err(1, "cap_rights_limit srecv"); + cap_rights_init(&rights_ssend, CAP_SEND, CAP_SETSOCKOPT); + if (caph_rights_limit(ssend, &rights_ssend) < 0) + err(1, "cap_rights_limit ssend"); + #if defined(SO_SNDBUF) && defined(SO_RCVBUF) if (sockbufsize) { if (datalen > (size_t)sockbufsize) warnx("you need -b to increase socket buffer size"); - if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, + if (setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_SNDBUF)"); - if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize, + if (setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, &sockbufsize, sizeof(sockbufsize)) < 0) err(1, "setsockopt(SO_RCVBUF)"); } @@ -997,7 +1055,7 @@ main(int argc, char *argv[]) * to get some stuff for /etc/ethers. */ hold = 48 * 1024; - setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); } #endif @@ -1005,25 +1063,32 @@ main(int argc, char *argv[]) optval = 1; #ifndef USE_SIN6_SCOPE_ID #ifdef IPV6_RECVPKTINFO - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */ #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_PKTINFO, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */ #endif #endif /* USE_SIN6_SCOPE_ID */ #ifdef IPV6_RECVHOPLIMIT - if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */ #else /* old adv. API */ - if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, + if (setsockopt(srecv, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval, sizeof(optval)) < 0) warn("setsockopt(IPV6_HOPLIMIT)"); /* XXX err? */ #endif + cap_rights_clear(&rights_srecv, CAP_SETSOCKOPT); + if (caph_rights_limit(srecv, &rights_srecv) < 0) + err(1, "cap_rights_limit srecv setsockopt"); + cap_rights_clear(&rights_ssend, CAP_SETSOCKOPT); + if (caph_rights_limit(ssend, &rights_ssend) < 0) + err(1, "cap_rights_limit ssend setsockopt"); + printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()), (unsigned long)(pingerlen() - 8)); printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); @@ -1081,7 +1146,7 @@ main(int argc, char *argv[]) } #endif FD_ZERO(&rfds); - FD_SET(s, &rfds); + FD_SET(srecv, &rfds); gettimeofday(&now, NULL); timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; @@ -1096,7 +1161,7 @@ main(int argc, char *argv[]) if (timeout.tv_sec < 0) timeout.tv_sec = timeout.tv_usec = 0; - n = select(s + 1, &rfds, NULL, NULL, &timeout); + n = select(srecv + 1, &rfds, NULL, NULL, &timeout); if (n < 0) continue; /* EINTR */ if (n == 1) { @@ -1111,7 +1176,7 @@ main(int argc, char *argv[]) m.msg_control = (void *)cm; m.msg_controllen = CONTROLLEN; - cc = recvmsg(s, &m, 0); + cc = recvmsg(srecv, &m, 0); if (cc < 0) { if (errno != EINTR) { warn("recvmsg"); @@ -1325,15 +1390,13 @@ pinger(void) errx(1, "internal error; length mismatch"); #endif - smsghdr.msg_name = (caddr_t)&dst; - smsghdr.msg_namelen = sizeof(dst); memset(&iov, 0, sizeof(iov)); iov[0].iov_base = (caddr_t)outpack; iov[0].iov_len = cc; smsghdr.msg_iov = iov; smsghdr.msg_iovlen = 1; - i = sendmsg(s, &smsghdr, 0); + i = sendmsg(ssend, &smsghdr, 0); if (i < 0 || i != cc) { if (i < 0) @@ -2497,7 +2560,8 @@ pr_addr(struct sockaddr *addr, int addrlen) if ((options & F_HOSTNAME) == 0) flag |= NI_NUMERICHOST; - if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0) + if (cap_getnameinfo(capdns, addr, addrlen, buf, sizeof(buf), NULL, 0, + flag) == 0) return (buf); else return "?"; @@ -2631,7 +2695,7 @@ setpolicy(int so __unused, char *policy) buf = ipsec_set_policy(policy, strlen(policy)); if (buf == NULL) errx(1, "%s", ipsec_strerror()); - if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, + if (setsockopt(ssend, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) warnx("Unable to set IPsec policy"); free(buf); @@ -2727,4 +2791,30 @@ usage(void) "[-x waittime]\n" " [-X timeout] [hops ...] host\n"); exit(1); +} + +static cap_channel_t * +capdns_setup(void) +{ + cap_channel_t *capcas, *capdnsloc; + const char *types[2]; + int families[1]; + + capcas = cap_init(); + if (capcas == NULL) + err(1, "unable to create casper process"); + capdnsloc = cap_service_open(capcas, "system.dns"); + /* Casper capability no longer needed. */ + cap_close(capcas); + if (capdnsloc == NULL) + err(1, "unable to open system.dns service"); + types[0] = "NAME2ADDR"; + types[1] = "ADDR2NAME"; + if (cap_dns_type_limit(capdnsloc, types, nitems(types)) < 0) + err(1, "unable to limit access to system.dns service"); + families[0] = AF_INET6; + if (cap_dns_family_limit(capdnsloc, families, nitems(families)) < 0) + err(1, "unable to limit access to system.dns service"); + + return (capdnsloc); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201909061946.x86JkRSv074074>