Now pipex(4) is fully covered by NET_LOCK() and this is documented. But
we still have an issue with pipex(4) session itself and I guess it's
time to fix it.

We have `pipexinq' and `pipexoutq' mbuf(9) queues to store mbufs. Each
mbuf(9) passed to these queues stores the pointer to corresponding
session referenced as `m_pkthdr.ph_cookie'. We enqueue incoming mbufs for
pppx(4) and incoming and outgoing mbufs for pppac(4). But we don't
enqueue pppoe related mbufs. After packet was enqueued to corresponding
queue we call schednetisr() which just schedules netisr() to run:

---- cut begin ----

780 pipex_ppp_enqueue(struct mbuf *m0, struct pipex_session *session,
781     struct mbuf_queue *mq)
782 {
783         m0->m_pkthdr.ph_cookie = session;
784         /* XXX need to support other protocols */
785         m0->m_pkthdr.ph_ppp_proto = PPP_IP;
786 
787         if (mq_enqueue(mq, m0) != 0)
788                 return (1);
789 
790         schednetisr(NETISR_PIPEX);
791 
792         return (0);
793 }

---- cut end ----

Also we have pipex_timer() which should destroy session in safe way, but
it does this only for pppac(4) and only for sessions closed by
`PIPEXDSESSION' command:

---- cut begin ----

812 pipex_timer(void *ignored_arg)
813 {
        /* skip */
846                 case PIPEX_STATE_CLOSED:
847                         /*
848                          * mbuf queued in pipexinq or pipexoutq may have a
849                          * refererce to this session.
850                          */
851                         if (!mq_empty(&pipexinq) || !mq_empty(&pipexoutq))
852                                 continue;
853 
854                         pipex_destroy_session(session);
855                         break;

---- cut end ----

While we destroy sessions through pipex_rele_session() or through
pipex_iface_fini() or through `PIPEXSMODE' command we don't check
`pipexinq' and `pipexoutq' state. This means we can break them.

It's not guaranteed that netisr() will start just after schednetisr()
call. This means we can destroy session, but corresponding mbuf(9) is
stored within `pipexinq' or `pipexoutq'. It's `m_pkthdr.ph_cookie' still
stores pointer to destroyed session and we have use after free issue. I
wonder why we didn't caught panic yet.

I propose to kill `pipexinq', `pipexoutq' and pipexintr(). There is
absolutely no reason them to exist. This should not only fix issue
described above but simplifies code too.

Other ways are to implement reference counters for session or walk
through mbuf(9) queues and kill corresponding mbufs. It doesn't make
sense to go these ways.

Index: lib/libc/sys/sysctl.2
===================================================================
RCS file: /cvs/src/lib/libc/sys/sysctl.2,v
retrieving revision 1.40
diff -u -p -r1.40 sysctl.2
--- lib/libc/sys/sysctl.2       17 May 2020 05:48:39 -0000      1.40
+++ lib/libc/sys/sysctl.2       29 Jul 2020 13:47:40 -0000
@@ -2033,35 +2033,11 @@ The currently defined variable names are
 .Bl -column "Third level name" "integer" "Changeable" -offset indent
 .It Sy "Third level name" Ta Sy "Type" Ta Sy "Changeable"
 .It Dv PIPEXCTL_ENABLE Ta integer Ta yes
-.It Dv PIPEXCTL_INQ Ta node Ta not applicable
-.It Dv PIPEXCTL_OUTQ Ta node Ta not applicable
 .El
 .Bl -tag -width "123456"
 .It Dv PIPEXCTL_ENABLE
 If set to 1, enable PIPEX processing.
 The default is 0.
-.It Dv PIPEXCTL_INQ Pq Va net.pipex.inq
-Fourth level comprises an array of
-.Vt struct ifqueue
-structures containing information about the PIPEX packet input queue.
-The forth level names for the elements of
-.Vt struct ifqueue
-are the same as described in
-.Li ip.arpq
-in the
-.Dv PF_INET
-section.
-.It Dv PIPEXCTL_OUTQ Pq Va net.pipex.outq
-Fourth level comprises an array of
-.Vt struct ifqueue
-structures containing information about PIPEX packet output queue.
-The forth level names for the elements of
-.Vt struct ifqueue
-are the same as described in
-.Li ip.arpq
-in the
-.Dv PF_INET
-section.
 .El
 .El
 .Ss CTL_VFS
Index: sys/net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.616
diff -u -p -r1.616 if.c
--- sys/net/if.c        24 Jul 2020 18:17:14 -0000      1.616
+++ sys/net/if.c        29 Jul 2020 13:47:44 -0000
@@ -909,13 +909,6 @@ if_netisr(void *unused)
                        KERNEL_UNLOCK();
                }
 #endif
