On Sat, Aug 01, 2020 at 07:44:17PM +0900, YASUOKA Masahiko wrote:
> Hi,
> 
> I'm not sure when it is broken, in old versions, it was assumed the
> pipex queues are empty when pipex_iface_stop() is called.  The problem
> mvs@ found is the assumption is not true any more.
> 
> pipex has a mechanism that delete a session when the queues are empty.
> 
>     819 Static void
>     820 pipex_timer(void *ignored_arg)
>     821 {
>     (snip)
>     854                 case PIPEX_STATE_CLOSED:
>     855                         /*
>     856                          * mbuf queued in pipexinq or pipexoutq may 
> have a
>     857                          * refererce to this session.
>     858                          */
>     859                         if (!mq_empty(&pipexinq) || 
> !mq_empty(&pipexoutq))
>     860                                 continue;
>     861 
>     862                         pipex_destroy_session(session);
>     863                         break;
> 
> I think using this is better.
> 
> How about this?
> 

Unfortunately your diff is incorrect. It introduces memory leaks and
breaks pppx(4). Also it is incomplete.

We have multiple ways to kill pipex(sessions):

1. pppx(4)

We have `struct pppx_if' which has pointer to corresponding session and
this session is accessed directly within pppx(4) layer. Since we can't
destroy `ppp_if' in pipex(4) layer we can't destroy these sessions by
pipex_timer(). The only way to destroy them is pppx_if_destroy() which:

1. unlink session by pipex_unlink_session()
2. detach corresponding `ifnet' by if_detach()
3. release session by pipex_rele_session() 

It's unsafe because mbuf queues can have references to this session.

2. pppac(4)

We have no direct access to corresponding sessions within pppac(4)
layer. Also there are multiple ways to do this:

1. pipex_ioctl() with `PIPEXSMODE' command. Underlay pipex_iface_stop()
walks through `pipex_session_list' and destroy sessions by
pipex_destroy_session() call. It's unsafe because we don't check queues.

2. pipex_ioctl() with `PIPEXDSESSION'. pipex_close_session() will change
session's  state and pipex_timer() will kill this sessions later. This
is the only safe way.

3. pipex_iface_fini(). The same as `PIPEXSMODE', pipex_iface_stop()
kills sessions, Which is also unsafe. Also we have another use after
free issue:

---- cut begin ----

pipex_iface_fini(struct pipex_iface_context *pipex_iface)
{
        pool_put(&pipex_session_pool, pipex_iface->multicast_session);
        NET_LOCK();
        pipex_iface_stop(pipex_iface);
        NET_UNLOCK();
}

---- cut end ----

`multicast_session' should be protected too. It also can be pushed to
`pipexoutq'. Also since this time pipexintr() and pipex_iface_fini() are
both serialized by KERNEL_LOCK() too we can't destroy `multicast_session'
which is in use by pipexintr(). But when we will drop KERNEL_LOCK()
around pipexintr() we can catch use after free issue here. I already did
diff for move this pool_put() under NET_LOCK(), but it was rejectedi by
mpi@ because:

---- cut begin ----
pipex_iface_fini() should be called on the last reference of the                
descriptor.  So this shouldn't be necessary.  If there's an issue               
with the current order of the operations, we should certainly fix               
it differently.   
---- cut end ----

So I repeat it again: npppd(8) can be killed in every moment by SIGKILL
or by SIGSEGV and pppacclose() will be called and it will call
pipex_iface_fini(). `multicast_session' can be used in this moment by
pipexintr().

And no locks protect `multicast_session' itself.

The two diffs I proposed in this thread solve problems caused by
pipexintr().

I'm not sure about bottleneck in crypto thread, because we have no
simultaneous execution with pipexintr(), but the second diff which
introduces refcounters does session destruction well, include
`multicast_session'. I found a little issue with second diff which stops
processing multicast packets, so I included updated version below.

> diff --git a/sys/net/pipex.c b/sys/net/pipex.c
> index 2ad7757fee9..6fe14c400bf 100644
> --- a/sys/net/pipex.c
> +++ b/sys/net/pipex.c
> @@ -190,7 +190,7 @@ pipex_iface_stop(struct pipex_iface_context *pipex_iface)
>       LIST_FOREACH_SAFE(session, &pipex_session_list, session_list,
>           session_tmp) {
>               if (session->pipex_iface == pipex_iface)
> -                     pipex_destroy_session(session);
> +                     pipex_unlink_session(session);

You assumed pipex_timer() the only place where sessions can be released?
pipex_unlink_session() will detach session from all lists, include
`pipex_session_list'. This session is leaked.

Also what to do with multicast sessions?

>       }
>  }
>  
> @@ -470,9 +470,16 @@ pipex_link_session(struct pipex_session *session,
>  void
>  pipex_unlink_session(struct pipex_session *session)
>  {
> +     struct radix_node *rn;
> +
>       session->ifindex = 0;
>  
>       NET_ASSERT_LOCKED();
> +     if (!in_nullhost(session->ip_address.sin_addr)) {
> +             rn = rn_delete(&session->ip_address, &session->ip_netmask,
> +                 pipex_rd_head4, (struct radix_node *)session);
> +             KASSERT(rn != NULL);
> +     }

pppx(4) has no sessions in radix tree. We will panic here.

>       LIST_REMOVE(session, id_chain);
>  #if defined(PIPEX_PPTP) || defined(PIPEX_L2TP)
>       switch (session->protocol) {
> @@ -486,10 +493,6 @@ pipex_unlink_session(struct pipex_session *session)
>               LIST_REMOVE(session, state_list);
>       LIST_REMOVE(session, session_list);
>       session->state = PIPEX_STATE_CLOSED;
> -
> -     /* if final session is destroyed, stop timer */
> -     if (LIST_EMPTY(&pipex_session_list))
> -             pipex_timer_stop();
>  }
>  
>  Static int
> @@ -652,20 +655,16 @@ pipex_get_closed(struct pipex_session_list_req *req,
>  Static int
>  pipex_destroy_session(struct pipex_session *session)
>  {
> -     struct radix_node *rn;
> -
>       /* remove from radix tree and hash chain */
>       NET_ASSERT_LOCKED();
>  
> -     if (!in_nullhost(session->ip_address.sin_addr)) {
> -             rn = rn_delete(&session->ip_address, &session->ip_netmask,
> -                 pipex_rd_head4, (struct radix_node *)session);
> -             KASSERT(rn != NULL);
> -     }
> -
>       pipex_unlink_session(session);
>       pipex_rele_session(session);
>  
> +     /* if final session is destroyed, stop timer */
> +     if (LIST_EMPTY(&pipex_session_list))
> +             pipex_timer_stop();
> +
>       return (0);
>  }
>  
> @@ -739,7 +738,8 @@ pipexintr(void)
>       mq_delist(&pipexoutq, &ml);
>       while ((m = ml_dequeue(&ml)) != NULL) {
>               pkt_session = m->m_pkthdr.ph_cookie;
> -             if (pkt_session == NULL) {
> +             if (pkt_session == NULL ||
> +                 pkt_session->state == PIPEX_STATE_CLOSED) {
>                       m_freem(m);
>                       continue;
>               }

Multicast sessions state never changed, so this checks is wrong for
them.

> @@ -776,7 +776,8 @@ pipexintr(void)
>       mq_delist(&pipexinq, &ml);
>       while ((m = ml_dequeue(&ml)) != NULL) {
>               pkt_session = m->m_pkthdr.ph_cookie;
> -             if (pkt_session == NULL) {
> +             if (pkt_session == NULL ||
> +                 pkt_session->state == PIPEX_STATE_CLOSED) {
>                       m_freem(m);
>                       continue;
>               }
> 

Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.266
diff -u -p -r1.266 if_ethersubr.c
--- sys/net/if_ethersubr.c      22 Jul 2020 02:16:01 -0000      1.266
+++ sys/net/if_ethersubr.c      1 Aug 2020 15:49:36 -0000
@@ -527,6 +527,7 @@ ether_input(struct ifnet *ifp, struct mb
 
                        if ((session = pipex_pppoe_lookup_session(m)) != NULL) {
                                pipex_pppoe_input(m, session);
+                               pipex_rele_session(session);
                                return;
                        }
                }
Index: sys/net/if_gre.c
===================================================================
RCS file: /cvs/src/sys/net/if_gre.c,v
retrieving revision 1.158
diff -u -p -r1.158 if_gre.c
--- sys/net/if_gre.c    10 Jul 2020 13:26:41 -0000      1.158
+++ sys/net/if_gre.c    1 Aug 2020 15:49:36 -0000
@@ -984,9 +984,15 @@ gre_input_1(struct gre_tunnel *key, stru
                        struct pipex_session *session;
 
                        session = pipex_pptp_lookup_session(m);
-                       if (session != NULL &&
-                           pipex_pptp_input(m, session) == NULL)
-                               return (NULL);
+                       if (session != NULL) {
+                               struct mbuf *m0;
+
+                               m0 = pipex_pptp_input(m, session);
+                               pipex_rele_session(session);
+
+                               if (m0 == NULL)
+                                       return NULL;
+                       }
                }
 #endif
                break;
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     1 Aug 2020 15:49:36 -0000
@@ -165,6 +165,8 @@ pipex_iface_init(struct pipex_iface_cont
 
        /* virtual pipex_session entry for multicast */
        session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO);
+       session->refs = 1;
+       session->state = PIPEX_STATE_INITIAL;
        session->is_multicast = 1;
        session->pipex_iface = pipex_iface;
        session->ifindex = ifindex;
@@ -175,6 +177,7 @@ Static void
 pipex_iface_start(struct pipex_iface_context *pipex_iface)
 {
        pipex_iface->pipexmode = 1;
+       pipex_iface->multicast_session->state = PIPEX_STATE_OPENED;
 }
 
 Static void
@@ -183,6 +186,7 @@ pipex_iface_stop(struct pipex_iface_cont
        struct pipex_session *session, *session_tmp;
 
        pipex_iface->pipexmode = 0;
+       pipex_iface->multicast_session->state = PIPEX_STATE_CLOSED;
        /*
         * traversal all pipex sessions.
         * it will become heavy if the number of pppac devices bocomes large.
@@ -197,9 +201,9 @@ pipex_iface_stop(struct pipex_iface_cont
 void
 pipex_iface_fini(struct pipex_iface_context *pipex_iface)
 {
-       pool_put(&pipex_session_pool, pipex_iface->multicast_session);
        NET_LOCK();
        pipex_iface_stop(pipex_iface);
+       pipex_rele_session(pipex_iface->multicast_session);
        NET_UNLOCK();
 }
 
@@ -329,6 +333,7 @@ pipex_init_session(struct pipex_session 
 
        /* prepare a new session */
        session = pool_get(&pipex_session_pool, PR_WAITOK | PR_ZERO);
+       session->refs = 1;
        session->state = PIPEX_STATE_INITIAL;
        session->protocol = req->pr_protocol;
        session->session_id = req->pr_session_id;
@@ -421,9 +426,20 @@ pipex_init_session(struct pipex_session 
        return 0;
 }
 
+void pipex_ref_session(struct pipex_session *session)
+{
+       atomic_inc_int_nv(&session->refs);
+       KASSERT(session->refs != 0);
+}
+
 void
 pipex_rele_session(struct pipex_session *session)
 {
+       KASSERT(session->refs > 0);
+
+       if (atomic_dec_int_nv(&session->refs) > 0)
+               return;
+
        if (session->mppe_recv.old_session_keys)
                pool_put(&mppe_key_pool, session->mppe_recv.old_session_keys);
        pool_put(&pipex_session_pool, session);
@@ -439,10 +455,12 @@ pipex_link_session(struct pipex_session 
 
        if (!iface->pipexmode)
                return (ENXIO);
-       if (pipex_lookup_by_session_id(session->protocol,
+       if (pipex_lookup_by_session_id_nonref(session->protocol,
            session->session_id))
                return (EEXIST);
 
+       pipex_ref_session(session);
+
        session->pipex_iface = iface;
        session->ifindex = iface->ifindex;
 
@@ -490,6 +508,8 @@ pipex_unlink_session(struct pipex_sessio
        /* if final session is destroyed, stop timer */
        if (LIST_EMPTY(&pipex_session_list))
                pipex_timer_stop();
+
+       pipex_rele_session(session);
 }
 
 Static int
@@ -505,8 +525,8 @@ pipex_add_session(struct pipex_session_r
 
        /* commit the session */
        if (!in_nullhost(session->ip_address.sin_addr)) {
-               if (pipex_lookup_by_ip_address(session->ip_address.sin_addr)
-                   != NULL) {
+               if (pipex_lookup_by_ip_address_nonref(
+                   session->ip_address.sin_addr) != NULL) {
                        error = EADDRINUSE;
                        goto free;
                }
@@ -568,6 +588,7 @@ pipex_close_session(struct pipex_session
     struct pipex_iface_context *iface)
 {
        struct pipex_session *session;
+       int error = 0;
 
        NET_ASSERT_LOCKED();
        session = pipex_lookup_by_session_id(req->pcr_protocol,
@@ -575,17 +596,20 @@ pipex_close_session(struct pipex_session
        if (session == NULL)
                return (EINVAL);
        if (session->pipex_iface != iface)
-               return (EINVAL);
-
-       /* remove from close_wait list */
-       if (session->state == PIPEX_STATE_CLOSE_WAIT)
-               LIST_REMOVE(session, state_list);
+               error = EINVAL;
+       else {
+               /* remove from close_wait list */
+               if (session->state == PIPEX_STATE_CLOSE_WAIT)
+                       LIST_REMOVE(session, state_list);
+
+               /* get statistics before destroy the session */
+               req->pcr_stat = session->stat;
+               session->state = PIPEX_STATE_CLOSED;
+       }
 
-       /* get statistics before destroy the session */
-       req->pcr_stat = session->stat;
-       session->state = PIPEX_STATE_CLOSED;
+       pipex_rele_session(session);
 
-       return (0);
+       return (error);
 }
 
 Static int
@@ -593,6 +617,7 @@ pipex_config_session(struct pipex_sessio
     struct pipex_iface_context *iface)
 {
        struct pipex_session *session;
+       int error = 0;
 
        NET_ASSERT_LOCKED();
        session = pipex_lookup_by_session_id(req->pcr_protocol,
@@ -600,10 +625,13 @@ pipex_config_session(struct pipex_sessio
        if (session == NULL)
                return (EINVAL);
        if (session->pipex_iface != iface)
-               return (EINVAL);
-       session->ip_forward = req->pcr_ip_forward;
+               error = EINVAL;
+       else
+               session->ip_forward = req->pcr_ip_forward;
 
-       return (0);
+       pipex_rele_session(session);
+
+       return (error);
 }
 
 Static int
@@ -611,6 +639,7 @@ pipex_get_stat(struct pipex_session_stat
     struct pipex_iface_context *iface)
 {
        struct pipex_session *session;
+       int error = 0;
 
        NET_ASSERT_LOCKED();
        session = pipex_lookup_by_session_id(req->psr_protocol,
@@ -618,10 +647,13 @@ pipex_get_stat(struct pipex_session_stat
        if (session == NULL)
                return (EINVAL);
        if (session->pipex_iface != iface)
-               return (EINVAL);
-       req->psr_stat = session->stat;
+               error = EINVAL;
+       else
+               req->psr_stat = session->stat;
 
-       return (0);
+       pipex_rele_session(session);
+
+       return (error);
 }
 
 Static int
@@ -670,7 +702,7 @@ pipex_destroy_session(struct pipex_sessi
 }
 
 Static struct pipex_session *
-pipex_lookup_by_ip_address(struct in_addr addr)
+pipex_lookup_by_ip_address_nonref(struct in_addr addr)
 {
        struct pipex_session *session;
        struct sockaddr_in pipex_in4, pipex_in4mask;
@@ -700,8 +732,20 @@ pipex_lookup_by_ip_address(struct in_add
        return (session);
 }
 
+struct pipex_session *
+pipex_lookup_by_ip_address(struct in_addr addr)
+{
+       struct pipex_session *session;
+
+       session = pipex_lookup_by_ip_address_nonref(addr);
+       if (session != NULL)
+               pipex_ref_session(session);
+
+       return (session);
+}
+
 Static struct pipex_session *
-pipex_lookup_by_session_id(int protocol, int session_id)
+pipex_lookup_by_session_id_nonref(int protocol, int session_id)
 {
        struct pipex_hash_head *list;
        struct pipex_session *session;
@@ -724,6 +768,18 @@ pipex_lookup_by_session_id(int protocol,
        return (session);
 }
 
+struct pipex_session *
+pipex_lookup_by_session_id(int protocol, int session_id)
+{
+       struct pipex_session *session;
+
+       session = pipex_lookup_by_session_id_nonref(protocol, session_id);
+       if (session != NULL)
+               pipex_ref_session(session);
+
+       return (session);
+}
+
 /***********************************************************************
  * Queue and Software Interrupt Handler
  ***********************************************************************/
@@ -743,6 +799,7 @@ pipexintr(void)
                        m_freem(m);
                        continue;
                }
+
                proto = m->m_pkthdr.ph_ppp_proto;
 
                m->m_pkthdr.ph_cookie = NULL;
@@ -752,6 +809,12 @@ pipexintr(void)
                        struct pipex_session *session;
                        struct mbuf *m0;
 
+                       if (pkt_session->state != PIPEX_STATE_OPENED) {
+                               m_freem(m);
+                               pipex_rele_session(pkt_session);
+                               continue;
+                       }
+
                        LIST_FOREACH(session, &pipex_session_list,
                            session_list) {
                                if (session->pipex_iface !=
@@ -770,6 +833,8 @@ pipexintr(void)
                        m_freem(m);
                } else
                        pipex_ppp_output(m, pkt_session, proto);
+
+               pipex_rele_session(pkt_session);
        }
 
        /* ppp input */
@@ -780,7 +845,9 @@ pipexintr(void)
                        m_freem(m);
                        continue;
                }
+
                pipex_ppp_input(m, pkt_session, 0);
+               pipex_rele_session(pkt_session);
        }
 }
 
@@ -788,6 +855,7 @@ Static int
 pipex_ppp_enqueue(struct mbuf *m0, struct pipex_session *session,
     struct mbuf_queue *mq)
 {
+       pipex_ref_session(session);
        m0->m_pkthdr.ph_cookie = session;
        /* XXX need to support other protocols */
        m0->m_pkthdr.ph_ppp_proto = PPP_IP;
@@ -852,13 +920,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;
 
@@ -888,9 +949,10 @@ pipex_output(struct mbuf *m0, int af, in
        case AF_INET:
                if (m0->m_pkthdr.len >= sizeof(struct ip) + off) {
                        m_copydata(m0, off, sizeof(struct ip), (caddr_t)&ip);
-                       if (IN_MULTICAST(ip.ip_dst.s_addr))
+                       if (IN_MULTICAST(ip.ip_dst.s_addr)) {
                                session = pipex_iface->multicast_session;
-                       else
+                               pipex_ref_session(session);
+                       } else
                                session = pipex_lookup_by_ip_address(ip.ip_dst);
                }
                if (session != NULL) {
@@ -908,6 +970,7 @@ pipex_output(struct mbuf *m0, int af, in
                                m_adj(m0, off);
 
                        pipex_ip_output(m0, session);
+                       pipex_rele_session(session);
                        return (mret);
                }
                break;
@@ -917,8 +980,11 @@ pipex_output(struct mbuf *m0, int af, in
 
 drop:
        m_freem(m0);
-       if (session != NULL)
+       if (session != NULL) {
                session->stat.oerrors++;
+               pipex_rele_session(session);
+       }
+
        return(NULL);
 }
 
@@ -1377,8 +1443,11 @@ pipex_pppoe_lookup_session(struct mbuf *
                PIPEX_DBG((NULL, LOG_DEBUG, "<%s> session not found (id=%d)",
                    __func__, pppoe.session_id));
 #endif
-       if (session && session->proto.pppoe.over_ifidx != m0->m_pkthdr.ph_ifidx)
+       if (session && session->proto.pppoe.over_ifidx !=
+           m0->m_pkthdr.ph_ifidx) {
+               pipex_rele_session(session);
                session = NULL;
+       }
 
        return (session);
 }
@@ -1817,8 +1886,10 @@ pipex_pptp_userland_lookup_session(struc
        LIST_FOREACH(session, list, peer_addr_chain) {
                if (pipex_sockaddr_compar_addr(&session->peer.sa, sa) != 0)
                        continue;
-               if (session->peer_session_id == id)
+               if (session->peer_session_id == id) {
+                       pipex_ref_session(session);
                        break;
+               }
        }
 #ifdef PIPEX_DEBUG
        if (session == NULL) {
@@ -2250,8 +2321,10 @@ pipex_l2tp_userland_lookup_session(struc
                        continue;
                if (session->proto.l2tp.peer_tunnel_id != tunnel_id)
                        continue;
-               if (session->peer_session_id == session_id)
+               if (session->peer_session_id == session_id) {
+                       pipex_ref_session(session);
                        break;
+               }
        }
 #ifdef PIPEX_DEBUG
        if (session == NULL) {
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     1 Aug 2020 15:49:36 -0000
@@ -201,6 +201,7 @@ void                  pipex_init (void);
 void                  pipex_iface_init (struct pipex_iface_context *, u_int);
 void                  pipex_iface_fini (struct pipex_iface_context *);
 
+void                  pipex_rele_session(struct pipex_session *);
 int                   pipex_notify_close_session(struct pipex_session 
*session);
 int                   pipex_notify_close_session_all(void);
 
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       1 Aug 2020 15:49:36 -0000
@@ -159,6 +159,8 @@ struct pipex_session {
        LIST_ENTRY(pipex_session) id_chain;     /* [N] id hash chain */
        LIST_ENTRY(pipex_session) peer_addr_chain;
                                        /* [N] peer's address hash chain */
+       u_int           refs;           /* reference counter for this
+                                               session */
        uint16_t        state;          /* [N] pipex session state */
 #define PIPEX_STATE_INITIAL            0x0000
 #define PIPEX_STATE_OPENED             0x0001
@@ -379,7 +381,7 @@ void                  pipex_iface_start 
 void                  pipex_iface_stop (struct pipex_iface_context *);
 int                   pipex_init_session(struct pipex_session **,
                                              struct pipex_session_req *);
-void                  pipex_rele_session(struct pipex_session *);
+void                  pipex_ref_session(struct pipex_session *);
 int                   pipex_link_session(struct pipex_session *,
                                              struct pipex_iface_context *);
 void                  pipex_unlink_session(struct pipex_session *);
@@ -393,7 +395,9 @@ int                   pipex_get_stat (st
 int                   pipex_get_closed (struct pipex_session_list_req *,
                           struct pipex_iface_context *);
 int                   pipex_destroy_session (struct pipex_session *);
+struct pipex_session  *pipex_lookup_by_ip_address_nonref (struct in_addr);
 struct pipex_session  *pipex_lookup_by_ip_address (struct in_addr);
+struct pipex_session  *pipex_lookup_by_session_id_nonref (int, int);
 struct pipex_session  *pipex_lookup_by_session_id (int, int);
 void                  pipex_ip_output (struct mbuf *, struct pipex_session *);
 void                  pipex_ppp_output (struct mbuf *, struct pipex_session *, 
int);
Index: sys/netinet/ip_gre.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_gre.c,v
retrieving revision 1.71
diff -u -p -r1.71 ip_gre.c
--- sys/netinet/ip_gre.c        7 Feb 2018 22:30:59 -0000       1.71
+++ sys/netinet/ip_gre.c        1 Aug 2020 15:49:36 -0000
@@ -81,10 +81,15 @@ gre_usrreq(struct socket *so, int req, s
                        if (in_nam2sin(nam, &sin4) == 0)
                                ina_dst = &sin4->sin_addr;
                }
-               if (ina_dst != NULL &&
-                   (session = pipex_pptp_userland_lookup_session_ipv4(m,
-                           *ina_dst)))
-                       m = pipex_pptp_userland_output(m, session);
+               if (ina_dst != NULL) {
+                       session = pipex_pptp_userland_lookup_session_ipv4(m,
+                           *ina_dst);
+
+                       if (session != NULL) {
+                               m = pipex_pptp_userland_output(m, session);
+                               pipex_rele_session(session);
+                       }
+               }
 
                if (m == NULL)
                        return (ENOMEM);
Index: sys/netinet/udp_usrreq.c
===================================================================
RCS file: /cvs/src/sys/netinet/udp_usrreq.c,v
retrieving revision 1.259
diff -u -p -r1.259 udp_usrreq.c
--- sys/netinet/udp_usrreq.c    21 Jun 2020 05:19:27 -0000      1.259
+++ sys/netinet/udp_usrreq.c    1 Aug 2020 15:49:36 -0000
@@ -565,8 +565,11 @@ udp_input(struct mbuf **mp, int *offp, i
                struct pipex_session *session;
                int off = iphlen + sizeof(struct udphdr);
                if ((session = pipex_l2tp_lookup_session(m, off)) != NULL) {
-                       if ((m = *mp = pipex_l2tp_input(m, off, session,
-                           ipsecflowinfo)) == NULL) {
+                       m = *mp = pipex_l2tp_input(m, off, session,
+                           ipsecflowinfo);
+                       pipex_rele_session(session);
+
+                       if (m == NULL) {
                                /* the packet is handled by PIPEX */
                                return IPPROTO_DONE;
                        }
@@ -1149,12 +1152,15 @@ udp_usrreq(struct socket *so, int req, s
                                session =
                                    pipex_l2tp_userland_lookup_session_ipv4(
                                        m, inp->inp_faddr);
-                       if (session != NULL)
-                               if ((m = pipex_l2tp_userland_output(
-                                   m, session)) == NULL) {
+                       if (session != NULL) {
+                               m = pipex_l2tp_userland_output(m, session);
+                               pipex_rele_session(session);
+
+                               if(m == NULL) {
                                        error = ENOMEM;
                                        goto release;
                                }
+                       }
                }
 #endif
 

Reply via email to