From de0bd6f76b4d39a09bccb18b0804ee60119a442a Mon Sep 17 00:00:00 2001 From: "Bjoern A. Zeeb" <bz@FreeBSD.org> Date: Sun, 13 Dec 2009 13:57:32 +0000 Subject: [PATCH] Throughout the network stack we have a few places of if (jailed(cred)) left. If you are running with a vnet (virtual network stack) those will return true and defer you to classic IP-jails handling and thus things will be "denied" or returned with an error. Work around this problem by introducing another "jailed()" function, jailed_without_vnet(), that also takes vnets into account, and permits the calls, should the jail from the given cred have its own virtual network stack. We cannot change the classic jailed() call to do that, as it is used outside the network stack as well. Discussed with: julian, zec, jamie, rwatson (back in Sept) MFC after: 5 days --- sys/kern/kern_jail.c | 25 ++++++++++++++++++++++++- sys/net/rtsock.c | 4 ++-- sys/netinet/raw_ip.c | 4 ++-- sys/netinet6/raw_ip6.c | 2 +- sys/sys/jail.h | 1 + 5 files changed, 30 insertions(+), 6 deletions(-) diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 0cc330cd5ad4..0900541f2cc9 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -3161,7 +3161,7 @@ prison_check_af(struct ucred *cred, int af) pr = cred->cr_prison; #ifdef VIMAGE /* Prisons with their own network stack are not limited. */ - if (pr->pr_flags & PR_VNET) + if (prison_owns_vnet(cred)) return (0); #endif @@ -3222,6 +3222,11 @@ prison_if(struct ucred *cred, struct sockaddr *sa) KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); KASSERT(sa != NULL, ("%s: sa is NULL", __func__)); +#ifdef VIMAGE + if (prison_owns_vnet(cred)) + return (0); +#endif + error = 0; switch (sa->sa_family) { @@ -3278,6 +3283,24 @@ jailed(struct ucred *cred) return (cred->cr_prison != &prison0); } +/* + * Return 1 if the passed credential is in a jail and that jail does not + * have its own virtual network stack, otherwise 0. + */ +int +jailed_without_vnet(struct ucred *cred) +{ + + if (!jailed(cred)) + return (0); +#ifdef VIMAGE + if (prison_owns_vnet(cred)) + return (0); +#endif + + return (1); +} + /* * Return the correct hostname (domainname, et al) for the passed credential. */ diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c index 4bbd6e32fa9c..a0677ec1dfc1 100644 --- a/sys/net/rtsock.c +++ b/sys/net/rtsock.c @@ -651,7 +651,7 @@ route_output(struct mbuf *m, struct socket *so) report: RT_LOCK_ASSERT(rt); if ((rt->rt_flags & RTF_HOST) == 0 - ? jailed(curthread->td_ucred) + ? jailed_without_vnet(curthread->td_ucred) : prison_if(curthread->td_ucred, rt_key(rt)) != 0) { RT_UNLOCK(rt); @@ -1312,7 +1312,7 @@ sysctl_dumpentry(struct radix_node *rn, void *vw) if (w->w_op == NET_RT_FLAGS && !(rt->rt_flags & w->w_arg)) return 0; if ((rt->rt_flags & RTF_HOST) == 0 - ? jailed(w->w_req->td->td_ucred) + ? jailed_without_vnet(w->w_req->td->td_ucred) : prison_if(w->w_req->td->td_ucred, rt_key(rt)) != 0) return (0); bzero((caddr_t)&info, sizeof(info)); diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 02b51eb703c2..3573472bf258 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -291,7 +291,7 @@ rip_input(struct mbuf *m, int off) continue; if (inp->inp_faddr.s_addr != ip->ip_src.s_addr) continue; - if (jailed(inp->inp_cred)) { + if (jailed_without_vnet(inp->inp_cred)) { /* * XXX: If faddr was bound to multicast group, * jailed raw socket will drop datagram. @@ -325,7 +325,7 @@ rip_input(struct mbuf *m, int off) if (!in_nullhost(inp->inp_faddr) && !in_hosteq(inp->inp_faddr, ip->ip_src)) continue; - if (jailed(inp->inp_cred)) { + if (jailed_without_vnet(inp->inp_cred)) { /* * Allow raw socket in jail to receive multicast; * assume process had PRIV_NETINET_RAW at attach, diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c index 335eff549393..9f1236ab1bdb 100644 --- a/sys/netinet6/raw_ip6.c +++ b/sys/netinet6/raw_ip6.c @@ -184,7 +184,7 @@ rip6_input(struct mbuf **mp, int *offp, int proto) if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr) && !IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src)) continue; - if (jailed(in6p->inp_cred)) { + if (jailed_without_vnet(in6p->inp_cred)) { /* * Allow raw socket in jail to receive multicast; * assume process had PRIV_NETINET_RAW at attach, diff --git a/sys/sys/jail.h b/sys/sys/jail.h index cb26a64ec7d2..2c5d1787786b 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -335,6 +335,7 @@ struct mount; struct sockaddr; struct statfs; int jailed(struct ucred *cred); +int jailed_without_vnet(struct ucred *); void getcredhostname(struct ucred *, char *, size_t); void getcreddomainname(struct ucred *, char *, size_t); void getcredhostuuid(struct ucred *, char *, size_t);