-#ifdef PIPEX
-               if (n & (1 << NETISR_PIPEX)) {
-                       KERNEL_LOCK();
-                       pipexintr();
-                       KERNEL_UNLOCK();
-               }
-#endif
                t |= n;
        }
 
Index: sys/net/netisr.h
===================================================================
RCS file: /cvs/src/sys/net/netisr.h,v
retrieving revision 1.51
diff -u -p -r1.51 netisr.h
--- sys/net/netisr.h    6 Aug 2019 22:57:54 -0000       1.51
+++ sys/net/netisr.h    29 Jul 2020 13:47:44 -0000
@@ -48,7 +48,6 @@
 #define        NETISR_IPV6     24              /* same as AF_INET6 */
 #define        NETISR_ISDN     26              /* same as AF_E164 */
 #define        NETISR_PPP      28              /* for PPP processing */
-#define        NETISR_PIPEX    27              /* for pipex processing */
 #define        NETISR_BRIDGE   29              /* for bridge processing */
 #define        NETISR_PPPOE    30              /* for pppoe processing */
 #define        NETISR_SWITCH   31              /* for switch dataplane */
@@ -68,7 +67,6 @@ void  bridgeintr(void);
 void   pppoeintr(void);
 void   switchintr(void);
 void   pfsyncintr(void);
-void   pipexintr(void);
 
 #define        schednetisr(anisr)                                              
