Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 Sep 2011 01:45:56 GMT
From:      Nikos Vassiliadis <nvass@gmx.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/160496: [patch] kernel panic with pf + VIMAGE
Message-ID:  <201109060145.p861juxO096933@red.freebsd.org>
Resent-Message-ID: <201109060150.p861o14A083645@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         160496
>Category:       kern
>Synopsis:       [patch] kernel panic with pf + VIMAGE
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Sep 06 01:50:01 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Nikos Vassiliadis
>Release:        9.0-CURRENT
>Organization:
>Environment:
FreeBSD lab.local 9.0-BETA2 FreeBSD 9.0-BETA2 #77 r225405: Tue Sep  6 01:25:42 EEST 2011     root@lab.local:/usr/obj/usr/src/sys/LAB  i386

>Description:
When multiple instances of pf are used on an "options VIMAGE" kernel,
a kernel panic is quickly triggered. It happens when pf is trying to
remove a state from its state table. Two indicative backtraces:
 
#9  0xc0a127a4 in panic (fmt=0xc404ec26 "Bad link elm %p next->prev != elm")
    at /usr/src/sys/kern/kern_shutdown.c:587
#10 0xc4027099 in pf_free_state (cur=Variable "cur" is not available.
)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:1655
#11 0xc4027110 in pf_purge_expired_states (maxcheck=1, waslocked=0)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:1727
#12 0xc40285d0 in pf_purge_thread (v=0xc35a85a0)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:1370
#13 0xc09e5818 in fork_exit (callout=0xc4028460 <pf_purge_thread>,
    arg=0xc35a85a0, frame=0xcd69ed28) at /usr/src/sys/kern/kern_fork.c:1025
#14 0xc0d72574 in fork_trampoline () at /usr/src/sys/i386/i386/exception.s:275
(kgdb)

and

#8  0xc0d724fc in calltrap () at /usr/src/sys/i386/i386/exception.s:168
#9  0xc40e776a in pf_state_tree_id_RB_REMOVE_COLOR (head=0xc4081148,
    parent=0x0, elm=0xc4183198)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:474
#10 0xc40e7aa0 in pf_state_tree_id_RB_REMOVE (head=0xc4081148, elm=0xc417ce58)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:474
#11 0xc40ec83e in pf_unlink_state (cur=0xc417ce58)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:1592
#12 0xc40ed15a in pf_purge_expired_states (maxcheck=429496730, waslocked=0)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:1717
#13 0xc40ee5d0 in pf_purge_thread (v=0xc35a8a00)
    at /usr/src/sys/modules/pf/../../contrib/pf/net/pf.c:1370
#14 0xc09e5818 in fork_exit (callout=0xc40ee460 <pf_purge_thread>,
    arg=0xc35a8a00, frame=0xcd6ddd28) at /usr/src/sys/kern/kern_fork.c:1025
#15 0xc0d72574 in fork_trampoline () at /usr/src/sys/i386/i386/exception.s:275
(kgdb)

Sometimes the state table corruption is observable using
"vmstat -z":

lab# vmstat -z | grep pfstate
pfstatepl:              204,  10013,18446744073709551615,       1,       0,   0,   0
pfstatekeypl:           204,      0,18446744073709551615,       1,       0,   0,   0
pfstateitempl:          204,      0,18446744073709551615,       1,       0,   0,   0
pfstatescrub:            28,      0,       0,       0,       0,   0,   0
pfstatepl:              204,  10013,18446744073709551615,       1,       0,   0,   0
pfstatekeypl:           204,      0,18446744073709551615,       1,       0,   0,   0
pfstateitempl:          204,      0,18446744073709551615,       1,       0,   0,   0
pfstatescrub:            28,      0,       0,       0,       0,   0,   0
pfstatepl:              204,  10013,       4,      34,       4,   0,   0
pfstatekeypl:           204,      0,       4,      34,       4,   0,   0
pfstateitempl:          204,      0,       4,      34,       4,   0,   0
pfstatescrub:            28,      0,       0,       0,       0,   0,   0
pfstatepl:              204,  10013,       8,      30,       8,   0,   0
pfstatekeypl:           204,      0,       8,      30,       8,   0,   0
pfstateitempl:          204,      0,       8,      30,       8,   0,   0
pfstatescrub:            28,      0,       0,       0,       0,   0,   0
lab#

>How-To-Repeat:
build a kernel with the VIMAGE option
create a few vnet jails
kldload pf
enable pf on all jails
create a very basic ruleset like "pass out all\npass in all" on all jails
create some IP traffic that will create pf states
the kernel will soon panic on a state expiration

>Fix:
There  is a static non virtualized variable that causes the problem
in pf_purge_expired_states():/sys/contrib/pf/net/pf.c. This should be
virtualized in an "option VIMAGE" kernel. See the attached patch.


Patch attached with submission follows:

Index: sys/contrib/pf/net/pf.c
===================================================================
--- sys/contrib/pf/net/pf.c	(revision 225405)
+++ sys/contrib/pf/net/pf.c	(working copy)
@@ -1677,30 +1677,41 @@
 pf_purge_expired_states(u_int32_t maxcheck)
 #endif
 {
-	static struct pf_state	*cur = NULL;
 	struct pf_state		*next;
 #ifdef __FreeBSD__
+	static VNET_DEFINE(struct pf_state *, cur) = NULL;
 	int			 locked = waslocked;
 #else
+	static struct pf_state	*cur = NULL;
 	int			 locked = 0;
 #endif
 
 	while (maxcheck--) {
 		/* wrap to start of list when we hit the end */
-		if (cur == NULL) {
 #ifdef __FreeBSD__
-			cur = TAILQ_FIRST(&V_state_list);
+		if (VNET(cur) == NULL) {
+			VNET(cur) = TAILQ_FIRST(&V_state_list);
+			if (VNET(cur) == NULL)
 #else
+		if (cur == NULL) {
 			cur = TAILQ_FIRST(&state_list);
+			if (cur == NULL)
 #endif
-			if (cur == NULL)
 				break;	/* list empty */
 		}
 
 		/* get next state, as cur may get deleted */
+#ifdef __FreeBSD__
+		next = TAILQ_NEXT(VNET(cur), entry_list);
+#else
 		next = TAILQ_NEXT(cur, entry_list);
+#endif
 
+#ifdef __FreeBSD__
+		if (VNET(cur)->timeout == PFTM_UNLINKED) {
+#else
 		if (cur->timeout == PFTM_UNLINKED) {
+#endif
 			/* free unlinked state */
 			if (! locked) {
 #ifdef __FreeBSD__
@@ -1711,10 +1722,17 @@
 #endif
 				locked = 1;
 			}
+#ifdef __FreeBSD__
+			pf_free_state(VNET(cur));
+		} else if (pf_state_expires(VNET(cur)) <= time_second) {
+			/* unlink and free expired state */
+			pf_unlink_state(VNET(cur));
+#else
 			pf_free_state(cur);
 		} else if (pf_state_expires(cur) <= time_second) {
 			/* unlink and free expired state */
 			pf_unlink_state(cur);
+#endif
 			if (! locked) {
 #ifdef __FreeBSD__
 				if (!sx_try_upgrade(&V_pf_consistency_lock))
@@ -1724,9 +1742,15 @@
 #endif
 				locked = 1;
 			}
+#ifdef __FreeBSD__
+			pf_free_state(VNET(cur));
+		}
+		VNET(cur) = next;
+#else
 			pf_free_state(cur);
 		}
 		cur = next;
+#endif
 	}
 
 #ifdef __FreeBSD__


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201109060145.p861juxO096933>