diff options
-rw-r--r-- | sys/kern/kern_jail.c | 110 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 7 | ||||
-rw-r--r-- | sys/netinet6/in6_src.c | 7 | ||||
-rw-r--r-- | sys/sys/jail.h | 6 | ||||
-rw-r--r-- | usr.sbin/jail/jail.8 | 16 |
5 files changed, 140 insertions, 6 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 8ad22ca..379ff78 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -77,6 +77,21 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_PRISON, "prison", "Prison structures"); +/* Keep struct prison prison0 and some code in kern_jail_set() readable. */ +#ifdef INET +#ifdef INET6 +#define _PR_IP_SADDRSEL PR_IP4_SADDRSEL|PR_IP6_SADDRSEL +#else +#define _PR_IP_SADDRSEL PR_IP4_SADDRSEL +#endif +#else /* !INET */ +#ifdef INET6 +#define _PR_IP_SADDRSEL PR_IP6_SADDRSEL +#else +#define _PR_IP_SADDRSEL 0 +#endif +#endif + /* prison0 describes what is "real" about the system. */ struct prison prison0 = { .pr_id = 0, @@ -89,9 +104,9 @@ struct prison prison0 = { .pr_hostuuid = DEFAULT_HOSTUUID, .pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), #ifdef VIMAGE - .pr_flags = PR_HOST|PR_VNET, + .pr_flags = PR_HOST|PR_VNET|_PR_IP_SADDRSEL, #else - .pr_flags = PR_HOST, + .pr_flags = PR_HOST|_PR_IP_SADDRSEL, #endif .pr_allow = PR_ALLOW_ALL, }; @@ -129,10 +144,22 @@ static int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6); */ static char *pr_flag_names[] = { [0] = "persist", +#ifdef INET + [7] = "ip4.saddrsel", +#endif +#ifdef INET6 + [8] = "ip6.saddrsel", +#endif }; static char *pr_flag_nonames[] = { [0] = "nopersist", +#ifdef INET + [7] = "ip4.nosaddrsel", +#endif +#ifdef INET6 + [8] = "ip6.nosaddrsel", +#endif }; struct jailsys_flags { @@ -1199,6 +1226,9 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) #endif } #endif + /* Source address selection is always on by default. */ + pr->pr_flags |= _PR_IP_SADDRSEL; + pr->pr_securelevel = ppr->pr_securelevel; pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow; pr->pr_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS; @@ -2659,6 +2689,41 @@ prison_get_ip4(struct ucred *cred, struct in_addr *ia) } /* + * Return 1 if we should do proper source address selection or are not jailed. + * We will return 0 if we should bypass source address selection in favour + * of the primary jail IPv4 address. Only in this case *ia will be updated and + * returned in NBO. + * Return EAFNOSUPPORT, in case this jail does not allow IPv4. + */ +int +prison_saddrsel_ip4(struct ucred *cred, struct in_addr *ia) +{ + struct prison *pr; + struct in_addr lia; + int error; + + KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); + KASSERT(ia != NULL, ("%s: ia is NULL", __func__)); + + if (!jailed(cred)) + return (1); + + pr = cred->cr_prison; + if (pr->pr_flags & PR_IP4_SADDRSEL) + return (1); + + lia.s_addr = INADDR_ANY; + error = prison_get_ip4(cred, &lia); + if (error) + return (error); + if (lia.s_addr == INADDR_ANY) + return (1); + + ia->s_addr = lia.s_addr; + return (0); +} + +/* * Return true if pr1 and pr2 have the same IPv4 address restrictions. */ int @@ -2964,6 +3029,41 @@ prison_get_ip6(struct ucred *cred, struct in6_addr *ia6) } /* + * Return 1 if we should do proper source address selection or are not jailed. + * We will return 0 if we should bypass source address selection in favour + * of the primary jail IPv6 address. Only in this case *ia will be updated and + * returned in NBO. + * Return EAFNOSUPPORT, in case this jail does not allow IPv6. + */ +int +prison_saddrsel_ip6(struct ucred *cred, struct in6_addr *ia6) +{ + struct prison *pr; + struct in6_addr lia6; + int error; + + KASSERT(cred != NULL, ("%s: cred is NULL", __func__)); + KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__)); + + if (!jailed(cred)) + return (1); + + pr = cred->cr_prison; + if (pr->pr_flags & PR_IP6_SADDRSEL) + return (1); + + lia6 = in6addr_any; + error = prison_get_ip6(cred, &lia6); + if (error) + return (error); + if (IN6_IS_ADDR_UNSPECIFIED(&lia6)) + return (1); + + bcopy(&lia6, ia6, sizeof(struct in6_addr)); + return (0); +} + +/* * Return true if pr1 and pr2 have the same IPv6 address restrictions. */ int @@ -4116,12 +4216,18 @@ SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RDTUN, "Jail IPv4 address virtualization"); SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr), "S,in_addr,a", "Jail IPv4 addresses"); +SYSCTL_JAIL_PARAM(_ip4, saddrsel, CTLTYPE_INT | CTLFLAG_RW, + "B", "Do (not) use IPv4 source address selection rather than the " + "primary jail IPv4 address."); #endif #ifdef INET6 SYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RDTUN, "Jail IPv6 address virtualization"); SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr), "S,in6_addr,a", "Jail IPv6 addresses"); +SYSCTL_JAIL_PARAM(_ip6, saddrsel, CTLTYPE_INT | CTLFLAG_RW, + "B", "Do (not) use IPv6 source address selection rather than the " + "primary jail IPv6 address."); #endif SYSCTL_JAIL_PARAM_NODE(allow, "Jail permission flags"); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 7a4ac10..204d904 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -552,6 +552,13 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr, KASSERT(laddr != NULL, ("%s: laddr NULL", __func__)); + /* + * Bypass source address selection and use the primary jail IP + * if requested. + */ + if (cred != NULL && !prison_saddrsel_ip4(cred, laddr)) + return (0); + error = 0; bzero(&sro, sizeof(sro)); diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 8e82ef1..ea302a5 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -271,6 +271,13 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, } /* + * Bypass source address selection and use the primary jail IP + * if requested. + */ + if (cred != NULL && !prison_saddrsel_ip6(cred, srcp)) + return (0); + + /* * If the address is not specified, choose the best one based on * the outgoing interface and the destination address. */ diff --git a/sys/sys/jail.h b/sys/sys/jail.h index 2c5d178..d7a0622 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -191,6 +191,10 @@ struct prison { #define PR_VNET 0x00000010 /* Virtual network stack */ #define PR_IP4_DISABLE 0x00000020 /* Disable IPv4 */ #define PR_IP6_DISABLE 0x00000040 /* Disable IPv6 */ +#define PR_IP4_SADDRSEL 0x00000080 /* Do IPv4 src addr sel. or use the */ + /* primary jail address. */ +#define PR_IP6_SADDRSEL 0x00000100 /* Do IPv6 src addr sel. or use the */ + /* primary jail address. */ /* Internal flag bits */ #define PR_REMOVE 0x01000000 /* In process of being removed */ @@ -362,12 +366,14 @@ int prison_get_ip4(struct ucred *cred, struct in_addr *ia); int prison_local_ip4(struct ucred *cred, struct in_addr *ia); int prison_remote_ip4(struct ucred *cred, struct in_addr *ia); int prison_check_ip4(struct ucred *cred, struct in_addr *ia); +int prison_saddrsel_ip4(struct ucred *, struct in_addr *); #ifdef INET6 int prison_equal_ip6(struct prison *, struct prison *); int prison_get_ip6(struct ucred *, struct in6_addr *); int prison_local_ip6(struct ucred *, struct in6_addr *, int); int prison_remote_ip6(struct ucred *, struct in6_addr *); int prison_check_ip6(struct ucred *, struct in6_addr *); +int prison_saddrsel_ip6(struct ucred *, struct in6_addr *); #endif int prison_check_af(struct ucred *cred, int af); int prison_if(struct ucred *cred, struct sockaddr *sa); diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index 3fc4a4b..77f1b95 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 18, 2009 +.Dd January 17, 2010 .Dt JAIL 8 .Os .Sh NAME @@ -252,6 +252,13 @@ match. It is only possible to start multiple jails with the same IP address, if none of the jails has more than this single overlapping IP address assigned to itself. +.It Va ip4.saddrsel +A boolean option to change the formerly mentioned behaviour and disable +IPv4 source address selection for the prison in favour of the primary +IPv4 address of the jail. +Source address selection is enabled by default for all jails and a +.Va ip4.nosaddrsel +setting of a parent jail is not inherited for any child jails. .It Va ip4 Control the availablity of IPv4 addresses. Possible values are @@ -267,9 +274,10 @@ Setting the .Va ip4.addr parameter implies a value of .Dq new . -.It Va ip6.addr , Va ip6 -A list of IPv6 addresses assigned to the prison, the counterpart to -.Va ip4.addr +.It Va ip6.addr , Va ip6.saddrsel , Va ip6 +A set of IPv6 options for the prison, the counterparts to +.Va ip4.addr , +.Va ip4.saddrsel and .Va ip4 above. |