• Ian Abbott's avatar
    staging: comedi: comedi_test: fix timer race conditions · 403fe7f3
    Ian Abbott authored
    Commit 73e0e4df ("staging: comedi: comedi_test: fix timer lock-up")
    fixed a lock-up in the timer routine `waveform_ai_timer()` (which was
    called `waveform_ai_interrupt()` at the time) caused by
    commit 24051247 ("staging: comedi: comedi_test: use
    comedi_handle_events()").  However, it introduced a race condition that
    can result in the timer routine misbehaving, such as accessing freed
    memory or dereferencing a NULL pointer.
    
    73e0... changed the timer routine to do nothing unless a
    `WAVEFORM_AI_RUNNING` flag was set, and changed `waveform_ai_cancel()`
    to clear the flag and replace a call to `del_timer_sync()` with a call
    to `del_timer()`.  `waveform_ai_cancel()` may be called from the timer
    routine itself (via `comedi_handle_events()`), or from `do_cancel()`.
    (`do_cancel()` is called as a result of a file operation (usually a
    `COMEDI_CANCEL` ioctl command, or a release), or during device removal.)
    When called from `do_cancel()`, the call to `waveform_ai_cancel()` is
    followed by a call to `do_become_nonbusy()`, which frees up stuff for
    the current asynchronous command under the assumption that it is now
    safe to do so.  The race condition occurs when the timer routine
    `waveform_ai_timer()` checks the `WAVEFORM_AI_RUNNING` flag just before
    it is cleared by `waveform_ai_cancel()`, and is still running during the
    call to `do_become_nonbusy()`.  In particular, it can lead to a NULL
    pointer dereference:
    
    BUG: unable to handle kernel NULL pointer dereference at (null)
    IP: [<ffffffffc0c63add>] waveform_ai_timer+0x17d/0x290 [comedi_test]
    
    That corresponds to this line in `waveform_ai_timer()`:
    
    		unsigned int chanspec = cmd->chanlist[async->cur_chan];
    
    but `do_become_nonbusy()` frees `cmd->chanlist` and sets it to `NULL`.
    
    Fix the race by calling `del_timer_sync()` instead of `del_timer()` in
    `waveform_ai_cancel()` when not in an interrupt context.  The only time
    `waveform_ai_cancel()` is called in an interrupt context is when it is
    called from the timer routine itself, via `comedi_handle_events()`.
    
    There is no longer any need for the `WAVEFORM_AI_RUNNING` flag, so get
    rid of it.
    
    The bug was copied from the AI subdevice to the AO when support for
    commands on the AO subdevice was added by commit 0cf55bbe ("staging:
    comedi: comedi_test: implement commands on AO subdevice").  That
    involves the timer routine `waveform_ao_timer()`, the comedi "cancel"
    routine `waveform_ao_cancel()`, and the flag `WAVEFORM_AO_RUNNING`.  Fix
    it in the same way as for the AI subdevice.
    
    Fixes: 73e0e4df ("staging: comedi: comedi_test: fix timer lock-up")
    Fixes: 0cf55bbe ("staging: comedi: comedi_test: implement commands
     on AO subdevice")
    Reported-by: default avatarÉric Piel <piel@delmic.com>
    Signed-off-by: default avatarIan Abbott <abbotti@mev.co.uk>
    Cc: <stable@vger.kernel.org> # 4.4+
    Cc: Éric Piel <piel@delmic.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    403fe7f3
Name
Last commit
Last update
..
android Loading commit data...
board Loading commit data...
clocking-wizard Loading commit data...
comedi Loading commit data...
dgnc Loading commit data...
emxx_udc Loading commit data...
fbtft Loading commit data...
fsl-mc Loading commit data...
fwserial Loading commit data...
gdm724x Loading commit data...
goldfish Loading commit data...
gs_fpgaboot Loading commit data...
i4l Loading commit data...
iio Loading commit data...
ks7010 Loading commit data...
lustre Loading commit data...
media Loading commit data...
most Loading commit data...
mt29f_spinand Loading commit data...
netlogic Loading commit data...
nvec Loading commit data...
octeon Loading commit data...
octeon-usb Loading commit data...
olpc_dcon Loading commit data...
rtl8188eu Loading commit data...
rtl8192e Loading commit data...
rtl8192u Loading commit data...
rtl8712 Loading commit data...
rtl8723au Loading commit data...
rts5208 Loading commit data...
skein Loading commit data...
slicoss Loading commit data...
sm750fb Loading commit data...
speakup Loading commit data...
unisys Loading commit data...
vme Loading commit data...
vt6655 Loading commit data...
vt6656 Loading commit data...
wilc1000 Loading commit data...
wlan-ng Loading commit data...
xgifb Loading commit data...
Kconfig Loading commit data...
Makefile Loading commit data...