\
 do {                                                                   \
Index: sys/net/pipex.c
===================================================================
RCS file: /cvs/src/sys/net/pipex.c,v
retrieving revision 1.122
diff -u -p -r1.122 pipex.c
--- sys/net/pipex.c     29 Jul 2020 12:09:31 -0000      1.122
+++ sys/net/pipex.c     29 Jul 2020 13:47:44 -0000
@@ -102,10 +102,6 @@ struct radix_node_head     *pipex_rd_head6 =
 struct timeout pipex_timer_ch;         /* callout timer context */
 int pipex_prune = 1;                   /* [I] walk list every seconds */
 
-/* pipex traffic queue */
-struct mbuf_queue pipexinq = MBUF_QUEUE_INITIALIZER(IFQ_MAXLEN, IPL_NET);
-struct mbuf_queue pipexoutq = MBUF_QUEUE_INITIALIZER(IFQ_MAXLEN, IPL_NET);
-
 /* borrow an mbuf pkthdr field */
 #define ph_ppp_proto ether_vtag
 
@@ -725,82 +721,6 @@ pipex_lookup_by_session_id(int protocol,
 }
 
 /***********************************************************************
- * Queue and Software Interrupt Handler
- ***********************************************************************/
-void
-pipexintr(void)
-{
-       struct pipex_session *pkt_session;
-       u_int16_t proto;
-       struct mbuf *m;
-       struct mbuf_list ml;
-
-       /* ppp output */
-       mq_delist(&pipexoutq, &ml);
-       while ((m = ml_dequeue(&ml)) != NULL) {
-               pkt_session = m->m_pkthdr.ph_cookie;
-               if (pkt_session == NULL) {
-                       m_freem(m);
-                       continue;
-               }
-               proto = m->m_pkthdr.ph_ppp_proto;
-
-               m->m_pkthdr.ph_cookie = NULL;
-               m->m_pkthdr.ph_ppp_proto = 0;
-
-               if (pkt_session->is_multicast != 0) {
-                       struct pipex_session *session;
-                       struct mbuf *m0;
-
-                       LIST_FOREACH(session, &pipex_session_list,
-                           session_list) {
-                               if (session->pipex_iface !=
-                                   pkt_session->pipex_iface)
-                                       continue;
-                               if (session->ip_forward == 0 &&
-                                   session->ip6_forward == 0)
-                                       continue;
-                               m0 = m_copym(m, 0, M_COPYALL, M_NOWAIT);
-                               if (m0 == NULL) {
-                                       session->stat.oerrors++;
-                                       continue;
-                               }
-                               pipex_ppp_output(m0, session, proto);
-                       }
-                       m_freem(m);
-               } else
-                       pipex_ppp_output(m, pkt_session, proto);
-       }
-
-       /* ppp input */
-       mq_delist(&pipexinq, &ml);
-       while ((m = ml_dequeue(&ml)) != NULL) {
-               pkt_session = m->m_pkthdr.ph_cookie;
-               if (pkt_session == NULL) {
-                       m_freem(m);
-                       continue;
-               }
-               pipex_ppp_input(m, pkt_session, 0);
-       }
-}
-
-Static int
-pipex_ppp_enqueue(struct mbuf *m0, struct pipex_session *session,
-    struct mbuf_queue *mq)
-{
-       m0->m_pkthdr.ph_cookie = session;
-       /* XXX need to support other protocols */
-       m0->m_pkthdr.ph_ppp_proto = PPP_IP;
-
-       if (mq_enqueue(mq, m0) != 0)
-               return (1);
-
-       schednetisr(NETISR_PIPEX);
-
-       return (0);
-}
-
-/***********************************************************************
  * Timer functions
  ***********************************************************************/
 Static void
@@ -852,13 +772,6 @@ pipex_timer(void *ignored_arg)
                        /* FALLTHROUGH */
 
                case PIPEX_STATE_CLOSED:
-                       /*
-                        * mbuf queued in pipexinq or pipexoutq may have a
-                        * refererce to this session.
-                        */
-                       if (!mq_empty(&pipexinq) || !mq_empty(&pipexoutq))
-                               continue;
-
                        pipex_destroy_session(session);
                        break;
 
@@ -958,12 +871,29 @@ pipex_ip_output(struct mbuf *m0, struct 
                        if (m0 == NULL)
                                goto dropped;
                }
-       } else
+
+               pipex_ppp_output(m0, session, PPP_IP);
+       } else {
+               struct pipex_session *session_tmp;
+               struct mbuf *m;
+
                m0->m_flags &= ~(M_BCAST|M_MCAST);
 
-       /* output ip packets to the session tunnel */
-       if (pipex_ppp_enqueue(m0, session, &pipexoutq))
-               goto dropped;
+               LIST_FOREACH(session_tmp, &pipex_session_list, session_list) {
+                       if (session_tmp->pipex_iface != session->pipex_iface)
+                               continue;
+                       if (session_tmp->ip_forward == 0 &&
+                           session_tmp->ip6_forward == 0)
+                               continue;
+                       m = m_copym(m0, 0, M_COPYALL, M_NOWAIT);
+                       if (m == NULL) {
+                               session_tmp->stat.oerrors++;
+                               continue;
+                       }
+                       pipex_ppp_output(m, session_tmp, PPP_IP);
+               }
+               m_freem(m0);
+       }
 
        return;
 drop:
@@ -1241,7 +1171,7 @@ drop:
 
 Static struct mbuf *
 pipex_common_input(struct pipex_session *session, struct mbuf *m0, int hlen,
-    int plen, int useq)
+    int plen)
 {
        int proto, ppphlen;
        u_char code;
@@ -1289,19 +1219,12 @@ pipex_common_input(struct pipex_session 
                        m_adj(m0, plen - m0->m_pkthdr.len);
        }
 
-       if (!useq) {
-               pipex_ppp_input(m0, session, 0);
-               return (NULL);
-       }
+       pipex_ppp_input(m0, session, 0);
+
+       return (NULL);
 
-       /* input ppp packets to kernel session */
-       if (pipex_ppp_enqueue(m0, session, &pipexinq) != 0)
-               goto dropped;
-       else
-               return (NULL);
 drop:
        m_freem(m0);
-dropped:
        session->stat.ierrors++;
        return (NULL);
 
@@ -1398,7 +1321,7 @@ pipex_pppoe_input(struct mbuf *m0, struc
            sizeof(struct pipex_pppoe_header), (caddr_t)&pppoe);
 
        hlen = sizeof(struct ether_header) + sizeof(struct pipex_pppoe_header);
-       if ((m0 = pipex_common_input(session, m0, hlen, ntohs(pppoe.length), 0))
+       if ((m0 = pipex_common_input(session, m0, hlen, ntohs(pppoe.length)))
            == NULL)
                return (NULL);
        m_freem(m0);
@@ -1694,7 +1617,7 @@ pipex_pptp_input(struct mbuf *m0, struct
                        pipex_pptp_output(NULL, session, 0, 1);
        }
 
-       if ((m0 = pipex_common_input(session, m0, hlen, ntohs(gre->len), 1))
+       if ((m0 = pipex_common_input(session, m0, hlen, ntohs(gre->len)))
            == NULL) {
                /* ok,  The packet is for PIPEX */
                if (!rewind)
@@ -2129,7 +2052,7 @@ pipex_l2tp_input(struct mbuf *m0, int of
 
        length -= hlen + offset;
        hlen += off0 + offset;
-       if ((m0 = pipex_common_input(session, m0, hlen, length, 1)) == NULL) {
+       if ((m0 = pipex_common_input(session, m0, hlen, length)) == NULL) {
                /* ok,  The packet is for PIPEX */
                if (!rewind)
                        session->proto.l2tp.nr_gap += nseq;
@@ -3052,12 +2975,6 @@ pipex_sysctl(int *name, u_int namelen, v
                        return (ENOTDIR);
                return (sysctl_int(oldp, oldlenp, newp, newlen,
                    &pipex_enable));
-       case PIPEXCTL_INQ:
-               return (sysctl_mq(name + 1, namelen - 1,
-                   oldp, oldlenp, newp, newlen, &pipexinq));
-       case PIPEXCTL_OUTQ:
-               return (sysctl_mq(name + 1, namelen - 1,
-                   oldp, oldlenp, newp, newlen, &pipexoutq));
        default:
                return (ENOPROTOOPT);
        }
Index: sys/net/pipex.h
===================================================================
RCS file: /cvs/src/sys/net/pipex.h,v
retrieving revision 1.26
diff -u -p -r1.26 pipex.h
--- sys/net/pipex.h     29 Jul 2020 12:09:31 -0000      1.26
+++ sys/net/pipex.h     29 Jul 2020 13:47:44 -0000
@@ -33,15 +33,11 @@
  * Names for pipex sysctl objects
  */
 #define PIPEXCTL_ENABLE                1
-#define PIPEXCTL_INQ           2
-#define PIPEXCTL_OUTQ          3
-#define PIPEXCTL_MAXID         4
+#define PIPEXCTL_MAXID         2
 
 #define PIPEXCTL_NAMES { \
         { 0, 0 }, \
         { "enable", CTLTYPE_INT }, \
-        { "inq", CTLTYPE_NODE }, \
-        { "outq", CTLTYPE_NODE }, \
 }
 
 #define PIPEX_PROTO_L2TP               1       /* protocol L2TP */
Index: sys/net/pipex_local.h
===================================================================
RCS file: /cvs/src/sys/net/pipex_local.h,v
retrieving revision 1.38
diff -u -p -r1.38 pipex_local.h
--- sys/net/pipex_local.h       29 Jul 2020 12:09:31 -0000      1.38
+++ sys/net/pipex_local.h       29 Jul 2020 13:47:44 -0000
@@ -403,7 +403,8 @@ void                  pipex_ip_input (st
 #ifdef INET6
 void                  pipex_ip6_input (struct mbuf *, struct pipex_session *);
 #endif
-struct mbuf           *pipex_common_input(struct pipex_session *, struct mbuf 
*, int, int, int);
+struct mbuf           *pipex_common_input(struct pipex_session *,
+                          struct mbuf *, int, int);
 
 #ifdef PIPEX_PPPOE
 void                  pipex_pppoe_output (struct mbuf *, struct pipex_session 
*);

Reply via email to