Hello,
On Wed, May 27, 2015 at 07:44:15PM +0200, Mike Belopuhov wrote: > On Wed, May 27, 2015 at 10:39 +0200, Alexandr Nedvedicky wrote: > > Hello, > > > > > > - if (pf_state_insert(BOUND_IFACE(r, pd->kif), skw, sks, s)) { > > > > - pf_state_key_detach(s, PF_SK_STACK); > > > > - pf_state_key_detach(s, PF_SK_WIRE); > > > > > > This bug is not yours, but doing two pf_state_key_detach is wrong > > > and results in all kinds of protection fault fireworks. The right > > > thing is to do pf_detach_state that would handle the case where > > > PF_SK_STACK == PF_SK_WIRE (i.e. we need only one invocation). > > good catch. > > > > > > > > In csfailed case we do pf_remove_src_node and then call > > > pf_src_tree_remove_state. With your diff this means that > > > pf_src_tree_remove_state will be dereferencing sni->sn that > > > might be pool_put by the pf_remove_src_node. Therefore their > > > order needs to be reversed. > > > > I see. Another option to fix it would be to do: > > > > sni->sn = sns[i]; > > sns[i] = NULL; > > > > I'm not sure I follow. Where do you want to do it? > If it's when we pool_get sni's, then this would mean > we won't run pf_remove_src_node and cleanup source > nodes that might have been created. > sorry I was too brief. The snippet below comes from pf_create_state() with your patch applied: 3560 for (i = 0; i < PF_SN_MAX; i++) 3561 if (sns[i] != NULL) { 3562 struct pf_sn_item *sni; 3563 3564 sni = pool_get(&pf_sn_item_pl, PR_NOWAIT); 3565 if (sni == NULL) { 3566 REASON_SET(&reason, PFRES_MEMORY); 3567 goto csfailed; 3568 } 3569 sni->sn = sns[i]; 3570 sns[i] = NULL; 3571 SLIST_INSERT_HEAD(&s->src_nodes, sni, next); 3572 sni->sn->states++; 3573 } 3574 the point of my suggestion is to transfer ownership of source node from local variable sns[] to state. so the check performed later in csfailed at line 3617, will find NULL pointer in sns[i] field and won't attempt to call pf_remove_src_node(). 3610 csfailed: 3611 if (s) { 3612 pf_normalize_tcp_cleanup(s); /* safe even w/o init */ 3613 pf_src_tree_remove_state(s); 3614 } 3615 3616 for (i = 0; i < PF_SN_MAX; i++) 3617 if (sns[i] != NULL) 3618 pf_remove_src_node(sns[i]); 3619 your patch updated by my suggestion is further below. regards sasha ? pf.c.diff ? pf.c.patch Index: pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.916 diff -u -r1.916 pf.c --- pf.c 26 May 2015 16:17:51 -0000 1.916 +++ pf.c 27 May 2015 22:59:32 -0000 @@ -3557,16 +3557,6 @@ goto csfailed; } - if (pf_state_insert(BOUND_IFACE(r, pd->kif), skw, sks, s)) { - pf_state_key_detach(s, PF_SK_STACK); - pf_state_key_detach(s, PF_SK_WIRE); - *sks = *skw = NULL; - REASON_SET(&reason, PFRES_STATEINS); - goto csfailed; - } else - *sm = s; - - /* attach src nodes late, otherwise cleanup on error nontrivial */ for (i = 0; i < PF_SN_MAX; i++) if (sns[i] != NULL) { struct pf_sn_item *sni; @@ -3574,16 +3564,22 @@ sni = pool_get(&pf_sn_item_pl, PR_NOWAIT); if (sni == NULL) { REASON_SET(&reason, PFRES_MEMORY); - pf_src_tree_remove_state(s); - STATE_DEC_COUNTERS(s); - pool_put(&pf_state_pl, s); - return (PF_DROP); + goto csfailed; } sni->sn = sns[i]; + sns[i] = NULL; SLIST_INSERT_HEAD(&s->src_nodes, sni, next); sni->sn->states++; } + if (pf_state_insert(BOUND_IFACE(r, pd->kif), skw, sks, s)) { + pf_detach_state(s); + *sks = *skw = NULL; + REASON_SET(&reason, PFRES_STATEINS); + goto csfailed; + } else + *sm = s; + pf_set_rt_ifp(s, pd->src); /* needs s->state_key set */ if (tag > 0) { pf_tag_ref(tag); @@ -3612,12 +3608,16 @@ return (PF_PASS); csfailed: + if (s) { + pf_normalize_tcp_cleanup(s); /* safe even w/o init */ + pf_src_tree_remove_state(s); + } + for (i = 0; i < PF_SN_MAX; i++) if (sns[i] != NULL) pf_remove_src_node(sns[i]); + if (s) { - pf_normalize_tcp_cleanup(s); /* safe even w/o init */ - pf_src_tree_remove_state(s); STATE_DEC_COUNTERS(s); pool_put(&pf_state_pl, s); }