]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/rtsock.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / bsd / net / rtsock.c
index 2c2ae2dcdb1754ff0ba10eae08d7c65f574bbf54..457eaf4eb35f3ddfb15861e709af4a72dc18ca9e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -75,6 +75,7 @@
 #include <sys/syslog.h>
 #include <sys/mcache.h>
 #include <kern/locks.h>
+#include <sys/codesign.h>
 
 #include <net/if.h>
 #include <net/route.h>
@@ -124,7 +125,7 @@ static int rts_shutdown(struct socket *);
 static int rts_sockaddr(struct socket *, struct sockaddr **);
 
 static int route_output(struct mbuf *, struct socket *);
-static void rt_setmetrics(u_int32_t, struct rt_metrics *, struct rtentry *);
+static int rt_setmetrics(u_int32_t, struct rt_metrics *, struct rtentry *);
 static void rt_getmetrics(struct rtentry *, struct rt_metrics *);
 static void rt_setif(struct rtentry *, struct sockaddr *, struct sockaddr *,
     struct sockaddr *, unsigned int);
@@ -145,6 +146,11 @@ SYSCTL_NODE(_net, PF_ROUTE, routetable, CTLFLAG_RD | CTLFLAG_LOCKED,
 
 SYSCTL_NODE(_net, OID_AUTO, route, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "routing");
 
+/* Align x to 1024 (only power of 2) assuming x is positive */
+#define ALIGN_BYTES(x) do {                                            \
+       x = P2ALIGN(x, 1024);                                           \
+} while(0)
+
 #define        ROUNDUP32(a)                                                    \
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof (uint32_t) - 1))) :        \
        sizeof (uint32_t))
@@ -307,7 +313,7 @@ route_output(struct mbuf *m, struct socket *so)
        int sendonlytoself = 0;
        unsigned int ifscope = IFSCOPE_NONE;
        struct rawcb *rp = NULL;
-
+       boolean_t is_router = FALSE;
 #define        senderr(e) { error = (e); goto flush; }
        if (m == NULL || ((m->m_len < sizeof (intptr_t)) &&
            (m = m_pullup(m, sizeof (intptr_t))) == NULL))
@@ -420,6 +426,22 @@ route_output(struct mbuf *m, struct socket *so)
                        senderr(EINVAL);
                ifscope = rtm->rtm_index;
        }
+       /*
+        * Block changes on INTCOPROC interfaces.
+        */
+       if (ifscope) {
+               unsigned int intcoproc_scope = 0;
+               ifnet_head_lock_shared();
+               TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+                       if (IFNET_IS_INTCOPROC(ifp)) {
+                               intcoproc_scope = ifp->if_index;
+                               break;
+                       }
+               }
+               ifnet_head_done();
+               if (intcoproc_scope == ifscope && current_proc()->p_pid != 0)
+                       senderr(EINVAL);
+       }
 
        /*
         * RTF_PROXY can only be set internally from within the kernel.
@@ -481,7 +503,7 @@ route_output(struct mbuf *m, struct socket *so)
                        rt_setif(saved_nrt,
                            info.rti_info[RTAX_IFP], info.rti_info[RTAX_IFA],
                            info.rti_info[RTAX_GATEWAY], ifscope);
-                       rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, saved_nrt);
+                       (void)rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, saved_nrt);
                        saved_nrt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
                        saved_nrt->rt_rmx.rmx_locks |=
                            (rtm->rtm_inits & rtm->rtm_rmx.rmx_locks);
@@ -526,8 +548,10 @@ route_output(struct mbuf *m, struct socket *so)
                 */
                switch (rtm->rtm_type) {
                case RTM_GET: {
+                       kauth_cred_t cred;
                        struct ifaddr *ifa2;
 report:
+                       cred = kauth_cred_proc_ref(current_proc());
                        ifa2 = NULL;
                        RT_LOCK_ASSERT_HELD(rt);
                        info.rti_info[RTAX_DST] = rt_key(rt);
@@ -556,7 +580,7 @@ report:
                        }
                        if (ifa2 != NULL)
                                IFA_LOCK(ifa2);
-                       len = rt_msg2(rtm->rtm_type, &info, NULL, NULL, NULL);
+                       len = rt_msg2(rtm->rtm_type, &info, NULL, NULL, &cred);
                        if (ifa2 != NULL)
                                IFA_UNLOCK(ifa2);
                        if (len > rtm->rtm_msglen) {
@@ -574,7 +598,7 @@ report:
                        if (ifa2 != NULL)
                                IFA_LOCK(ifa2);
                        (void) rt_msg2(rtm->rtm_type, &info, (caddr_t)rtm,
-                           NULL, NULL);
+                           NULL, &cred);
                        if (ifa2 != NULL)
                                IFA_UNLOCK(ifa2);
                        rtm->rtm_flags = rt->rt_flags;
@@ -582,10 +606,14 @@ report:
                        rtm->rtm_addrs = info.rti_addrs;
                        if (ifa2 != NULL)
                                IFA_REMREF(ifa2);
+
+                       kauth_cred_unref(&cred);
                        break;
                }
 
                case RTM_CHANGE:
