Diff below fixes a race reported by Hrvoje Popovski.  If `ipsec_in_use'
is enabled after the softnettq checked for it but before it grabbed the
NET_LOCK(), IPsec code will be executed without KERNEL_LOCK().

ipsec_in_use is protected by the NET_LOCK(), so it has to be checked
after grabbing it.

ok?

Index: net/if.c
===================================================================
RCS file: /cvs/src/sys/net/if.c,v
retrieving revision 1.511
diff -u -p -r1.511 if.c
--- net/if.c    12 Aug 2017 20:27:28 -0000      1.511
+++ net/if.c    22 Aug 2017 10:26:49 -0000
@@ -887,19 +887,6 @@ if_input_process(void *xifidx)
        if (!ISSET(ifp->if_xflags, IFXF_CLONED))
                add_net_randomness(ml_len(&ml));
 
-#ifdef IPSEC
-       /*
-        * IPsec is not ready to run without KERNEL_LOCK().  So all
-        * the traffic on your machine is punished if you have IPsec
-        * enabled.
-        */
-       extern int ipsec_in_use;
-       if (ipsec_in_use) {
-               KERNEL_LOCK();
-               locked = 1;
-       }
-#endif /* IPSEC */
-
        /*
         * We grab the NET_LOCK() before processing any packet to
         * ensure there's no contention on the routing table lock.
@@ -914,6 +901,22 @@ if_input_process(void *xifidx)
         */
        NET_LOCK();
        s = splnet();
+
+#ifdef IPSEC
+       /*
+        * IPsec is not ready to run without KERNEL_LOCK().  So all
+        * the traffic on your machine is punished if you have IPsec
+        * enabled.
+        */
+       extern int ipsec_in_use;
+       if (ipsec_in_use) {
+               NET_UNLOCK();
+               KERNEL_LOCK();
+               NET_LOCK();
+               locked = 1;
+       }
+#endif /* IPSEC */
+
        while ((m = ml_dequeue(&ml)) != NULL) {
                /*
                 * Pass this mbuf to all input handlers of its
Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.318
diff -u -p -r1.318 ip_input.c
--- netinet/ip_input.c  11 Aug 2017 21:24:20 -0000      1.318
+++ netinet/ip_input.c  22 Aug 2017 10:27:09 -0000
@@ -1802,6 +1802,8 @@ ip_send_dispatch(void *xmq)
        if (ml_empty(&ml))
                return;
 
+       NET_LOCK();
+
 #ifdef IPSEC
        /*
         * IPsec is not ready to run without KERNEL_LOCK().  So all
@@ -1810,12 +1812,13 @@ ip_send_dispatch(void *xmq)
         */
        extern int ipsec_in_use;
        if (ipsec_in_use) {
+               NET_UNLOCK();
                KERNEL_LOCK();
+               NET_LOCK();
                locked = 1;
        }
 #endif /* IPSEC */
 
-       NET_LOCK();
        while ((m = ml_dequeue(&ml)) != NULL) {
                ip_output(m, NULL, NULL, 0, NULL, NULL, 0);
        }
Index: netinet6/ip6_input.c
===================================================================
RCS file: /cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.201
diff -u -p -r1.201 ip6_input.c
--- netinet6/ip6_input.c        11 Aug 2017 21:24:20 -0000      1.201
+++ netinet6/ip6_input.c        22 Aug 2017 10:28:14 -0000
@@ -1450,6 +1450,8 @@ ip6_send_dispatch(void *xmq)
        if (ml_empty(&ml))
                return;
 
+       NET_LOCK();
+
 #ifdef IPSEC
        /*
         * IPsec is not ready to run without KERNEL_LOCK().  So all
@@ -1458,12 +1460,13 @@ ip6_send_dispatch(void *xmq)
         */
        extern int ipsec_in_use;
        if (ipsec_in_use) {
+               NET_UNLOCK();
                KERNEL_LOCK();
+               NET_LOCK();
                locked = 1;
        }
 #endif /* IPSEC */
 
-       NET_LOCK();
        while ((m = ml_dequeue(&ml)) != NULL) {
                ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL);
        }

Reply via email to