>Number:         144453
>Category:       kern
>Synopsis:       bpf(4) can panic due to a race condition on descriptor 
>destruction
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Mar 03 21:20:03 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Alexander Sack
>Release:        CURRENT, 7.2-amd64
>Organization:
Niksun
>Environment:
SA5000PAL Intel board with 8GB of RAM, em(4) network interface card
>Description:
When an application polls on a particular bpf descriptor, a timeout is 
scheduled, bpf_timed_out() via callout_reset().  If a buffer is not available 
within the poll period, bpf_timed_out() is fired which will change the bpf_d 
state and wakeup any threads waiting for an event.  When bpf_timed_out() is 
attempts to acquire the descriptor lock.

Now if a process is in the middle of a poll/select and closes (gracefully or 
otherwise) when the bpf descriptor is closed, bpf_dtor() is called.  This will 
acquire the descriptor lock and do callout_stop() if the bpf state is in 
BPF_WAITING (i.e. select was called and callout_reset has completed scheduling 
the callout).  After calling callout_stop() it released the descriptor lock 
where now a race condition can occur.

If callout_stop() can't stop bpf_timed_out() from firing (say it has already 
fired) then bpf_timed_out() is sitting waiting on the descriptor lock to 
continue. When bpf_dtor() drops the lock, bpf_timed_out() is allowed to 
continue. But bpf_dtor() is going to free the descriptor that bpf_timed_out() 
is currently changing.  This can lead to panic.

The patch attached addresses this situation by just doing a callout_active() 
and if so do a callout_drain() which will wait until bpf_timed_out() has 
finished.  This allows bpf_dtor() to confidently free the descriptor during 
close operation.
>How-To-Repeat:
Loads of pollers on a descriptor with high load during a shutdown.
>Fix:
See patch attached.  I tested this on my Intel machine issuing 200 tcpdump 
processes with zerocopy disabled and enabled (even though with zerocopy libpcap 
doens't poll on it) capturing 100% utilization gige traffic.  No panic occured 
during shutdown.  We also saw this using our own custom packet capture 
application which is where I discovered and fixed the problem.

Patch attached with submission follows:

? bpf.patch
Index: bpf.c
===================================================================
RCS file: /home/ncvs/src/sys/net/bpf.c,v
retrieving revision 1.219
diff -u -r1.219 bpf.c
--- bpf.c       20 Feb 2010 00:19:21 -0000      1.219
+++ bpf.c       3 Mar 2010 21:04:48 -0000
@@ -614,6 +614,15 @@
        mac_bpfdesc_destroy(d);
 #endif /* MAC */
        knlist_destroy(&d->bd_sel.si_note);
+       /*
+        * If we could not stop the callout above, 
+        * then when we release the descriptor lock, 
+        * there is a race between when bpf_timed_out() 
+        * finishes and descriptor tear down.  Check
+        * for it and drain.
+        */
+       if (callout_active(&d->bd_callout))
+               callout_drain(&d->bd_callout);
        bpf_freed(d);
        free(d, M_BPF);
 }


>Release-Note:
>Audit-Trail:
>Unformatted:
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to