+                       is_router = (rt->rt_flags & RTF_ROUTER) ? TRUE : FALSE;
+
                        if (info.rti_info[RTAX_GATEWAY] != NULL &&
                            (error = rt_setgate(rt, rt_key(rt),
                            info.rti_info[RTAX_GATEWAY]))) {
@@ -598,7 +626,7 @@ report:
                         * the required gateway, then just use the old one.
                         * This can happen if the user tries to change the
                         * flags on the default route without changing the
-                        * default gateway.  Changing flags still doesn't work.
+                        * default gateway. Changing flags still doesn't work.
                         */
                        if ((rt->rt_flags & RTF_GATEWAY) &&
                            info.rti_info[RTAX_GATEWAY] == NULL)
@@ -613,9 +641,32 @@ report:
                            info.rti_info[RTAX_IFP], info.rti_info[RTAX_IFA],
                            info.rti_info[RTAX_GATEWAY], ifscope);
 
-                       rt_setmetrics(rtm->rtm_inits, &rtm->rtm_rmx, rt);
+                       if ((error = rt_setmetrics(rtm->rtm_inits,
+                           &rtm->rtm_rmx, rt))) {
+                                int tmp = error;
+                                RT_UNLOCK(rt);
+                                senderr(tmp);
+                       }
                        if (info.rti_info[RTAX_GENMASK])
                                rt->rt_genmask = info.rti_info[RTAX_GENMASK];
+
+                       /*
+                        * Enqueue work item to invoke callback for this route entry
+                        * This may not be needed always, but for now issue it anytime
+                        * RTM_CHANGE gets called.
+                        */
+                       route_event_enqueue_nwk_wq_entry(rt, NULL, ROUTE_ENTRY_REFRESH, NULL, TRUE);
+                       /*
+                        * If the route is for a router, walk the tree to send refresh
+                        * event to protocol cloned entries
+                        */
+                       if (is_router) {
+                               struct route_event rt_ev;
+                               route_event_init(&rt_ev, rt, NULL, ROUTE_ENTRY_REFRESH);
+                               RT_UNLOCK(rt);
+                               (void) rnh->rnh_walktree(rnh, route_event_walktree, (void *)&rt_ev);
+                               RT_LOCK(rt);
+                       }
                        /* FALLTHRU */
                case RTM_LOCK:
                        rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
@@ -705,41 +756,54 @@ rt_setexpire(struct rtentry *rt, uint64_t expiry)
        }
 }
 
