Author: stevek Date: Tue Aug 9 02:16:21 2016 New Revision: 303863 URL: https://svnweb.freebsd.org/changeset/base/303863
Log: Move IPv4-specific jail functions to new file netinet/in_jail.c _prison_check_ip4 renamed to prison_check_ip4_locked Move IPv6-specific jail functions to new file netinet6/in6_jail.c _prison_check_ip6 renamed to prison_check_ip6_locked Add appropriate prototypes to sys/sys/jail.h Adjust kern_jail.c to call prison_check_ip4_locked and prison_check_ip6_locked accordingly. Add netinet/in_jail.c and netinet6/in6_jail.c to the list of files that need to be built when INET and INET6, respectively, are configured in the kernel configuration file. Reviewed by: jtl Approved by: sjg (mentor) Sponsored by: Juniper Networks, Inc. Differential Revision: https://reviews.freebsd.org/D6799 Added: head/sys/netinet/in_jail.c (contents, props changed) head/sys/netinet6/in6_jail.c (contents, props changed) Modified: head/sys/conf/files head/sys/kern/kern_jail.c head/sys/sys/jail.h Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Tue Aug 9 01:05:29 2016 (r303862) +++ head/sys/conf/files Tue Aug 9 02:16:21 2016 (r303863) @@ -3748,6 +3748,7 @@ netinet/in_fib.c optional inet 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_cksum.c optional inet6 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 Modified: head/sys/kern/kern_jail.c ============================================================================== --- head/sys/kern/kern_jail.c Tue Aug 9 01:05:29 2016 (r303862) +++ head/sys/kern/kern_jail.c Tue Aug 9 02:16:21 2016 (r303863) @@ -130,14 +130,6 @@ static void prison_racct_attach(struct p 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 @@ prison0_init(void) 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 @@ kern_jail_set(struct thread *td, struct * 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 @@ kern_jail_set(struct thread *td, struct 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 @@ kern_jail_set(struct thread *td, struct (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 @@ kern_jail_set(struct thread *td, struct (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 @@ prison_proc_free(struct prison *pr) 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. * Added: head/sys/netinet/in_jail.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/netinet/in_jail.c Tue Aug 9 02:16:21 2016 (r303863) @@ -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). *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"