privsep: Capsicum needs root to access ipv6 forwarding sysctl

Optimise the flow so that if we do have a global address on the
source interface we avoid the sysctl via the privileged process.

Generally the only time we don't is when we de-configure an
interface or we are configuring an interface where there is
no autoconf prefix from the RA and the only globals come
from a DHCPv6 Prefix Delegation to other interfaces which
requires us to be a router.
This commit is contained in:
Roy Marples 2024-09-03 09:37:47 +01:00
parent ae3d1b550a
commit b22ef29e3e
4 changed files with 48 additions and 23 deletions

View File

@ -1108,43 +1108,61 @@ ipv6_getstate(struct interface *ifp)
return state;
}
static struct ipv6_addr *
ipv6_ifanyglobal(struct interface *ifp)
{
struct ipv6_state *state;
struct ipv6_addr *ia;
state = IPV6_STATE(ifp);
if (state == NULL)
return NULL;
TAILQ_FOREACH(ia, &state->addrs, next) {
if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) ||
IN6_IS_ADDR_LOOPBACK(&ia->addr))
continue;
/* Let's be optimistic.
* Any decent OS won't forward or accept traffic
* from/to tentative or detached addresses. */
if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
return ia;
}
return NULL;
}
struct ipv6_addr *
ipv6_anyglobal(struct interface *sifp)
{
struct interface *ifp;
struct ipv6_state *state;
struct ipv6_addr *ia;
struct interface *ifp;
bool forwarding;
ia = ipv6_ifanyglobal(sifp);
if (ia != NULL)
return ia;
/* BSD forwarding is either on or off.
* Linux forwarding is technically the same as it's
* configured by the "all" interface.
* Per interface only affects IsRouter of NA messages. */
#if defined(PRIVSEP) && (defined(HAVE_PLEDGE) || defined(__linux__))
#ifdef PRIVSEP_SYSCTL
if (IN_PRIVSEP(sifp->ctx))
forwarding = ps_root_ip6forwarding(sifp->ctx, NULL) != 0;
else
#endif
forwarding = ip6_forwarding(NULL) != 0;
if (!forwarding)
return NULL;
TAILQ_FOREACH(ifp, sifp->ctx->ifaces, next) {
if (ifp != sifp && !forwarding)
if (ifp == sifp)
continue;
state = IPV6_STATE(ifp);
if (state == NULL)
continue;
TAILQ_FOREACH(ia, &state->addrs, next) {
if (IN6_IS_ADDR_LINKLOCAL(&ia->addr) ||
IN6_IS_ADDR_LOOPBACK(&ia->addr))
continue;
/* Let's be optimistic.
* Any decent OS won't forward or accept traffic
* from/to tentative or detached addresses. */
if (!(ia->addr_flags & IN6_IFF_DUPLICATED))
return ia;
}
ia = ipv6_ifanyglobal(ifp);
if (ia != NULL)
return ia;
}
return NULL;
}

View File

@ -566,7 +566,7 @@ ipv6nd_advertise(struct ipv6_addr *ia)
na->nd_na_type = ND_NEIGHBOR_ADVERT;
na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
#if defined(PRIVSEP) && (defined(__linux__) || defined(HAVE_PLEDGE))
#ifdef PRIVSEP_SYSCTL
if (IN_PRIVSEP(ctx)) {
if (ps_root_ip6forwarding(ctx, ifp->name) != 0)
na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;

View File

@ -1173,7 +1173,7 @@ err:
}
#endif
#if defined(__linux__) || defined(HAVE_PLEDGE)
#ifdef PRIVSEP_SYSCTL
ssize_t
ps_root_ip6forwarding(struct dhcpcd_ctx *ctx, const char *ifname)
{

View File

@ -110,8 +110,15 @@
#define PS_PROCESS_TIMEOUT 5 /* seconds to stop all processes */
#if defined(PRIVSEP) && defined(HAVE_CAPSICUM)
#define PRIVSEP_RIGHTS
#ifdef PRIVSEP
# ifdef HAVE_CAPSICUM
# define PRIVSEP_RIGHTS
# endif
/* Pledge and Capsicum deny nearly all sysctls.
* Linux needs directory access to sysctls. */
# if defined(HAVE_CAPSICUM) ||defined(HAVE_PLEDGE) || defined(__linux__)
# define PRIVSEP_SYSCTL
# endif
#endif
#define PS_ROOT_FD(ctx) ((ctx)->ps_root ? (ctx)->ps_root->psp_fd : -1)