Index: sys/conf/files =================================================================== --- sys/conf/files +++ sys/conf/files @@ -3456,6 +3456,7 @@ netinet/in_mcast.c optional inet netinet/in_pcb.c optional inet | inet6 netinet/in_pcbgroup.c optional inet pcbgroup | inet6 pcbgroup +netinet/in_prot.c optional inet | inet6 netinet/in_proto.c optional inet | inet6 netinet/in_rmx.c optional inet netinet/in_rss.c optional inet rss Index: sys/kern/kern_prot.c =================================================================== --- sys/kern/kern_prot.c +++ sys/kern/kern_prot.c @@ -76,11 +76,6 @@ "Kernel support for interfaces necessary for regression testing (SECURITY RISK!)"); #endif -#if defined(INET) || defined(INET6) -#include -#include -#endif - #include #include @@ -1343,8 +1338,8 @@ * References: *u1 and *u2 must not change during the call * u1 may equal u2, in which case only one reference is required */ -static int -cr_seeotheruids(struct ucred *u1, struct ucred *u2) +int +cr_canseeotheruids(struct ucred *u1, struct ucred *u2) { if (!see_other_uids && u1->cr_ruid != u2->cr_ruid) { @@ -1373,8 +1368,8 @@ * References: *u1 and *u2 must not change during the call * u1 may equal u2, in which case only one reference is required */ -static int -cr_seeothergids(struct ucred *u1, struct ucred *u2) +int +cr_canseeothergids(struct ucred *u1, struct ucred *u2) { int i, match; @@ -1412,9 +1407,9 @@ if ((error = mac_cred_check_visible(u1, u2))) return (error); #endif - if ((error = cr_seeotheruids(u1, u2))) + if ((error = cr_canseeotheruids(u1, u2))) return (error); - if ((error = cr_seeothergids(u1, u2))) + if ((error = cr_canseeothergids(u1, u2))) return (error); return (0); } @@ -1473,9 +1468,9 @@ if ((error = mac_proc_check_signal(cred, proc, signum))) return (error); #endif - if ((error = cr_seeotheruids(cred, proc->p_ucred))) + if ((error = cr_canseeotheruids(cred, proc->p_ucred))) return (error); - if ((error = cr_seeothergids(cred, proc->p_ucred))) + if ((error = cr_canseeothergids(cred, proc->p_ucred))) return (error); /* @@ -1590,9 +1585,9 @@ if ((error = mac_proc_check_sched(td->td_ucred, p))) return (error); #endif - if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) + if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) return (error); - if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) + if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred))) return (error); if (td->td_ucred->cr_ruid != p->p_ucred->cr_ruid && td->td_ucred->cr_uid != p->p_ucred->cr_ruid) { @@ -1647,9 +1642,9 @@ if ((error = mac_proc_check_debug(td->td_ucred, p))) return (error); #endif - if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) + if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) return (error); - if ((error = cr_seeothergids(td->td_ucred, p->p_ucred))) + if ((error = cr_canseeothergids(td->td_ucred, p->p_ucred))) return (error); /* @@ -1741,42 +1736,14 @@ if (error) return (error); #endif - if (cr_seeotheruids(cred, so->so_cred)) + if (cr_canseeotheruids(cred, so->so_cred)) return (ENOENT); - if (cr_seeothergids(cred, so->so_cred)) + if (cr_canseeothergids(cred, so->so_cred)) return (ENOENT); return (0); } -#if defined(INET) || defined(INET6) -/*- - * Determine whether the subject represented by cred can "see" a socket. - * Returns: 0 for permitted, ENOENT otherwise. - */ -int -cr_canseeinpcb(struct ucred *cred, struct inpcb *inp) -{ - int error; - - error = prison_check(cred, inp->inp_cred); - if (error) - return (ENOENT); -#ifdef MAC - INP_LOCK_ASSERT(inp); - error = mac_inpcb_check_visible(cred, inp); - if (error) - return (error); -#endif - if (cr_seeotheruids(cred, inp->inp_cred)) - return (ENOENT); - if (cr_seeothergids(cred, inp->inp_cred)) - return (ENOENT); - - return (0); -} -#endif - /*- * Determine whether td can wait for the exit of p. * Returns: 0 for permitted, an errno value otherwise @@ -1801,7 +1768,7 @@ #endif #if 0 /* XXXMAC: This could have odd effects on some shells. */ - if ((error = cr_seeotheruids(td->td_ucred, p->p_ucred))) + if ((error = cr_canseeotheruids(td->td_ucred, p->p_ucred))) return (error); #endif Index: sys/kern/sys_socket.c =================================================================== --- sys/kern/sys_socket.c +++ sys/kern/sys_socket.c @@ -1,6 +1,8 @@ /*- * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. + * Copyright (c) 2012, 2013, 2015, Juniper Networks, Inc. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -37,7 +39,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -89,6 +94,73 @@ .fo_flags = DFLAG_PASSABLE }; +static struct socket_iocgroup *so_iocgroups; +static int so_iocgroup_init_status; +static struct mtx soiocg_mtx; +MTX_SYSINIT(soiocg, &soiocg_mtx, "socket ioctl groups", MTX_DEF); + +static void so_iocgroupinit(void *); +SYSINIT(so_iocgroup, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, so_iocgroupinit, + NULL); + +static void so_iocgroupfinalize(void *); +SYSINIT(so_iocgroupfin, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST, + so_iocgroupfinalize, NULL); + +void +so_iocgroup_add(void *data) +{ + struct socket_iocgroup *gp; + + gp = (struct socket_iocgroup *)data; + mtx_lock(&soiocg_mtx); + gp->soiocg_next = so_iocgroups; + so_iocgroups = gp; + + KASSERT(so_iocgroup_init_status >= 1, + ("attempt to so_iocgroup_add(%c) before so_iocgroupinit()", + gp->soiocg_group)); +#ifndef INVARIANTS + if (so_iocgroup_init_status < 1) + printf("WARNING: attempt to so_iocgroup_add(%c) before " + "so_iocgroupinit()\n", gp->soiocg_group); +#endif +#ifdef notyet + KASSERT(so_iocgroup_init_status < 2, + ("attempt to so_iocgroup_add(%c) after so_iocgroupfinalize()", + gp->soiocg_group)); +#else + if (so_iocgroup_init_status >= 2) + printf("WARNING: attempt to so_iocgroup_add(%c) after " + "so_iocgroupfinalize()\n", gp->soiocg_group); +#endif + mtx_unlock(&soiocg_mtx); +} + +/* ARGSUSED*/ +static void +so_iocgroupinit(void *dummy) +{ + + mtx_lock(&soiocg_mtx); + KASSERT(so_iocgroup_init_status == 0, + ("so_iocgroupinit called too late!")); + so_iocgroup_init_status = 1; + mtx_unlock(&soiocg_mtx); +} + +/* ARGSUSED*/ +static void +so_iocgroupfinalize(void *dummy) +{ + + mtx_lock(&soiocg_mtx); + KASSERT(so_iocgroup_init_status == 1, + ("so_iocgroupfinalize called too late!")); + so_iocgroup_init_status = 2; + mtx_unlock(&soiocg_mtx); +} + static int soo_read(struct file *fp, struct uio *uio, struct ucred *active_cred, int flags, struct thread *td) @@ -131,6 +203,7 @@ struct thread *td) { struct socket *so = fp->f_data; + struct socket_iocgroup *soiocg; int error = 0; switch (cmd) { @@ -218,13 +291,13 @@ * routing ioctls should have a different entry since a * socket is unnecessary. */ - if (IOCGROUP(cmd) == 'i') - error = ifioctl(so, cmd, data, td); - else if (IOCGROUP(cmd) == 'r') { - CURVNET_SET(so->so_vnet); - error = rtioctl_fib(cmd, data, so->so_fibnum); - CURVNET_RESTORE(); - } else { + for (soiocg = so_iocgroups; soiocg; + soiocg = soiocg->soiocg_next) + if (soiocg->soiocg_group == IOCGROUP(cmd)) + break; + if (soiocg && soiocg->soiocg_ioctl) + error = ((*soiocg->soiocg_ioctl)(so, cmd, data, td)); + else { CURVNET_SET(so->so_vnet); error = ((*so->so_proto->pr_usrreqs->pru_control) (so, cmd, data, 0, td)); Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -120,6 +120,12 @@ static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions"); +static struct socket_iocgroup ifiocgroup = { + .soiocg_group = 'i', + .soiocg_ioctl = ifioctl +}; +SO_IOCGROUP_SET(if); + /* global sx for non-critical path ifdescr */ static struct sx ifdescr_sx; SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr"); Index: sys/net/route.c =================================================================== --- sys/net/route.c +++ sys/net/route.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -147,6 +148,14 @@ }; static int if_updatemtu_cb(struct radix_node *, void *); +static int rtioctl_socket(struct socket *, u_long, caddr_t, + struct thread *); + +static struct socket_iocgroup rtiocgroup = { + .soiocg_group = 'r', + .soiocg_ioctl = rtioctl_socket +}; +SO_IOCGROUP_SET(rt); /* * handler for net.my_fibnum @@ -702,6 +711,20 @@ #endif /* INET */ } + +static int +rtioctl_socket(struct socket *so, u_long cmd, caddr_t data, + struct thread *td __unused) +{ + int error; + + CURVNET_SET(so->so_vnet); + error = rtioctl_fib(cmd, data, so->so_fibnum); + CURVNET_RESTORE(); + + return (error); +} + struct ifaddr * ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway, u_int fibnum) Index: sys/netinet/in_prot.c =================================================================== --- /dev/null +++ sys/netinet/in_prot.c @@ -0,0 +1,90 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1990, 1991, 1993 + * The Regents of the University of California. + * (c) UNIX System Laboratories, Inc. + * Copyright (c) 2000-2001 Robert N. M. Watson. + * All rights reserved. + * + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)kern_prot.c 8.6 (Berkeley) 1/21/94 + */ + +/* + * System calls related to processes and protection + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" +#include "opt_inet.h" +#include "opt_inet6.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/*- + * Determine whether the subject represented by cred can "see" a socket. + * Returns: 0 for permitted, ENOENT otherwise. + */ +int +cr_canseeinpcb(struct ucred *cred, struct inpcb *inp) +{ + int error; + + error = prison_check(cred, inp->inp_cred); + if (error) + return (ENOENT); +#ifdef MAC + INP_LOCK_ASSERT(inp); + error = mac_inpcb_check_visible(cred, inp); + if (error) + return (error); +#endif + if (cr_canseeotheruids(cred, inp->inp_cred)) + return (ENOENT); + if (cr_canseeothergids(cred, inp->inp_cred)) + return (ENOENT); + + return (0); +} Index: sys/netinet/in_systm.h =================================================================== --- sys/netinet/in_systm.h +++ sys/netinet/in_systm.h @@ -55,6 +55,11 @@ typedef u_int32_t n_time; /* ms since 00:00 UTC, byte rev */ #ifdef _KERNEL +struct inpcb; +struct ucred; + +int cr_canseeinpcb(struct ucred *cred, struct inpcb *inp); + uint32_t iptime(void); #endif Index: sys/netinet6/ip6_forward.c =================================================================== --- sys/netinet6/ip6_forward.c +++ sys/netinet6/ip6_forward.c @@ -104,9 +104,6 @@ #ifdef IPSEC struct secpolicy *sp = NULL; #endif -#ifdef SCTP - int sw_csum; -#endif struct m_tag *fwd_tag; char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; Index: sys/sys/socketvar.h =================================================================== --- sys/sys/socketvar.h +++ sys/sys/socketvar.h @@ -130,6 +130,17 @@ uint32_t so_user_cookie; }; +struct socket_iocgroup { + char soiocg_group; + int (*soiocg_ioctl)(struct socket *, u_long, caddr_t, + struct thread *); + struct socket_iocgroup *soiocg_next; +}; + +#define SO_IOCGROUP_SET(name) \ + SYSINIT(so_iocgroup_add_ ## name, SI_SUB_PROTO_DOMAIN, \ + SI_ORDER_FIRST, so_iocgroup_add, & name ## iocgroup) + /* * Global accept mutex to serialize access to accept queues and * fields associated with multiple sockets. This allows us to @@ -334,6 +345,8 @@ #define SU_OK 0 #define SU_ISCONNECTED 1 +void so_iocgroup_add(void *); + /* * From uipc_socket and friends */ Index: sys/sys/systm.h =================================================================== --- sys/sys/systm.h +++ sys/sys/systm.h @@ -307,7 +307,8 @@ int cr_cansee(struct ucred *u1, struct ucred *u2); int cr_canseesocket(struct ucred *cred, struct socket *so); -int cr_canseeinpcb(struct ucred *cred, struct inpcb *inp); +int cr_canseeothergids(struct ucred *u1, struct ucred *u2); +int cr_canseeotheruids(struct ucred *u1, struct ucred *u2); char *kern_getenv(const char *name); void freeenv(char *env);