Hello,
My colleague hit the following kernel panic when he is doing "psctl
-ss" repeatedly by a script during a performance test.
uvm_fault(0xfffffd811b869110, 0x10, 0, 1) -> e
kernel: page fault trap, code=0
Stopped at pf_state_export+0x42: movq 0x10(%rax),%rcx
TID PID UID PRFLAGS PFLAGS CPU COMMAND
313402 43614 0 0x3 0 0 awk
* 66859 46071 0 0x3 0 3K pfctl
48782 57541 0 0x14000 0x200 1 softnet
pf_state_export(ffff80003a863218,fffffd81117155a8) at pf_state_export+0x42
pf_states_get(ffff80003a863680) at pf_states_get+0xe1
pfioctl(4900,c0104419,ffff80003a863680,1,ffff80003a823cf0) at pfioctl+0x11ba
VOP_IOCTL(fffffd811f894770,c0104419,ffff80003a863680,1,fffffd811a4e3ba8,ffff80003a823cf0)
at VOP_IOCTL+0x57
vn_ioctl(fffffd812742c168,c0104419,ffff80003a863680,ffff80003a823cf0) at
vn_ioctl+0x79
sys_ioctl(ffff80003a823cf0,ffff80003a863790,ffff80003a863780) at
sys_ioctl+0x2b9
syscall(ffff80003a863830) at syscall+0x35b
Xsyscall() at Xsyscall+0xef
end of kernel
end trace frame: 0x7f7fffff3960, count: 7
Running script...
ddb{3}>
Look at "pf_state_export+0x42":
(gdb) l *(pf_state_export+0x42)
0xffffffff819bb112 is in pf_state_export (/usr/src/sys/net/pf.c:1216).
1211
1212 memset(sp, 0, sizeof(struct pfsync_state));
1213
1214 /* copy from state key */
1215 sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
1216 sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
1217 sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
1218 sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
1219 sp->key[PF_SK_WIRE].rdomain =
htons(st->key[PF_SK_WIRE]->rdomain);
1220 sp->key[PF_SK_WIRE].af = st->key[PF_SK_WIRE]->af;
(gdb)
the uvm_fault happened because st->key[PF_SK_WIRE] is NULL. This is
can happen after pf_state_key_detach() <- pf_state_remove() is called
for the state.
The diff is to take care of that condition.
ok? comments?
Don't assume pf state keys of pf_state are always there. Take a
reference of pf state key with a reference counter and access its
members through it. Found by IIJ.
Index: sys/net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1140
diff -u -p -r1.1140 pf.c
--- sys/net/pf.c 3 Sep 2022 19:22:19 -0000 1.1140
+++ sys/net/pf.c 21 Sep 2022 05:50:16 -0000
@@ -1193,26 +1193,37 @@ void
pf_state_export(struct pfsync_state *sp, struct pf_state *st)
{
int32_t expire;
+ struct pf_state_key *skw, *sks;
memset(sp, 0, sizeof(struct pfsync_state));
/* copy from state key */
- sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0];
- sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1];
- sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0];
- sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1];
- sp->key[PF_SK_WIRE].rdomain = htons(st->key[PF_SK_WIRE]->rdomain);
- sp->key[PF_SK_WIRE].af = st->key[PF_SK_WIRE]->af;
- sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0];
- sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1];
- sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0];
- sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1];
- sp->key[PF_SK_STACK].rdomain = htons(st->key[PF_SK_STACK]->rdomain);
- sp->key[PF_SK_STACK].af = st->key[PF_SK_STACK]->af;
+ skw = pf_state_key_ref(st->key[PF_SK_WIRE]);
+ if (skw != NULL) {
+ sp->key[PF_SK_WIRE].addr[0] = skw->addr[0];
+ sp->key[PF_SK_WIRE].addr[1] = skw->addr[1];
+ sp->key[PF_SK_WIRE].port[0] = skw->port[0];
+ sp->key[PF_SK_WIRE].port[1] = skw->port[1];
+ sp->key[PF_SK_WIRE].rdomain = htons(skw->rdomain);
+ sp->key[PF_SK_WIRE].af = skw->af;
+ sp->proto = skw->proto;
+ sp->af = skw->af;
+ pf_state_key_unref(skw);
+ skw = NULL;
+ }
+ sks = pf_state_key_ref(st->key[PF_SK_STACK]);
+ if (sks != NULL) {
+ sp->key[PF_SK_STACK].addr[0] = sks->addr[0];
+ sp->key[PF_SK_STACK].addr[1] = sks->addr[1];
+ sp->key[PF_SK_STACK].port[0] = sks->port[0];
+ sp->key[PF_SK_STACK].port[1] = sks->port[1];
+ sp->key[PF_SK_STACK].rdomain = htons(sks->rdomain);
+ sp->key[PF_SK_STACK].af = sks->af;
+ pf_state_key_unref(sks);
+ sks = NULL;
+ }
sp->rtableid[PF_SK_WIRE] = htonl(st->rtableid[PF_SK_WIRE]);
sp->rtableid[PF_SK_STACK] = htonl(st->rtableid[PF_SK_STACK]);
- sp->proto = st->key[PF_SK_WIRE]->proto;
- sp->af = st->key[PF_SK_WIRE]->af;
/* copy from state */
strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname));