Deal with the netgraph NULL function dereference on shutdown()
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 27 Dec 2008 23:10:55 +0000 (15:10 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 27 Dec 2008 23:10:55 +0000 (15:10 -0800)
vulnerability.  Use a solution similar to FreeBSD's.

sys/kern/uipc_domain.c
sys/kern/uipc_socket2.c
sys/sys/protosw.h

index 3a4f184..2b6ca59 100644 (file)
@@ -78,18 +78,45 @@ static struct callout pfslowtimo_ch;
  * Note: you cant unload it again because a socket may be using it.
  * XXX can't fail at this time.
  */
+#define PRU_NOTSUPP(pu, label)         \
+       if (pu->pru_ ## label == NULL)  \
+               pu->pru_ ## label = pru_ ## label ## _notsupp;
+#define PRU_NULL(pu, label)            \
+       if (pu->pru_ ## label == NULL)  \
+               pu->pru_ ## label = pru_ ## label ## _null;
+
 static void
 net_init_domain(struct domain *dp)
 {
        struct protosw *pr;
+       struct pr_usrreqs *pu;
 
        crit_enter();
        if (dp->dom_init)
                (*dp->dom_init)();
        for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
-               if (pr->pr_usrreqs == NULL)
+               pu = pr->pr_usrreqs;
+               if (pu == NULL)
                        panic("domaininit: %ssw[%d] has no usrreqs!",
                              dp->dom_name, pr - dp->dom_protosw);
+               PRU_NOTSUPP(pu, accept);
+               PRU_NOTSUPP(pu, bind);
+               PRU_NOTSUPP(pu, connect);
+               PRU_NOTSUPP(pu, connect2);
+               PRU_NOTSUPP(pu, control);
+               PRU_NOTSUPP(pu, disconnect);
+               PRU_NOTSUPP(pu, listen);
+               PRU_NOTSUPP(pu, peeraddr);
+               PRU_NOTSUPP(pu, rcvd);
+               PRU_NOTSUPP(pu, rcvoob);
+               PRU_NULL(pu, sense);
+               PRU_NOTSUPP(pu, shutdown);
+               PRU_NOTSUPP(pu, sockaddr);
+               PRU_NOTSUPP(pu, sosend);
+               PRU_NOTSUPP(pu, soreceive);
+               PRU_NOTSUPP(pu, sopoll);
+               PRU_NOTSUPP(pu, ctloutput);
+
                if (pr->pr_init)
                        (*pr->pr_init)();
        }
index 07d3550..adb6390 100644 (file)
@@ -460,6 +460,12 @@ pru_accept_notsupp(struct socket *so, struct sockaddr **nam)
        return EOPNOTSUPP;
 }
 
+int
+pru_bind_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
+{
+       return EOPNOTSUPP;
+}
+
 int
 pru_connect_notsupp(struct socket *so, struct sockaddr *nam, struct thread *td)
 {
@@ -479,12 +485,24 @@ pru_control_notsupp(struct socket *so, u_long cmd, caddr_t data,
        return EOPNOTSUPP;
 }
 
+int
+pru_disconnect_notsupp(struct socket *so)
+{
+       return EOPNOTSUPP;
+}
+
 int
 pru_listen_notsupp(struct socket *so, struct thread *td)
 {
        return EOPNOTSUPP;
 }
 
+int
+pru_peeraddr_notsupp(struct socket *so, struct sockaddr **nam)
+{
+       return EOPNOTSUPP;
+}
+
 int
 pru_rcvd_notsupp(struct socket *so, int flags)
 {
@@ -497,6 +515,51 @@ pru_rcvoob_notsupp(struct socket *so, struct mbuf *m, int flags)
        return EOPNOTSUPP;
 }
 
+int
+pru_shutdown_notsupp(struct socket *so)
+{
+       return EOPNOTSUPP;
+}
+
+int
+pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam)
+{
+       return EOPNOTSUPP;
+}
+
+int
+pru_sosend_notsupp(struct socket *so, struct sockaddr *addr, struct uio *uio,
+          struct mbuf *top, struct mbuf *control, int flags,
+          struct thread *td)
+{
+       if (top)
+               m_freem(top);
+       if (control)
+               m_freem(control);
+       return (EOPNOTSUPP);
+}
+
+int
+pru_soreceive_notsupp(struct socket *so, struct sockaddr **paddr,
+                     struct uio *uio, struct sockbuf *sio,
+                     struct mbuf **controlp, int *flagsp)
+{
+       return (EOPNOTSUPP);
+}
+
+int
+pru_sopoll_notsupp(struct socket *so, int events,
+                  struct ucred *cred, struct thread *td)
+{
+       return (EOPNOTSUPP);
+}
+
+int
+pru_ctloutput_notsupp(struct socket *so, struct sockopt *sopt)
+{
+       return (EOPNOTSUPP);
+}
+
 /*
  * This isn't really a ``null'' operation, but it's the default one
  * and doesn't do anything destructive.
index e2df40c..4d971f1 100644 (file)
@@ -104,7 +104,7 @@ struct protosw {
                                        /* slow timeout (500ms) */
        void    (*pr_drain) (void);
                                        /* flush any excess space possible */
-       const struct    pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */
+       struct  pr_usrreqs *pr_usrreqs; /* supersedes pr_usrreq() */
 };
 
 #endif
@@ -299,14 +299,32 @@ typedef   int     (*pru_ctloutput_fn_t) (struct socket *so, struct sockopt *sopt);
 typedef        void (*pru_ctlinput_fn_t) (int cmd, struct sockaddr *arg, void *extra);
 
 int    pru_accept_notsupp (struct socket *so, struct sockaddr **nam);
+int    pru_bind_notsupp (struct socket *so, struct sockaddr *nam,
+                               struct thread *td);
 int    pru_connect_notsupp (struct socket *so, struct sockaddr *nam,
                                struct thread *td);
 int    pru_connect2_notsupp (struct socket *so1, struct socket *so2);
 int    pru_control_notsupp (struct socket *so, u_long cmd, caddr_t data,
                                struct ifnet *ifp, struct thread *td);
+int    pru_disconnect_notsupp (struct socket *so);
 int    pru_listen_notsupp (struct socket *so, struct thread *td);
+int    pru_peeraddr_notsupp (struct socket *so, struct sockaddr **nam);
 int    pru_rcvd_notsupp (struct socket *so, int flags);
 int    pru_rcvoob_notsupp (struct socket *so, struct mbuf *m, int flags);
+int    pru_shutdown_notsupp(struct socket *so);
+int    pru_sockaddr_notsupp(struct socket *so, struct sockaddr **nam);
+int    pru_sosend_notsupp(struct socket *so, struct sockaddr *addr,
+                               struct uio *uio, struct mbuf *top,
+                               struct mbuf *control, int flags,
+                               struct thread *td);
+int    pru_soreceive_notsupp(struct socket *so,
+                               struct sockaddr **paddr,
+                               struct uio *uio,
+                               struct sockbuf *sio,
+                               struct mbuf **controlp, int *flagsp);
+int    pru_sopoll_notsupp(struct socket *so, int events,
+                               struct ucred *cred, struct thread *td);
+int    pru_ctloutput_notsupp(struct socket *so, struct sockopt *sopt);
 int    pru_sense_null (struct socket *so, struct stat *sb);
 
 struct lwkt_port *cpu0_soport(struct socket *, struct sockaddr *,