-static void
+static int
 rt_setmetrics(u_int32_t which, struct rt_metrics *in, struct rtentry *out)
 {
-       struct timeval caltime;
-
-       getmicrotime(&caltime);
-
+       if (!(which & RTV_REFRESH_HOST)) {
+               struct timeval caltime;
+               getmicrotime(&caltime);
 #define        metric(f, e) if (which & (f)) out->rt_rmx.e = in->e;
-       metric(RTV_RPIPE, rmx_recvpipe);
-       metric(RTV_SPIPE, rmx_sendpipe);
-       metric(RTV_SSTHRESH, rmx_ssthresh);
-       metric(RTV_RTT, rmx_rtt);
-       metric(RTV_RTTVAR, rmx_rttvar);
-       metric(RTV_HOPCOUNT, rmx_hopcount);
-       metric(RTV_MTU, rmx_mtu);
-       metric(RTV_EXPIRE, rmx_expire);
+               metric(RTV_RPIPE, rmx_recvpipe);
+               metric(RTV_SPIPE, rmx_sendpipe);
+               metric(RTV_SSTHRESH, rmx_ssthresh);
+               metric(RTV_RTT, rmx_rtt);
+               metric(RTV_RTTVAR, rmx_rttvar);
+               metric(RTV_HOPCOUNT, rmx_hopcount);
+               metric(RTV_MTU, rmx_mtu);
+               metric(RTV_EXPIRE, rmx_expire);
 #undef metric
+               if (out->rt_rmx.rmx_expire > 0) {
+                       /* account for system time change */
+                       getmicrotime(&caltime);
+                       out->base_calendartime +=
+                               NET_CALCULATE_CLOCKSKEW(caltime,
+                                               out->base_calendartime,
+                                               net_uptime(), out->base_uptime);
+                       rt_setexpire(out,
+                                       out->rt_rmx.rmx_expire -
+                                       out->base_calendartime +
+                                       out->base_uptime);
+               } else {
+                       rt_setexpire(out, 0);
+               }
 
-       if (out->rt_rmx.rmx_expire > 0) {
-               /* account for system time change */
-               getmicrotime(&caltime);
-               out->base_calendartime +=
-                   NET_CALCULATE_CLOCKSKEW(caltime,
-                   out->base_calendartime,
-                   net_uptime(), out->base_uptime);
-               rt_setexpire(out,
-                   out->rt_rmx.rmx_expire -
-                   out->base_calendartime +
-                   out->base_uptime);
+               VERIFY(out->rt_expire == 0 || out->rt_rmx.rmx_expire != 0);
+               VERIFY(out->rt_expire != 0 || out->rt_rmx.rmx_expire == 0);
        } else {
-               rt_setexpire(out, 0);
-       }
+               /* Only RTV_REFRESH_HOST must be set */
+               if ((which & ~RTV_REFRESH_HOST) ||
+                   (out->rt_flags & RTF_STATIC) ||
+                   !(out->rt_flags & RTF_LLINFO)) {
+                       return (EINVAL);
+               }
+
+               if (out->rt_llinfo_refresh == NULL) {
+                       return (ENOTSUP);
+               }
 
-       VERIFY(out->rt_expire == 0 || out->rt_rmx.rmx_expire != 0);
-       VERIFY(out->rt_expire != 0 || out->rt_rmx.rmx_expire == 0);
+               out->rt_llinfo_refresh(out);
+       }
+       return (0);
 }
 
 static void
@@ -779,7 +843,7 @@ rt_setif(struct rtentry *rt, struct sockaddr *Ifpaddr, struct sockaddr *Ifaaddr,
        struct ifnet *ifp = NULL;
        void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *);
 
-       lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(rnh_lock, LCK_MTX_ASSERT_OWNED);
 
        RT_LOCK_ASSERT_HELD(rt);
 
@@ -983,7 +1047,7 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo)
        struct rt_msghdr *rtm;
        struct mbuf *m;
        int i;
-       int len, dlen;
+       int len, dlen, off;
 
        switch (type) {
 
@@ -1004,8 +1068,6 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo)
        default:
                len = sizeof (struct rt_msghdr);
        }
-       if (len > MCLBYTES)
-               panic("rt_msg1");
        m = m_gethdr(M_DONTWAIT, MT_DATA);
        if (m && len > MHLEN) {
                MCLGET(m, M_DONTWAIT);
@@ -1020,6 +1082,7 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo)
        m->m_pkthdr.rcvif = NULL;
        rtm = mtod(m, struct rt_msghdr *);
        bzero((caddr_t)rtm, len);
+       off = len;
        for (i = 0; i < RTAX_MAX; i++) {
                struct sockaddr *sa, *hint;
                uint8_t ssbuf[SOCK_MAXADDRLEN + 1];
@@ -1048,9 +1111,10 @@ rt_msg1(int type, struct rt_addrinfo *rtinfo)
                }
 
                rtinfo->rti_addrs |= (1 << i);
