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

drivers: char: tlclk.c: Avoid data race between init and interrupt handler

After registering character device the file operation callbacks can be
called. The open callback registers interrupt handler.
Therefore interrupt handler can execute in parallel with rest of the init
function. To avoid such data race initialize telclk_interrupt variable
and struct alarm_events before registering character device.

Found by Linux Driver Verification project (linuxtesting.org).

Signed-off-by: Madhuparna Bhowmik <madhuparnabhowmik10@gmail.com>
Link: https://lore.kernel.org/r/20200417153451.1551-1-madhuparnabhowmik10@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Madhuparna Bhowmik and committed by
Greg Kroah-Hartman
44b8fb6e c18c1f10

+11 -8
+11 -8
drivers/char/tlclk.c
··· 777 777 { 778 778 int ret; 779 779 780 - ret = register_chrdev(tlclk_major, "telco_clock", &tlclk_fops); 781 - if (ret < 0) { 782 - printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major); 783 - return ret; 784 - } 785 - tlclk_major = ret; 780 + telclk_interrupt = (inb(TLCLK_REG7) & 0x0f); 781 + 786 782 alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL); 787 783 if (!alarm_events) { 788 784 ret = -ENOMEM; 789 785 goto out1; 790 786 } 787 + 788 + ret = register_chrdev(tlclk_major, "telco_clock", &tlclk_fops); 789 + if (ret < 0) { 790 + printk(KERN_ERR "tlclk: can't get major %d.\n", tlclk_major); 791 + kfree(alarm_events); 792 + return ret; 793 + } 794 + tlclk_major = ret; 791 795 792 796 /* Read telecom clock IRQ number (Set by BIOS) */ 793 797 if (!request_region(TLCLK_BASE, 8, "telco_clock")) { ··· 800 796 ret = -EBUSY; 801 797 goto out2; 802 798 } 803 - telclk_interrupt = (inb(TLCLK_REG7) & 0x0f); 804 799 805 800 if (0x0F == telclk_interrupt ) { /* not MCPBL0010 ? */ 806 801 printk(KERN_ERR "telclk_interrupt = 0x%x non-mcpbl0010 hw.\n", ··· 840 837 release_region(TLCLK_BASE, 8); 841 838 out2: 842 839 kfree(alarm_events); 843 - out1: 844 840 unregister_chrdev(tlclk_major, "telco_clock"); 841 + out1: 845 842 return ret; 846 843 } 847 844