• B
    fcntl: Fix potential deadlock in send_sig{io, urg}() · 29e28b88
    Boqun Feng 提交于
    stable inclusion
    from stable-5.10.5
    commit 908030501772553dc8553792d6c97a24000ab04a
    bugzilla: 46931
    
    --------------------------------
    
    commit 8d1ddb5e upstream.
    
    Syzbot reports a potential deadlock found by the newly added recursive
    read deadlock detection in lockdep:
    
    [...] ========================================================
    [...] WARNING: possible irq lock inversion dependency detected
    [...] 5.9.0-rc2-syzkaller #0 Not tainted
    [...] --------------------------------------------------------
    [...] syz-executor.1/10214 just changed the state of lock:
    [...] ffff88811f506338 (&f->f_owner.lock){.+..}-{2:2}, at: send_sigurg+0x1d/0x200
    [...] but this lock was taken by another, HARDIRQ-safe lock in the past:
    [...]  (&dev->event_lock){-...}-{2:2}
    [...]
    [...]
    [...] and interrupts could create inverse lock ordering between them.
    [...]
    [...]
    [...] other info that might help us debug this:
    [...] Chain exists of:
    [...]   &dev->event_lock --> &new->fa_lock --> &f->f_owner.lock
    [...]
    [...]  Possible interrupt unsafe locking scenario:
    [...]
    [...]        CPU0                    CPU1
    [...]        ----                    ----
    [...]   lock(&f->f_owner.lock);
    [...]                                local_irq_disable();
    [...]                                lock(&dev->event_lock);
    [...]                                lock(&new->fa_lock);
    [...]   <Interrupt>
    [...]     lock(&dev->event_lock);
    [...]
    [...]  *** DEADLOCK ***
    
    The corresponding deadlock case is as followed:
    
    	CPU 0		CPU 1		CPU 2
    	read_lock(&fown->lock);
    			spin_lock_irqsave(&dev->event_lock, ...)
    					write_lock_irq(&filp->f_owner.lock); // wait for the lock
    			read_lock(&fown-lock); // have to wait until the writer release
    					       // due to the fairness
    	<interrupted>
    	spin_lock_irqsave(&dev->event_lock); // wait for the lock
    
    The lock dependency on CPU 1 happens if there exists a call sequence:
    
    	input_inject_event():
    	  spin_lock_irqsave(&dev->event_lock,...);
    	  input_handle_event():
    	    input_pass_values():
    	      input_to_handler():
    	        handler->event(): // evdev_event()
    	          evdev_pass_values():
    	            spin_lock(&client->buffer_lock);
    	            __pass_event():
    	              kill_fasync():
    	                kill_fasync_rcu():
    	                  read_lock(&fa->fa_lock);
    	                  send_sigio():
    	                    read_lock(&fown->lock);
    
    To fix this, make the reader in send_sigurg() and send_sigio() use
    read_lock_irqsave() and read_lock_irqrestore().
    
    Reported-by: syzbot+22e87cdf94021b984aa6@syzkaller.appspotmail.com
    Reported-by: syzbot+c5e32344981ad9f33750@syzkaller.appspotmail.com
    Signed-off-by: NBoqun Feng <boqun.feng@gmail.com>
    Signed-off-by: NJeff Layton <jlayton@kernel.org>
    Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: NChen Jun <chenjun102@huawei.com>
    Acked-by: NXie XiuQi <xiexiuqi@huawei.com>
    29e28b88
fcntl.c 23.4 KB