On Fri, Jan 25, 2019 at 10:30:59AM +0800, Yang Yingliang wrote: > When we excute the following commands, we got oops > rmmod ipmi_si > cat /proc/ioports > snip... > > If io_setup is called successful in try_smi_init() but try_smi_init() > goes out_err before calling ipmi_register_smi(), so ipmi_unregister_smi() > will not be called while removing module. It leads to the resource that > allocated in io_setup() can not be freed, but the name(DEVICE_NAME) of > resource is freed while removing the module. It causes use-after-free > when cat /proc/ioports. > > Fix this by calling shutdown_smi() while removing the module and don't > call release_region() if request_region() is not called to avoid error > prints. > > Fixes: 93c303d2045b ("ipmi_si: Clean up shutdown a bit") > Cc: stable@xxxxxxxxxxxxxxx > Reported-by: NuoHan Qiao <qiaonuohan@xxxxxxxxxx> > Signed-off-by: Yang Yingliang <yangyingliang@xxxxxxxxxx> > --- > drivers/char/ipmi/ipmi_si_intf.c | 2 ++ > drivers/char/ipmi/ipmi_si_port_io.c | 3 +++ > 2 files changed, 5 insertions(+) > > diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c > index dc8603d..635e98a 100644 > --- a/drivers/char/ipmi/ipmi_si_intf.c > +++ b/drivers/char/ipmi/ipmi_si_intf.c > @@ -2235,6 +2235,8 @@ static void cleanup_one_si(struct smi_info *smi_info) > > if (smi_info->intf) > ipmi_unregister_smi(smi_info->intf); > + else > + shutdown_smi(smi_info); This is completely the wrong way to fix this. The general principle is that a function cleans up for itself if it returns an error. If you add hacks other places for a function failing you end up with a mess. I think the right way to fix this is to add something like: if (rv && new_smi->io.io_size && smi_info->io.io_cleanup) { smi_info->io.io_cleanup(&smi_info->io); smi_info->io.io_cleanup = NULL; } at the end of try_smi_init(). -corey > > if (smi_info->pdev) { > if (smi_info->pdev_registered) > diff --git a/drivers/char/ipmi/ipmi_si_port_io.c b/drivers/char/ipmi/ipmi_si_port_io.c > index ef6dffc..0c46a3f 100644 > --- a/drivers/char/ipmi/ipmi_si_port_io.c > +++ b/drivers/char/ipmi/ipmi_si_port_io.c > @@ -53,6 +53,9 @@ static void port_cleanup(struct si_sm_io *io) > unsigned int addr = io->addr_data; > int idx; > > + if (io->regsize != 1 && io->regsize != 2 && io->regsize != 4) > + return; > + > if (addr) { > for (idx = 0; idx < io->io_size; idx++) > release_region(addr + idx * io->regspacing, > -- > 1.8.3 > >