linux-uconsole/drivers/char
Masamitsu Yamazaki 99962affcb ipmi: Stop timers before cleaning up the module
commit 4f7f5551a7 upstream.

System may crash after unloading ipmi_si.ko module
because a timer may remain and fire after the module cleaned up resources.

cleanup_one_si() contains the following processing.

        /*
         * Make sure that interrupts, the timer and the thread are
         * stopped and will not run again.
         */
        if (to_clean->irq_cleanup)
                to_clean->irq_cleanup(to_clean);
        wait_for_timer_and_thread(to_clean);

        /*
         * Timeouts are stopped, now make sure the interrupts are off
         * in the BMC.  Note that timers and CPU interrupts are off,
         * so no need for locks.
         */
        while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
                poll(to_clean);
                schedule_timeout_uninterruptible(1);
        }

si_state changes as following in the while loop calling poll(to_clean).

  SI_GETTING_MESSAGES
    => SI_CHECKING_ENABLES
     => SI_SETTING_ENABLES
      => SI_GETTING_EVENTS
       => SI_NORMAL

As written in the code comments above,
timers are expected to stop before the polling loop and not to run again.
But the timer is set again in the following process
when si_state becomes SI_SETTING_ENABLES.

  => poll
     => smi_event_handler
       => handle_transaction_done
          // smi_info->si_state == SI_SETTING_ENABLES
         => start_getting_events
           => start_new_msg
            => smi_mod_timer
              => mod_timer

As a result, before the timer set in start_new_msg() expires,
the polling loop may see si_state becoming SI_NORMAL
and the module clean-up finishes.

For example, hard LOCKUP and panic occurred as following.
smi_timeout was called after smi_event_handler,
kcs_event and hangs at port_inb()
trying to access I/O port after release.

    [exception RIP: port_inb+19]
    RIP: ffffffffc0473053  RSP: ffff88069fdc3d80  RFLAGS: 00000006
    RAX: ffff8806800f8e00  RBX: ffff880682bd9400  RCX: 0000000000000000
    RDX: 0000000000000ca3  RSI: 0000000000000ca3  RDI: ffff8806800f8e40
    RBP: ffff88069fdc3d80   R8: ffffffff81d86dfc   R9: ffffffff81e36426
    R10: 00000000000509f0  R11: 0000000000100000  R12: 0000000000]:000000
    R13: 0000000000000000  R14: 0000000000000246  R15: ffff8806800f8e00
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0000
 --- <NMI exception stack> ---

To fix the problem I defined a flag, timer_can_start,
as member of struct smi_info.
The flag is enabled immediately after initializing the timer
and disabled immediately before waiting for timer deletion.

Fixes: 0cfec916e8 ("ipmi: Start the timer and thread on internal msgs")
Signed-off-by: Yamazaki Masamitsu <m-yamazaki@ah.jp.nec.com>
[Adjusted for recent changes in the driver.]
[Some fairly major changes went into the IPMI driver in 4.15, so this
 required a backport as the code had changed and moved to a different
 file.  The 4.14 version of this patch moved some code under an
 if statement and there was an API change causing it to not apply to
 4.4-4.6.]
Signed-off-by: Corey Minyard <cminyard@mvista.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-12-16 10:33:56 +01:00
..
agp agp/uninorth: fix a memleak in create_gatt_table 2015-10-02 22:57:59 +10:00
hw_random hwrng: core - Don't use a stack buffer in add_early_randomness() 2016-11-18 10:48:36 +01:00
ipmi ipmi: Stop timers before cleaning up the module 2017-12-16 10:33:56 +01:00
mwave
pcmcia pcmcia: remove left-over %Z format 2017-06-07 12:06:01 +02:00
tpm tpm: Replace device number bitmap with IDR 2017-08-06 19:19:43 -07:00
xilinx_hwicap char:xilinx_hwicap:buffer_icap - change 1/0 to true/false for bool type variable in function buffer_icap_set_configuration(). 2015-06-12 16:58:33 -07:00
xillybus char: xillybus: Allow 64-bit DMA on PCIe interface 2015-08-05 12:27:09 -07:00
apm-emulation.c
applicom.c
applicom.h
bfin-otp.c
bsr.c
ds1302.c
ds1620.c
dsp56k.c
dtlk.c
efirtc.c drivers/char: make efirtc.c driver explicitly non-modular 2015-09-20 19:32:35 -07:00
generic_nvram.c
genrtc.c
hangcheck-timer.c hangcheck-timer: cleanup casting in hangcheck_init() 2014-11-07 11:24:01 -08:00
hpet.c drivers/char: make hpet.c explicitly non-modular 2015-09-20 19:32:35 -07:00
Kconfig char: lack of bool string made CONFIG_DEVPORT always on 2017-04-21 09:30:06 +02:00
lp.c char: lp: fix possible integer overflow in lp_setup() 2017-05-25 14:30:07 +02:00
Makefile hwmon: Rename i8k driver to dell-smm-hwmon and move it to hwmon tree 2015-05-24 12:48:12 -07:00
mbcs.c
mbcs.h
mem.c drivers: char: mem: Fix wraparound check to allow mappings up to the end 2017-06-14 13:16:26 +02:00
misc.c char: make misc_deregister a void function 2015-08-05 10:35:49 -07:00
mmtimer.c
mspec.c
nsc_gpio.c
nvram.c char/nvram: Use bitwise OR to obtain Atari video mode data 2015-08-05 13:30:16 -07:00
nwbutton.c
nwbutton.h
nwflash.c
pc8736x_gpio.c
ppdev.c
ps3flash.c
random.c random: properly align get_random_int_hash 2017-06-14 13:16:23 +02:00
raw.c writeback: separate out include/linux/backing-dev-defs.h 2015-06-02 08:33:34 -06:00
rtc.c
scx200_gpio.c
snsc.c drivers/char: make SGI snsc.c driver explicitly non-modular 2015-09-20 19:32:35 -07:00
snsc.h
snsc_event.c
sonypi.c
tb0219.c
tile-srom.c fs: move struct kiocb to fs.h 2015-03-25 20:28:11 -04:00
tlclk.c
toshiba.c toshiba laptop: replace ioremap_cache with ioremap 2015-08-05 17:26:00 -07:00
ttyprintk.c
uv_mmtimer.c
virtio_console.c virtio_console: fix a crash in config_work_handler 2017-07-05 14:37:18 +02:00