On Wed, Jun 21, 2017 at 01:21:50AM +0200, Alexander Bluhm wrote:
> Hi,
> 
> I saw a crash on an OpenBSD 6.1 based system when a kassert in
> pf_state_key_unref() was triggert.
> 
> kernel diagnostic assertion "(sk->inp == NULL) || (sk->inp->inp_pf_sk == 
> NULL)" 
>  failed: file "../../../../../net/pf.c", line 7155                            
>   
> 
> panic() at panic+0xfe                                                         
>   
> __assert() at __assert+0x25                                                   
>   
> pf_state_key_unref() at pf_state_key_unref+0xc6                               
>   
> pf_pkt_unlink_state_key() at pf_pkt_unlink_state_key+0x15                     
>   
> m_free() at m_free+0xc0                                                       
>   
> soreceive() at soreceive+0xb5d                                                
>   
> recvit() at recvit+0x13a                                                      
>   
> sys_recvmsg() at sys_recvmsg+0x107                                            
>   
> syscall() at syscall+0x2df                                                    
>   
> 
> The problem is that setting the inp pointer in the statekey to NULL
> is delayed until the statekey refcounter reaches 0.  So the inp
> could get linked to another statekey while the mbuf in the socket
> buffer was keeping the refcounter at 1.
> 
> The sk->inp should be set to NULL immediately, then the kassert can
> get even stricter.
> 
> ok?

ok!! dhill@

I hit this too.  See bugs@ archives :)

> 
> bluhm
> 
> Index: net/pf.c
> ===================================================================
> RCS file: /data/mirror/openbsd/cvs/src/sys/net/pf.c,v
> retrieving revision 1.1034
> diff -u -p -r1.1034 pf.c
> --- net/pf.c  5 Jun 2017 22:18:28 -0000       1.1034
> +++ net/pf.c  20 Jun 2017 22:37:43 -0000
> @@ -779,6 +779,7 @@ pf_state_key_detach(struct pf_state *s, 
>               sk->removed = 1;
>               pf_state_key_unlink_reverse(sk);
>               pf_inpcb_unlink_state_key(sk->inp);
> +             sk->inp = NULL;
>               pf_state_key_unref(sk);
>       }
>  }
> @@ -7147,8 +7148,7 @@ pf_state_key_unref(struct pf_state_key *
>               /* state key must be unlinked from reverse key */
>               KASSERT(sk->reverse == NULL);
>               /* state key must be unlinked from socket */
> -             KASSERT((sk->inp == NULL) || (sk->inp->inp_pf_sk == NULL));
> -             sk->inp = NULL;
> +             KASSERT(sk->inp == NULL);
>               pool_put(&pf_state_key_pl, sk);
>       }
>  }
> 

Reply via email to