• Duoming Zhou's avatar
    media: rc: Fix use-after-free bugs caused by ene_tx_irqsim() · 29b0589a
    Duoming Zhou authored
    When the ene device is detaching, function ene_remove() will
    be called. But there is no function to cancel tx_sim_timer
    in ene_remove(), the timer handler ene_tx_irqsim() could race
    with ene_remove(). As a result, the UAF bugs could happen,
    the process is shown below.
    
        (cleanup routine)          |        (timer routine)
                                   | mod_timer(&dev->tx_sim_timer, ..)
    ene_remove()                   | (wait a time)
                                   | ene_tx_irqsim()
                                   |   dev->hw_lock //USE
                                   |   ene_tx_sample(dev) //USE
    
    Fix by adding del_timer_sync(&dev->tx_sim_timer) in ene_remove(),
    The tx_sim_timer could stop before ene device is deallocated.
    
    What's more, The rc_unregister_device() and del_timer_sync()
    should be called first in ene_remove() and the deallocated
    functions such as free_irq(), release_region() and so on
    should be called behind them. Because the rc_unregister_device()
    is well synchronized. Otherwise, race conditions may happen. The
    situations that may lead to race conditions are shown below.
    
    Firstly, the rx receiver is disabled with ene_rx_disable()
    before rc_unregister_device() in ene_remove(), which means it
    can be enabled again if a process opens /dev/lirc0 between
    ene_rx_disable() and rc_unregister_device().
    
    Secondly, the irqaction descriptor is freed by free_irq()
    before the rc device is unregistered, which means irqaction
    descriptor may be accessed again after it is deallocated.
    
    Thirdly, the timer can call ene_tx_sample() that can write
    to the io ports, which means the io ports could be accessed
    again after they are deallocated by release_region().
    
    Therefore, the rc_unregister_device() and del_timer_sync()
    should be called first in ene_remove().
    
    Suggested by: Sean Young <sean@mess.org>
    
    Fixes: 9ea53b74 ("V4L/DVB: STAGING: remove lirc_ene0100 driver")
    Signed-off-by: default avatarDuoming Zhou <duoming@zju.edu.cn>
    Signed-off-by: default avatarSean Young <sean@mess.org>
    Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
    29b0589a
ene_ir.c 30.6 KB