-               dlen = ROUNDUP32(sa->sa_len);
-               m_copyback(m, len, dlen, (caddr_t)sa);
-               len += dlen;
+               dlen = sa->sa_len;
+               m_copyback(m, off, dlen, (caddr_t)sa);
+               len = off + dlen;
+               off += ROUNDUP32(dlen);
        }
        if (m->m_pkthdr.len != len) {
                m_freem(m);
@@ -1067,7 +1131,7 @@ rt_msg2(int type, struct rt_addrinfo *rtinfo, caddr_t cp, struct walkarg *w,
        kauth_cred_t* credp)
 {
        int i;
-       int len, dlen, second_time = 0;
+       int len, dlen, rlen, second_time = 0;
        caddr_t cp0;
 
        rtinfo->rti_addrs = 0;
@@ -1132,7 +1196,7 @@ again:
                        sa = rtm_scrub(type, i, hint, sa, &ssbuf,
                            sizeof (ssbuf), NULL);
                        break;
-
+               case RTAX_GATEWAY:
                case RTAX_IFP:
                        sa = rtm_scrub(type, i, NULL, sa, &ssbuf,
                            sizeof (ssbuf), credp);
@@ -1143,12 +1207,15 @@ again:
                }
 
                rtinfo->rti_addrs |= (1 << i);
-               dlen = ROUNDUP32(sa->sa_len);
+               dlen = sa->sa_len;
+               rlen = ROUNDUP32(dlen);
                if (cp) {
-                       bcopy((caddr_t)sa, cp, (unsigned)dlen);
-                       cp += dlen;
+                       bcopy((caddr_t)sa, cp, (size_t)dlen);
+                       if (dlen != rlen)
+                               bzero(cp + dlen, rlen - dlen);
+                       cp += rlen;
                }
-               len += dlen;
+               len += rlen;
        }
        if (cp == NULL && w != NULL && !second_time) {
                struct walkarg *rw = w;
@@ -1252,7 +1319,7 @@ rt_newaddrmsg(int cmd, struct ifaddr *ifa, int error, struct rtentry *rt)
        struct ifnet *ifp = ifa->ifa_ifp;
        struct sockproto route_proto = { PF_ROUTE, 0 };
 
-       lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
+       LCK_MTX_ASSERT(rnh_lock, LCK_MTX_ASSERT_OWNED);
        RT_LOCK_ASSERT_HELD(rt);
 
        if (route_cb.any_count == 0)
@@ -1574,7 +1641,7 @@ sysctl_iflist(int af, struct walkarg *w)
        struct ifnet *ifp;
        struct ifaddr *ifa;
        struct  rt_addrinfo info;
-       int     len, error = 0;
+       int     len = 0, error = 0;
        int     pass = 0;
        int     total_len = 0, current_len = 0;
        char    *total_buffer = NULL, *cp = NULL;
@@ -1623,6 +1690,14 @@ sysctl_iflist(int af, struct walkarg *w)
                                if_data_internal_to_if_data(ifp, &ifp->if_data,
                                    &ifm->ifm_data);
                                ifm->ifm_addrs = info.rti_addrs;
+                               /*
+                                * <rdar://problem/32940901>
+                                * Round bytes only for non-platform
+                               */
+                               if (!csproc_get_platform_binary(w->w_req->p)) {
+                                       ALIGN_BYTES(ifm->ifm_data.ifi_ibytes);
+                                       ALIGN_BYTES(ifm->ifm_data.ifi_obytes);
+                               }
 
                                cp += len;
                                VERIFY(IS_P2ALIGNED(cp, sizeof (u_int32_t)));
@@ -1716,7 +1791,7 @@ sysctl_iflist2(int af, struct walkarg *w)
        struct ifnet *ifp;
        struct ifaddr *ifa;
        struct  rt_addrinfo info;
-       int     len, error = 0;
+       int     len = 0, error = 0;
        int     pass = 0;
        int     total_len = 0, current_len = 0;
        char    *total_buffer = NULL, *cp = NULL;
@@ -1772,6 +1847,14 @@ sysctl_iflist2(int af, struct walkarg *w)
                                ifm->ifm_timer = ifp->if_timer;
                                if_data_internal_to_if_data64(ifp,
                                    &ifp->if_data, &ifm->ifm_data);
+                               /*
+                                * <rdar://problem/32940901>
+                                * Round bytes only for non-platform
+                               */
+                               if (!csproc_get_platform_binary(w->w_req->p)) {
+                                       ALIGN_BYTES(ifm->ifm_data.ifi_ibytes);
+                                       ALIGN_BYTES(ifm->ifm_data.ifi_obytes);
+                               }
 
                                cp += len;
                                VERIFY(IS_P2ALIGNED(cp, sizeof (u_int32_t)));