git: 0e6e2c4ef3d1 - main - netgraph(4): Don't process NGQF_MESG items in NET_EPOCH context.

From: Aleksandr Fedorov <afedorov_at_FreeBSD.org>
Date: Tue, 13 Sep 2022 14:24:27 UTC
The branch main has been updated by afedorov:

URL: https://cgit.FreeBSD.org/src/commit/?id=0e6e2c4ef3d1244fa21e7b691e76fdc09f8eacae

commit 0e6e2c4ef3d1244fa21e7b691e76fdc09f8eacae
Author:     Aleksandr Fedorov <afedorov@FreeBSD.org>
AuthorDate: 2022-09-13 14:15:23 +0000
Commit:     Aleksandr Fedorov <afedorov@FreeBSD.org>
CommitDate: 2022-09-13 14:20:41 +0000

    netgraph(4): Don't process NGQF_MESG items in NET_EPOCH context.
    
    Netgraph has two main types of message items:
    
    - NGQF_DATA items are used for data processing. This is a hot path that
    should be called from a NET_EPOCH context.
    
    - NGQF_MESG items are used for node configuration. There are many places
    in netgraph(4) where processing the NGQF_MESG item can call sections of code
    that are forbidden in the NET_EPOCH context.
    
    All item types can be queued and then processed using ngthread().
    But ngthread() is unconditionally enter in the NET_EPOCH section for all types.
    This causes panic/deadlocks when processing NGQF_MESG elements.
    
    Reported by:    mjg
    Reviewed by:    glebius, vmaffione (mentor)
    Tested by:      mjg, afedorov
    Approved by:    glebius, vmaffione (mentor)
    Sponsored by:   vstack.com
    Differential Revision:  https://reviews.freebsd.org/D36496
---
 sys/netgraph/ng_base.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index ac9d55a6f703..092231850f18 100644
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -3439,7 +3439,19 @@ ngthread(void *arg)
 			} else {
 				NG_QUEUE_UNLOCK(&node->nd_input_queue);
 				NGI_GET_NODE(item, node); /* zaps stored node */
-				ng_apply_item(node, item, rw);
+
+				if ((item->el_flags & NGQF_TYPE) == NGQF_MESG) {
+					/*
+					 * NGQF_MESG items should never be processed in
+					 * NET_EPOCH context. So, temporary exit from EPOCH.
+					 */
+					NET_EPOCH_EXIT(et);
+					ng_apply_item(node, item, rw);
+					NET_EPOCH_ENTER(et);
+				} else {
+					ng_apply_item(node, item, rw);
+				}
+
 				NG_NODE_UNREF(node);
 			}
 		}