Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F143609416
D6799.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
42 KB
Referenced Files
None
Subscribers
None
D6799.diff
View Options
Index: head/sys/conf/files
===================================================================
--- head/sys/conf/files
+++ head/sys/conf/files
@@ -3748,6 +3748,7 @@
netinet/in_gif.c optional gif inet | netgraph_gif inet
netinet/ip_gre.c optional gre inet
netinet/ip_id.c optional inet
+netinet/in_jail.c optional inet
netinet/in_mcast.c optional inet
netinet/in_pcb.c optional inet | inet6
netinet/in_pcbgroup.c optional inet pcbgroup | inet6 pcbgroup
@@ -3816,6 +3817,7 @@
netinet6/in6_fib.c optional inet6
netinet6/in6_gif.c optional gif inet6 | netgraph_gif inet6
netinet6/in6_ifattach.c optional inet6
+netinet6/in6_jail.c optional inet6
netinet6/in6_mcast.c optional inet6
netinet6/in6_pcb.c optional inet6
netinet6/in6_pcbgroup.c optional inet6 pcbgroup
Index: head/sys/kern/kern_jail.c
===================================================================
--- head/sys/kern/kern_jail.c
+++ head/sys/kern/kern_jail.c
@@ -130,14 +130,6 @@
static void prison_racct_modify(struct prison *pr);
static void prison_racct_detach(struct prison *pr);
#endif
-#ifdef INET
-static int _prison_check_ip4(const struct prison *, const struct in_addr *);
-static int prison_restrict_ip4(struct prison *pr, struct in_addr *newip4);
-#endif
-#ifdef INET6
-static int _prison_check_ip6(struct prison *pr, struct in6_addr *ia6);
-static int prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6);
-#endif
/* Flags for prison_deref */
#define PD_DEREF 0x01
@@ -252,54 +244,6 @@
strlcpy(prison0.pr_osrelease, osrelease, sizeof(prison0.pr_osrelease));
}
-#ifdef INET
-static int
-qcmp_v4(const void *ip1, const void *ip2)
-{
- in_addr_t iaa, iab;
-
- /*
- * We need to compare in HBO here to get the list sorted as expected
- * by the result of the code. Sorting NBO addresses gives you
- * interesting results. If you do not understand, do not try.
- */
- iaa = ntohl(((const struct in_addr *)ip1)->s_addr);
- iab = ntohl(((const struct in_addr *)ip2)->s_addr);
-
- /*
- * Do not simply return the difference of the two numbers, the int is
- * not wide enough.
- */
- if (iaa > iab)
- return (1);
- else if (iaa < iab)
- return (-1);
- else
- return (0);
-}
-#endif
-
-#ifdef INET6
-static int
-qcmp_v6(const void *ip1, const void *ip2)
-{
- const struct in6_addr *ia6a, *ia6b;
- int i, rc;
-
- ia6a = (const struct in6_addr *)ip1;
- ia6b = (const struct in6_addr *)ip2;
-
- rc = 0;
- for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) {
- if (ia6a->s6_addr[i] > ia6b->s6_addr[i])
- rc = 1;
- else if (ia6a->s6_addr[i] < ia6b->s6_addr[i])
- rc = -1;
- }
- return (rc);
-}
-#endif
-
/*
* struct jail_args {
* struct jail *jail;
@@ -845,7 +789,8 @@
* address to connect from.
*/
if (ip4s > 1)
- qsort(ip4 + 1, ip4s - 1, sizeof(*ip4), qcmp_v4);
+ qsort(ip4 + 1, ip4s - 1, sizeof(*ip4),
+ prison_qcmp_v4);
/*
* Check for duplicate addresses and do some simple
* zero and broadcast checks. If users give other bogus
@@ -893,7 +838,8 @@
ip6 = malloc(ip6s * sizeof(*ip6), M_PRISON, M_WAITOK);
bcopy(op, ip6, ip6s * sizeof(*ip6));
if (ip6s > 1)
- qsort(ip6 + 1, ip6s - 1, sizeof(*ip6), qcmp_v6);
+ qsort(ip6 + 1, ip6s - 1, sizeof(*ip6),
+ prison_qcmp_v6);
for (ii = 0; ii < ip6s; ii++) {
if (IN6_IS_ADDR_UNSPECIFIED(&ip6[ii])) {
error = EINVAL;
@@ -1486,7 +1432,8 @@
(ip4s == 1 && tpr->pr_ip4s == 1))
continue;
for (ii = 0; ii < ip4s; ii++) {
- if (_prison_check_ip4(tpr, &ip4[ii]) == 0) {
+ if (prison_check_ip4_locked(tpr, &ip4[ii]) ==
+ 0) {
error = EADDRINUSE;
vfs_opterror(opts,
"IPv4 addresses clash");
@@ -1552,7 +1499,8 @@
(ip6s == 1 && tpr->pr_ip6s == 1))
continue;
for (ii = 0; ii < ip6s; ii++) {
- if (_prison_check_ip6(tpr, &ip6[ii]) == 0) {
+ if (prison_check_ip6_locked(tpr, &ip6[ii]) ==
+ 0) {
error = EADDRINUSE;
vfs_opterror(opts,
"IPv6 addresses clash");
@@ -2770,684 +2718,6 @@
mtx_unlock(&pr->pr_mtx);
}
-
-#ifdef INET
-/*
- * Restrict a prison's IP address list with its parent's, possibly replacing
- * it. Return true if the replacement buffer was used (or would have been).
- */
-static int
-prison_restrict_ip4(struct prison *pr, struct in_addr *newip4)
-{
- int ii, ij, used;
- struct prison *ppr;
-
- ppr = pr->pr_parent;
- if (!(pr->pr_flags & PR_IP4_USER)) {
- /* This has no user settings, so just copy the parent's list. */
- if (pr->pr_ip4s < ppr->pr_ip4s) {
- /*
- * There's no room for the parent's list. Use the
- * new list buffer, which is assumed to be big enough
- * (if it was passed). If there's no buffer, try to
- * allocate one.
- */
- used = 1;
- if (newip4 == NULL) {
- newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4),
- M_PRISON, M_NOWAIT);
- if (newip4 != NULL)
- used = 0;
- }
- if (newip4 != NULL) {
- bcopy(ppr->pr_ip4, newip4,
- ppr->pr_ip4s * sizeof(*newip4));
- free(pr->pr_ip4, M_PRISON);
- pr->pr_ip4 = newip4;
- pr->pr_ip4s = ppr->pr_ip4s;
- }
- return (used);
- }
- pr->pr_ip4s = ppr->pr_ip4s;
- if (pr->pr_ip4s > 0)
- bcopy(ppr->pr_ip4, pr->pr_ip4,
- pr->pr_ip4s * sizeof(*newip4));
- else if (pr->pr_ip4 != NULL) {
- free(pr->pr_ip4, M_PRISON);
- pr->pr_ip4 = NULL;
- }
- } else if (pr->pr_ip4s > 0) {
- /* Remove addresses that aren't in the parent. */
- for (ij = 0; ij < ppr->pr_ip4s; ij++)
- if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr)
- break;
- if (ij < ppr->pr_ip4s)
- ii = 1;
- else {
- bcopy(pr->pr_ip4 + 1, pr->pr_ip4,
- --pr->pr_ip4s * sizeof(*pr->pr_ip4));
- ii = 0;
- }
- for (ij = 1; ii < pr->pr_ip4s; ) {
- if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) {
- ii++;
- continue;
- }
- switch (ij >= ppr->pr_ip4s ? -1 :
- qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) {
- case -1:
- bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii,
- (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4));
- break;
- case 0:
- ii++;
- ij++;
- break;
- case 1:
- ij++;
- break;
- }
- }
- if (pr->pr_ip4s == 0) {
- free(pr->pr_ip4, M_PRISON);
- pr->pr_ip4 = NULL;
- }
- }
- return (0);
-}
-
-/*
- * Pass back primary IPv4 address of this jail.
- *
- * If not restricted return success but do not alter the address. Caller has
- * to make sure to initialize it correctly (e.g. INADDR_ANY).
- *
- * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
- * Address returned in NBO.
- */
-int
-prison_get_ip4(struct ucred *cred, struct in_addr *ia)
-{
- struct prison *pr;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP4))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP4)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip4 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- ia->s_addr = pr->pr_ip4[0].s_addr;
- mtx_unlock(&pr->pr_mtx);
- return (0);
-}
-
-/*
- * 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
-prison_equal_ip4(struct prison *pr1, struct prison *pr2)
-{
-
- if (pr1 == pr2)
- return (1);
-
- /*
- * No need to lock since the PR_IP4_USER flag can't be altered for
- * existing prisons.
- */
- while (pr1 != &prison0 &&
-#ifdef VIMAGE
- !(pr1->pr_flags & PR_VNET) &&
-#endif
- !(pr1->pr_flags & PR_IP4_USER))
- pr1 = pr1->pr_parent;
- while (pr2 != &prison0 &&
-#ifdef VIMAGE
- !(pr2->pr_flags & PR_VNET) &&
-#endif
- !(pr2->pr_flags & PR_IP4_USER))
- pr2 = pr2->pr_parent;
- return (pr1 == pr2);
-}
-
-/*
- * Make sure our (source) address is set to something meaningful to this
- * jail.
- *
- * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail,
- * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
- * doesn't allow IPv4. Address passed in in NBO and returned in NBO.
- */
-int
-prison_local_ip4(struct ucred *cred, struct in_addr *ia)
-{
- struct prison *pr;
- struct in_addr ia0;
- int error;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP4))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP4)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip4 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- ia0.s_addr = ntohl(ia->s_addr);
- if (ia0.s_addr == INADDR_LOOPBACK) {
- ia->s_addr = pr->pr_ip4[0].s_addr;
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
-
- if (ia0.s_addr == INADDR_ANY) {
- /*
- * In case there is only 1 IPv4 address, bind directly.
- */
- if (pr->pr_ip4s == 1)
- ia->s_addr = pr->pr_ip4[0].s_addr;
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
-
- error = _prison_check_ip4(pr, ia);
- mtx_unlock(&pr->pr_mtx);
- return (error);
-}
-
-/*
- * Rewrite destination address in case we will connect to loopback address.
- *
- * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
- * Address passed in in NBO and returned in NBO.
- */
-int
-prison_remote_ip4(struct ucred *cred, struct in_addr *ia)
-{
- struct prison *pr;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP4))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP4)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip4 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- if (ntohl(ia->s_addr) == INADDR_LOOPBACK) {
- ia->s_addr = pr->pr_ip4[0].s_addr;
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
-
- /*
- * Return success because nothing had to be changed.
- */
- mtx_unlock(&pr->pr_mtx);
- return (0);
-}
-
-/*
- * Check if given address belongs to the jail referenced by cred/prison.
- *
- * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail,
- * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
- * doesn't allow IPv4. Address passed in in NBO.
- */
-static int
-_prison_check_ip4(const struct prison *pr, const struct in_addr *ia)
-{
- int i, a, z, d;
-
- /*
- * Check the primary IP.
- */
- if (pr->pr_ip4[0].s_addr == ia->s_addr)
- return (0);
-
- /*
- * All the other IPs are sorted so we can do a binary search.
- */
- a = 0;
- z = pr->pr_ip4s - 2;
- while (a <= z) {
- i = (a + z) / 2;
- d = qcmp_v4(&pr->pr_ip4[i+1], ia);
- if (d > 0)
- z = i - 1;
- else if (d < 0)
- a = i + 1;
- else
- return (0);
- }
-
- return (EADDRNOTAVAIL);
-}
-
-int
-prison_check_ip4(const struct ucred *cred, const struct in_addr *ia)
-{
- struct prison *pr;
- int error;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP4))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP4)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip4 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- error = _prison_check_ip4(pr, ia);
- mtx_unlock(&pr->pr_mtx);
- return (error);
-}
-#endif
-
-#ifdef INET6
-static int
-prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6)
-{
- int ii, ij, used;
- struct prison *ppr;
-
- ppr = pr->pr_parent;
- if (!(pr->pr_flags & PR_IP6_USER)) {
- /* This has no user settings, so just copy the parent's list. */
- if (pr->pr_ip6s < ppr->pr_ip6s) {
- /*
- * There's no room for the parent's list. Use the
- * new list buffer, which is assumed to be big enough
- * (if it was passed). If there's no buffer, try to
- * allocate one.
- */
- used = 1;
- if (newip6 == NULL) {
- newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6),
- M_PRISON, M_NOWAIT);
- if (newip6 != NULL)
- used = 0;
- }
- if (newip6 != NULL) {
- bcopy(ppr->pr_ip6, newip6,
- ppr->pr_ip6s * sizeof(*newip6));
- free(pr->pr_ip6, M_PRISON);
- pr->pr_ip6 = newip6;
- pr->pr_ip6s = ppr->pr_ip6s;
- }
- return (used);
- }
- pr->pr_ip6s = ppr->pr_ip6s;
- if (pr->pr_ip6s > 0)
- bcopy(ppr->pr_ip6, pr->pr_ip6,
- pr->pr_ip6s * sizeof(*newip6));
- else if (pr->pr_ip6 != NULL) {
- free(pr->pr_ip6, M_PRISON);
- pr->pr_ip6 = NULL;
- }
- } else if (pr->pr_ip6s > 0) {
- /* Remove addresses that aren't in the parent. */
- for (ij = 0; ij < ppr->pr_ip6s; ij++)
- if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0],
- &ppr->pr_ip6[ij]))
- break;
- if (ij < ppr->pr_ip6s)
- ii = 1;
- else {
- bcopy(pr->pr_ip6 + 1, pr->pr_ip6,
- --pr->pr_ip6s * sizeof(*pr->pr_ip6));
- ii = 0;
- }
- for (ij = 1; ii < pr->pr_ip6s; ) {
- if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii],
- &ppr->pr_ip6[0])) {
- ii++;
- continue;
- }
- switch (ij >= ppr->pr_ip6s ? -1 :
- qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) {
- case -1:
- bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii,
- (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6));
- break;
- case 0:
- ii++;
- ij++;
- break;
- case 1:
- ij++;
- break;
- }
- }
- if (pr->pr_ip6s == 0) {
- free(pr->pr_ip6, M_PRISON);
- pr->pr_ip6 = NULL;
- }
- }
- return 0;
-}
-
-/*
- * Pass back primary IPv6 address for this jail.
- *
- * If not restricted return success but do not alter the address. Caller has
- * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT).
- *
- * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
- */
-int
-prison_get_ip6(struct ucred *cred, struct in6_addr *ia6)
-{
- struct prison *pr;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP6))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP6)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip6 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
- mtx_unlock(&pr->pr_mtx);
- return (0);
-}
-
-/*
- * 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
-prison_equal_ip6(struct prison *pr1, struct prison *pr2)
-{
-
- if (pr1 == pr2)
- return (1);
-
- while (pr1 != &prison0 &&
-#ifdef VIMAGE
- !(pr1->pr_flags & PR_VNET) &&
-#endif
- !(pr1->pr_flags & PR_IP6_USER))
- pr1 = pr1->pr_parent;
- while (pr2 != &prison0 &&
-#ifdef VIMAGE
- !(pr2->pr_flags & PR_VNET) &&
-#endif
- !(pr2->pr_flags & PR_IP6_USER))
- pr2 = pr2->pr_parent;
- return (pr1 == pr2);
-}
-
-/*
- * Make sure our (source) address is set to something meaningful to this jail.
- *
- * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0)
- * when needed while binding.
- *
- * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail,
- * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
- * doesn't allow IPv6.
- */
-int
-prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only)
-{
- struct prison *pr;
- int error;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP6))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP6)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip6 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- if (IN6_IS_ADDR_LOOPBACK(ia6)) {
- bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
-
- if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
- /*
- * In case there is only 1 IPv6 address, and v6only is true,
- * then bind directly.
- */
- if (v6only != 0 && pr->pr_ip6s == 1)
- bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
-
- error = _prison_check_ip6(pr, ia6);
- mtx_unlock(&pr->pr_mtx);
- return (error);
-}
-
-/*
- * Rewrite destination address in case we will connect to loopback address.
- *
- * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
- */
-int
-prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6)
-{
- struct prison *pr;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP6))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP6)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip6 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- if (IN6_IS_ADDR_LOOPBACK(ia6)) {
- bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
-
- /*
- * Return success because nothing had to be changed.
- */
- mtx_unlock(&pr->pr_mtx);
- return (0);
-}
-
-/*
- * Check if given address belongs to the jail referenced by cred/prison.
- *
- * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail,
- * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
- * doesn't allow IPv6.
- */
-static int
-_prison_check_ip6(struct prison *pr, struct in6_addr *ia6)
-{
- int i, a, z, d;
-
- /*
- * Check the primary IP.
- */
- if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6))
- return (0);
-
- /*
- * All the other IPs are sorted so we can do a binary search.
- */
- a = 0;
- z = pr->pr_ip6s - 2;
- while (a <= z) {
- i = (a + z) / 2;
- d = qcmp_v6(&pr->pr_ip6[i+1], ia6);
- if (d > 0)
- z = i - 1;
- else if (d < 0)
- a = i + 1;
- else
- return (0);
- }
-
- return (EADDRNOTAVAIL);
-}
-
-int
-prison_check_ip6(struct ucred *cred, struct in6_addr *ia6)
-{
- struct prison *pr;
- int error;
-
- KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
- KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
-
- pr = cred->cr_prison;
- if (!(pr->pr_flags & PR_IP6))
- return (0);
- mtx_lock(&pr->pr_mtx);
- if (!(pr->pr_flags & PR_IP6)) {
- mtx_unlock(&pr->pr_mtx);
- return (0);
- }
- if (pr->pr_ip6 == NULL) {
- mtx_unlock(&pr->pr_mtx);
- return (EAFNOSUPPORT);
- }
-
- error = _prison_check_ip6(pr, ia6);
- mtx_unlock(&pr->pr_mtx);
- return (error);
-}
-#endif
-
/*
* Check if a jail supports the given address family.
*
Index: head/sys/netinet/in_jail.c
===================================================================
--- head/sys/netinet/in_jail.c
+++ head/sys/netinet/in_jail.c
@@ -0,0 +1,432 @@
+/*-
+ * Copyright (c) 1999 Poul-Henning Kamp.
+ * Copyright (c) 2008 Bjoern A. Zeeb.
+ * Copyright (c) 2009 James Gritton.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+#include "opt_ddb.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/sysproto.h>
+#include <sys/malloc.h>
+#include <sys/osd.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/taskqueue.h>
+#include <sys/fcntl.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/racct.h>
+#include <sys/refcount.h>
+#include <sys/sx.h>
+#include <sys/sysent.h>
+#include <sys/namei.h>
+#include <sys/mount.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <net/if.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+
+int
+prison_qcmp_v4(const void *ip1, const void *ip2)
+{
+ in_addr_t iaa, iab;
+
+ /*
+ * We need to compare in HBO here to get the list sorted as expected
+ * by the result of the code. Sorting NBO addresses gives you
+ * interesting results. If you do not understand, do not try.
+ */
+ iaa = ntohl(((const struct in_addr *)ip1)->s_addr);
+ iab = ntohl(((const struct in_addr *)ip2)->s_addr);
+
+ /*
+ * Do not simply return the difference of the two numbers, the int is
+ * not wide enough.
+ */
+ if (iaa > iab)
+ return (1);
+ else if (iaa < iab)
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * Restrict a prison's IP address list with its parent's, possibly replacing
+ * it. Return true if the replacement buffer was used (or would have been).
+ */
+int
+prison_restrict_ip4(struct prison *pr, struct in_addr *newip4)
+{
+ int ii, ij, used;
+ struct prison *ppr;
+
+ ppr = pr->pr_parent;
+ if (!(pr->pr_flags & PR_IP4_USER)) {
+ /* This has no user settings, so just copy the parent's list. */
+ if (pr->pr_ip4s < ppr->pr_ip4s) {
+ /*
+ * There's no room for the parent's list. Use the
+ * new list buffer, which is assumed to be big enough
+ * (if it was passed). If there's no buffer, try to
+ * allocate one.
+ */
+ used = 1;
+ if (newip4 == NULL) {
+ newip4 = malloc(ppr->pr_ip4s * sizeof(*newip4),
+ M_PRISON, M_NOWAIT);
+ if (newip4 != NULL)
+ used = 0;
+ }
+ if (newip4 != NULL) {
+ bcopy(ppr->pr_ip4, newip4,
+ ppr->pr_ip4s * sizeof(*newip4));
+ free(pr->pr_ip4, M_PRISON);
+ pr->pr_ip4 = newip4;
+ pr->pr_ip4s = ppr->pr_ip4s;
+ }
+ return (used);
+ }
+ pr->pr_ip4s = ppr->pr_ip4s;
+ if (pr->pr_ip4s > 0)
+ bcopy(ppr->pr_ip4, pr->pr_ip4,
+ pr->pr_ip4s * sizeof(*newip4));
+ else if (pr->pr_ip4 != NULL) {
+ free(pr->pr_ip4, M_PRISON);
+ pr->pr_ip4 = NULL;
+ }
+ } else if (pr->pr_ip4s > 0) {
+ /* Remove addresses that aren't in the parent. */
+ for (ij = 0; ij < ppr->pr_ip4s; ij++)
+ if (pr->pr_ip4[0].s_addr == ppr->pr_ip4[ij].s_addr)
+ break;
+ if (ij < ppr->pr_ip4s)
+ ii = 1;
+ else {
+ bcopy(pr->pr_ip4 + 1, pr->pr_ip4,
+ --pr->pr_ip4s * sizeof(*pr->pr_ip4));
+ ii = 0;
+ }
+ for (ij = 1; ii < pr->pr_ip4s; ) {
+ if (pr->pr_ip4[ii].s_addr == ppr->pr_ip4[0].s_addr) {
+ ii++;
+ continue;
+ }
+ switch (ij >= ppr->pr_ip4s ? -1 :
+ prison_qcmp_v4(&pr->pr_ip4[ii], &ppr->pr_ip4[ij])) {
+ case -1:
+ bcopy(pr->pr_ip4 + ii + 1, pr->pr_ip4 + ii,
+ (--pr->pr_ip4s - ii) * sizeof(*pr->pr_ip4));
+ break;
+ case 0:
+ ii++;
+ ij++;
+ break;
+ case 1:
+ ij++;
+ break;
+ }
+ }
+ if (pr->pr_ip4s == 0) {
+ free(pr->pr_ip4, M_PRISON);
+ pr->pr_ip4 = NULL;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Pass back primary IPv4 address of this jail.
+ *
+ * If not restricted return success but do not alter the address. Caller has
+ * to make sure to initialize it correctly (e.g. INADDR_ANY).
+ *
+ * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
+ * Address returned in NBO.
+ */
+int
+prison_get_ip4(struct ucred *cred, struct in_addr *ia)
+{
+ struct prison *pr;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP4))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP4)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip4 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ ia->s_addr = pr->pr_ip4[0].s_addr;
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+}
+
+/*
+ * 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
+prison_equal_ip4(struct prison *pr1, struct prison *pr2)
+{
+
+ if (pr1 == pr2)
+ return (1);
+
+ /*
+ * No need to lock since the PR_IP4_USER flag can't be altered for
+ * existing prisons.
+ */
+ while (pr1 != &prison0 &&
+#ifdef VIMAGE
+ !(pr1->pr_flags & PR_VNET) &&
+#endif
+ !(pr1->pr_flags & PR_IP4_USER))
+ pr1 = pr1->pr_parent;
+ while (pr2 != &prison0 &&
+#ifdef VIMAGE
+ !(pr2->pr_flags & PR_VNET) &&
+#endif
+ !(pr2->pr_flags & PR_IP4_USER))
+ pr2 = pr2->pr_parent;
+ return (pr1 == pr2);
+}
+
+/*
+ * Make sure our (source) address is set to something meaningful to this
+ * jail.
+ *
+ * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail,
+ * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
+ * doesn't allow IPv4. Address passed in in NBO and returned in NBO.
+ */
+int
+prison_local_ip4(struct ucred *cred, struct in_addr *ia)
+{
+ struct prison *pr;
+ struct in_addr ia0;
+ int error;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP4))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP4)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip4 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ ia0.s_addr = ntohl(ia->s_addr);
+ if (ia0.s_addr == INADDR_LOOPBACK) {
+ ia->s_addr = pr->pr_ip4[0].s_addr;
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+
+ if (ia0.s_addr == INADDR_ANY) {
+ /*
+ * In case there is only 1 IPv4 address, bind directly.
+ */
+ if (pr->pr_ip4s == 1)
+ ia->s_addr = pr->pr_ip4[0].s_addr;
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+
+ error = prison_check_ip4_locked(pr, ia);
+ mtx_unlock(&pr->pr_mtx);
+ return (error);
+}
+
+/*
+ * Rewrite destination address in case we will connect to loopback address.
+ *
+ * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv4.
+ * Address passed in in NBO and returned in NBO.
+ */
+int
+prison_remote_ip4(struct ucred *cred, struct in_addr *ia)
+{
+ struct prison *pr;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP4))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP4)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip4 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ if (ntohl(ia->s_addr) == INADDR_LOOPBACK) {
+ ia->s_addr = pr->pr_ip4[0].s_addr;
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+
+ /*
+ * Return success because nothing had to be changed.
+ */
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+}
+
+/*
+ * Check if given address belongs to the jail referenced by cred/prison.
+ *
+ * Returns 0 if jail doesn't restrict IPv4 or if address belongs to jail,
+ * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
+ * doesn't allow IPv4. Address passed in in NBO.
+ */
+int
+prison_check_ip4_locked(const struct prison *pr, const struct in_addr *ia)
+{
+ int i, a, z, d;
+
+ /*
+ * Check the primary IP.
+ */
+ if (pr->pr_ip4[0].s_addr == ia->s_addr)
+ return (0);
+
+ /*
+ * All the other IPs are sorted so we can do a binary search.
+ */
+ a = 0;
+ z = pr->pr_ip4s - 2;
+ while (a <= z) {
+ i = (a + z) / 2;
+ d = prison_qcmp_v4(&pr->pr_ip4[i+1], ia);
+ if (d > 0)
+ z = i - 1;
+ else if (d < 0)
+ a = i + 1;
+ else
+ return (0);
+ }
+
+ return (EADDRNOTAVAIL);
+}
+
+int
+prison_check_ip4(const struct ucred *cred, const struct in_addr *ia)
+{
+ struct prison *pr;
+ int error;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia != NULL, ("%s: ia is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP4))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP4)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip4 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ error = prison_check_ip4_locked(pr, ia);
+ mtx_unlock(&pr->pr_mtx);
+ return (error);
+}
Index: head/sys/netinet6/in6_jail.c
===================================================================
--- head/sys/netinet6/in6_jail.c
+++ head/sys/netinet6/in6_jail.c
@@ -0,0 +1,419 @@
+/*-
+ * Copyright (c) 1999 Poul-Henning Kamp.
+ * Copyright (c) 2008 Bjoern A. Zeeb.
+ * Copyright (c) 2009 James Gritton.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_compat.h"
+#include "opt_ddb.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/sysproto.h>
+#include <sys/malloc.h>
+#include <sys/osd.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/taskqueue.h>
+#include <sys/fcntl.h>
+#include <sys/jail.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/racct.h>
+#include <sys/refcount.h>
+#include <sys/sx.h>
+#include <sys/sysent.h>
+#include <sys/namei.h>
+#include <sys/mount.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/syscallsubr.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <net/if.h>
+#include <net/vnet.h>
+
+#include <netinet/in.h>
+
+int
+prison_qcmp_v6(const void *ip1, const void *ip2)
+{
+ const struct in6_addr *ia6a, *ia6b;
+ int i, rc;
+
+ ia6a = (const struct in6_addr *)ip1;
+ ia6b = (const struct in6_addr *)ip2;
+
+ rc = 0;
+ for (i = 0; rc == 0 && i < sizeof(struct in6_addr); i++) {
+ if (ia6a->s6_addr[i] > ia6b->s6_addr[i])
+ rc = 1;
+ else if (ia6a->s6_addr[i] < ia6b->s6_addr[i])
+ rc = -1;
+ }
+ return (rc);
+}
+
+int
+prison_restrict_ip6(struct prison *pr, struct in6_addr *newip6)
+{
+ int ii, ij, used;
+ struct prison *ppr;
+
+ ppr = pr->pr_parent;
+ if (!(pr->pr_flags & PR_IP6_USER)) {
+ /* This has no user settings, so just copy the parent's list. */
+ if (pr->pr_ip6s < ppr->pr_ip6s) {
+ /*
+ * There's no room for the parent's list. Use the
+ * new list buffer, which is assumed to be big enough
+ * (if it was passed). If there's no buffer, try to
+ * allocate one.
+ */
+ used = 1;
+ if (newip6 == NULL) {
+ newip6 = malloc(ppr->pr_ip6s * sizeof(*newip6),
+ M_PRISON, M_NOWAIT);
+ if (newip6 != NULL)
+ used = 0;
+ }
+ if (newip6 != NULL) {
+ bcopy(ppr->pr_ip6, newip6,
+ ppr->pr_ip6s * sizeof(*newip6));
+ free(pr->pr_ip6, M_PRISON);
+ pr->pr_ip6 = newip6;
+ pr->pr_ip6s = ppr->pr_ip6s;
+ }
+ return (used);
+ }
+ pr->pr_ip6s = ppr->pr_ip6s;
+ if (pr->pr_ip6s > 0)
+ bcopy(ppr->pr_ip6, pr->pr_ip6,
+ pr->pr_ip6s * sizeof(*newip6));
+ else if (pr->pr_ip6 != NULL) {
+ free(pr->pr_ip6, M_PRISON);
+ pr->pr_ip6 = NULL;
+ }
+ } else if (pr->pr_ip6s > 0) {
+ /* Remove addresses that aren't in the parent. */
+ for (ij = 0; ij < ppr->pr_ip6s; ij++)
+ if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0],
+ &ppr->pr_ip6[ij]))
+ break;
+ if (ij < ppr->pr_ip6s)
+ ii = 1;
+ else {
+ bcopy(pr->pr_ip6 + 1, pr->pr_ip6,
+ --pr->pr_ip6s * sizeof(*pr->pr_ip6));
+ ii = 0;
+ }
+ for (ij = 1; ii < pr->pr_ip6s; ) {
+ if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[ii],
+ &ppr->pr_ip6[0])) {
+ ii++;
+ continue;
+ }
+ switch (ij >= ppr->pr_ip6s ? -1 :
+ prison_qcmp_v6(&pr->pr_ip6[ii], &ppr->pr_ip6[ij])) {
+ case -1:
+ bcopy(pr->pr_ip6 + ii + 1, pr->pr_ip6 + ii,
+ (--pr->pr_ip6s - ii) * sizeof(*pr->pr_ip6));
+ break;
+ case 0:
+ ii++;
+ ij++;
+ break;
+ case 1:
+ ij++;
+ break;
+ }
+ }
+ if (pr->pr_ip6s == 0) {
+ free(pr->pr_ip6, M_PRISON);
+ pr->pr_ip6 = NULL;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Pass back primary IPv6 address for this jail.
+ *
+ * If not restricted return success but do not alter the address. Caller has
+ * to make sure to initialize it correctly (e.g. IN6ADDR_ANY_INIT).
+ *
+ * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
+ */
+int
+prison_get_ip6(struct ucred *cred, struct in6_addr *ia6)
+{
+ struct prison *pr;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP6))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP6)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip6 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+}
+
+/*
+ * 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
+prison_equal_ip6(struct prison *pr1, struct prison *pr2)
+{
+
+ if (pr1 == pr2)
+ return (1);
+
+ while (pr1 != &prison0 &&
+#ifdef VIMAGE
+ !(pr1->pr_flags & PR_VNET) &&
+#endif
+ !(pr1->pr_flags & PR_IP6_USER))
+ pr1 = pr1->pr_parent;
+ while (pr2 != &prison0 &&
+#ifdef VIMAGE
+ !(pr2->pr_flags & PR_VNET) &&
+#endif
+ !(pr2->pr_flags & PR_IP6_USER))
+ pr2 = pr2->pr_parent;
+ return (pr1 == pr2);
+}
+
+/*
+ * Make sure our (source) address is set to something meaningful to this jail.
+ *
+ * v6only should be set based on (inp->inp_flags & IN6P_IPV6_V6ONLY != 0)
+ * when needed while binding.
+ *
+ * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail,
+ * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
+ * doesn't allow IPv6.
+ */
+int
+prison_local_ip6(struct ucred *cred, struct in6_addr *ia6, int v6only)
+{
+ struct prison *pr;
+ int error;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP6))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP6)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip6 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ if (IN6_IS_ADDR_LOOPBACK(ia6)) {
+ bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+
+ if (IN6_IS_ADDR_UNSPECIFIED(ia6)) {
+ /*
+ * In case there is only 1 IPv6 address, and v6only is true,
+ * then bind directly.
+ */
+ if (v6only != 0 && pr->pr_ip6s == 1)
+ bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+
+ error = prison_check_ip6_locked(pr, ia6);
+ mtx_unlock(&pr->pr_mtx);
+ return (error);
+}
+
+/*
+ * Rewrite destination address in case we will connect to loopback address.
+ *
+ * Returns 0 on success, EAFNOSUPPORT if the jail doesn't allow IPv6.
+ */
+int
+prison_remote_ip6(struct ucred *cred, struct in6_addr *ia6)
+{
+ struct prison *pr;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP6))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP6)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip6 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ if (IN6_IS_ADDR_LOOPBACK(ia6)) {
+ bcopy(&pr->pr_ip6[0], ia6, sizeof(struct in6_addr));
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+
+ /*
+ * Return success because nothing had to be changed.
+ */
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+}
+
+/*
+ * Check if given address belongs to the jail referenced by cred/prison.
+ *
+ * Returns 0 if jail doesn't restrict IPv6 or if address belongs to jail,
+ * EADDRNOTAVAIL if the address doesn't belong, or EAFNOSUPPORT if the jail
+ * doesn't allow IPv6.
+ */
+int
+prison_check_ip6_locked(const struct prison *pr, const struct in6_addr *ia6)
+{
+ int i, a, z, d;
+
+ /*
+ * Check the primary IP.
+ */
+ if (IN6_ARE_ADDR_EQUAL(&pr->pr_ip6[0], ia6))
+ return (0);
+
+ /*
+ * All the other IPs are sorted so we can do a binary search.
+ */
+ a = 0;
+ z = pr->pr_ip6s - 2;
+ while (a <= z) {
+ i = (a + z) / 2;
+ d = prison_qcmp_v6(&pr->pr_ip6[i+1], ia6);
+ if (d > 0)
+ z = i - 1;
+ else if (d < 0)
+ a = i + 1;
+ else
+ return (0);
+ }
+
+ return (EADDRNOTAVAIL);
+}
+
+int
+prison_check_ip6(const struct ucred *cred, const struct in6_addr *ia6)
+{
+ struct prison *pr;
+ int error;
+
+ KASSERT(cred != NULL, ("%s: cred is NULL", __func__));
+ KASSERT(ia6 != NULL, ("%s: ia6 is NULL", __func__));
+
+ pr = cred->cr_prison;
+ if (!(pr->pr_flags & PR_IP6))
+ return (0);
+ mtx_lock(&pr->pr_mtx);
+ if (!(pr->pr_flags & PR_IP6)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+ }
+ if (pr->pr_ip6 == NULL) {
+ mtx_unlock(&pr->pr_mtx);
+ return (EAFNOSUPPORT);
+ }
+
+ error = prison_check_ip6_locked(pr, ia6);
+ mtx_unlock(&pr->pr_mtx);
+ return (error);
+}
Index: head/sys/sys/jail.h
===================================================================
--- head/sys/sys/jail.h
+++ head/sys/sys/jail.h
@@ -389,14 +389,20 @@
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(const struct ucred *, const struct in_addr *);
+int prison_check_ip4_locked(const struct prison *, const struct in_addr *);
int prison_saddrsel_ip4(struct ucred *, struct in_addr *);
+int prison_restrict_ip4(struct prison *, struct in_addr *);
+int prison_qcmp_v4(const void *, const void *);
#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_check_ip6(const struct ucred *, const struct in6_addr *);
+int prison_check_ip6_locked(const struct prison *, const struct in6_addr *);
int prison_saddrsel_ip6(struct ucred *, struct in6_addr *);
+int prison_restrict_ip6(struct prison *, struct in6_addr *);
+int prison_qcmp_v6(const void *, const void *);
#endif
int prison_check_af(struct ucred *cred, int af);
int prison_if(struct ucred *cred, struct sockaddr *sa);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Feb 1, 1:33 AM (5 h, 8 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28240874
Default Alt Text
D6799.diff (42 KB)
Attached To
Mode
D6799: Prepare for network stack as a module: Move protocol-specific functionality out of common jail-related source files.
Attached
Detach File
Event Timeline
Log In to Comment