summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/kern/kern_jail.c110
-rw-r--r--sys/netinet/in_pcb.c7
-rw-r--r--sys/netinet6/in6_src.c7
-rw-r--r--sys/sys/jail.h6
-rw-r--r--usr.sbin/jail/jail.816
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.
OpenPOWER on IntegriCloud