Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: maps: pcmciamtd: fix possible sleep-in-atomic-context bugs in pcmciamtd_set_vpp()

The driver may sleep while holding a spinlock.
The function call path (from bottom to top) in Linux 4.19 is:

drivers/pcmcia/pcmcia_resource.c, 312:
mutex_lock in pcmcia_fixup_vpp
drivers/mtd/maps/pcmciamtd.c, 309:
pcmcia_fixup_vpp in pcmciamtd_set_vpp
drivers/mtd/maps/pcmciamtd.c, 306:
_raw_spin_lock_irqsave in pcmciamtd_set_vpp

drivers/pcmcia/pcmcia_resource.c, 312:
mutex_lock in pcmcia_fixup_vpp
drivers/mtd/maps/pcmciamtd.c, 312:
pcmcia_fixup_vpp in pcmciamtd_set_vpp
drivers/mtd/maps/pcmciamtd.c, 306:
_raw_spin_lock_irqsave in pcmciamtd_set_vp

mutex_lock() may sleep at runtime.

To fix these bugs, the spinlock is replaced with a mutex.

These bugs are found by a static analysis tool STCheck written by
myself.

Signed-off-by: Jia-Ju Bai <baijiaju1990@gmail.com>
Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

authored by

Jia-Ju Bai and committed by
Miquel Raynal
2a0b390b e42617b8

+3 -4
+3 -4
drivers/mtd/maps/pcmciamtd.c
··· 294 294 } 295 295 296 296 297 - static DEFINE_SPINLOCK(pcmcia_vpp_lock); 297 + static DEFINE_MUTEX(pcmcia_vpp_lock); 298 298 static int pcmcia_vpp_refcnt; 299 299 static void pcmciamtd_set_vpp(struct map_info *map, int on) 300 300 { 301 301 struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; 302 302 struct pcmcia_device *link = dev->p_dev; 303 - unsigned long flags; 304 303 305 304 pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp); 306 - spin_lock_irqsave(&pcmcia_vpp_lock, flags); 305 + mutex_lock(&pcmcia_vpp_lock); 307 306 if (on) { 308 307 if (++pcmcia_vpp_refcnt == 1) /* first nested 'on' */ 309 308 pcmcia_fixup_vpp(link, dev->vpp); ··· 310 311 if (--pcmcia_vpp_refcnt == 0) /* last nested 'off' */ 311 312 pcmcia_fixup_vpp(link, 0); 312 313 } 313 - spin_unlock_irqrestore(&pcmcia_vpp_lock, flags); 314 + mutex_unlock(&pcmcia_vpp_lock); 314 315 } 315 316 316 317