linux/drivers/tty
Yi Yang f1cda3c5dd tty: tty_jobctrl: fix pid memleak in disassociate_ctty()
[ Upstream commit 11e7f27b79 ]

There is a pid leakage:
------------------------------
unreferenced object 0xffff88810c181940 (size 224):
  comm "sshd", pid 8191, jiffies 4294946950 (age 524.570s)
  hex dump (first 32 bytes):
    01 00 00 00 00 00 00 00 00 00 00 00 ad 4e ad de  .............N..
    ff ff ff ff 6b 6b 6b 6b ff ff ff ff ff ff ff ff  ....kkkk........
  backtrace:
    [<ffffffff814774e6>] kmem_cache_alloc+0x5c6/0x9b0
    [<ffffffff81177342>] alloc_pid+0x72/0x570
    [<ffffffff81140ac4>] copy_process+0x1374/0x2470
    [<ffffffff81141d77>] kernel_clone+0xb7/0x900
    [<ffffffff81142645>] __se_sys_clone+0x85/0xb0
    [<ffffffff8114269b>] __x64_sys_clone+0x2b/0x30
    [<ffffffff83965a72>] do_syscall_64+0x32/0x80
    [<ffffffff83a00085>] entry_SYSCALL_64_after_hwframe+0x61/0xc6

It turns out that there is a race condition between disassociate_ctty() and
tty_signal_session_leader(), which caused this leakage.

The pid memleak is triggered by the following race:
task[sshd]                     task[bash]
-----------------------        -----------------------
                               disassociate_ctty();
                               spin_lock_irq(&current->sighand->siglock);
                               put_pid(current->signal->tty_old_pgrp);
                               current->signal->tty_old_pgrp = NULL;
                               tty = tty_kref_get(current->signal->tty);
                               spin_unlock_irq(&current->sighand->siglock);
tty_vhangup();
tty_lock(tty);
...
tty_signal_session_leader();
spin_lock_irq(&p->sighand->siglock);
...
if (tty->ctrl.pgrp) //tty->ctrl.pgrp is not NULL
p->signal->tty_old_pgrp = get_pid(tty->ctrl.pgrp); //An extra get
spin_unlock_irq(&p->sighand->siglock);
...
tty_unlock(tty);
                               if (tty) {
                                   tty_lock(tty);
                                   ...
                                   put_pid(tty->ctrl.pgrp);
                                   tty->ctrl.pgrp = NULL; //It's too late
                                   ...
                                   tty_unlock(tty);
                               }

The issue is believed to be introduced by commit c8bcd9c5be ("tty:
Fix ->session locking") who moves the unlock of siglock in
disassociate_ctty() above "if (tty)", making a small window allowing
tty_signal_session_leader() to kick in. It can be easily reproduced by
adding a delay before "if (tty)" and at the entrance of
tty_signal_session_leader().

To fix this issue, we move "put_pid(current->signal->tty_old_pgrp)" after
"tty->ctrl.pgrp = NULL".

Fixes: c8bcd9c5be ("tty: Fix ->session locking")
Signed-off-by: Yi Yang <yiyang13@huawei.com>
Co-developed-by: GUO Zihua <guozihua@huawei.com>
Signed-off-by: GUO Zihua <guozihua@huawei.com>
Link: https://lore.kernel.org/r/20230831023329.165737-1-yiyang13@huawei.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
History 2023-11-20 11:52:09 +01:00
..
hvc hvc/xen: prevent concurrent accesses to the shared ring 2023-03-30 12:49:09 +02:00
ipwireless tty: drop put_tty_driver 2021-07-27 12:17:21 +02:00
serdev tty: Replace acpi_bus_get_device() 2022-01-31 14:30:06 +01:00
serial tty: 8250: Add Brainboxes Oxford Semiconductor-based quirks 2023-11-08 14:11:05 +01:00
vt vc_screen: reload load of struct vc_data pointer in vcs_write() to avoid UAF 2023-05-24 17:32:51 +01:00
amiserial.c tty: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
ehv_bytechan.c tty: drop put_tty_driver 2021-07-27 12:17:21 +02:00
goldfish.c tty: goldfish: Fix free_irq() on remove 2022-06-10 13:31:31 +02:00
Kconfig tty: add rpmsg driver 2021-10-21 12:35:35 +02:00
Makefile tty: add rpmsg driver 2021-10-21 12:35:35 +02:00
mips_ejtag_fdc.c serial: Convert SERIAL_XMIT_SIZE to UART_XMIT_SIZE 2022-06-27 14:41:31 +02:00
moxa.c tty: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
mxser.c tty: mxser: remove redundant assignment to hwid 2022-09-01 17:59:36 +02:00
n_gsm.c tty: n_gsm: fix race condition in status line change on dead connections 2023-11-08 14:11:03 +01:00
n_hdlc.c tty: n_hdlc: remove HDLC_MAGIC 2022-09-22 16:12:34 +02:00
n_null.c tty: make tty_ldisc_ops a param in tty_unregister_ldisc 2021-05-13 16:57:16 +02:00
n_tty.c tty: fix hang on tty device with no_room set 2023-08-03 10:23:53 +02:00
nozomi.c tty: drop put_tty_driver 2021-07-27 12:17:21 +02:00
pty.c tty: Make ->set_termios() old ktermios const 2022-08-30 14:22:35 +02:00
rpmsg_tty.c tty: rpmsg: Fix race condition releasing tty port 2022-01-26 14:50:26 +01:00
synclink_gt.c tty: synclink_gt: remove MGSL_MAGIC 2022-09-22 16:12:34 +02:00
sysrq.c Merge branch 'rework/kthreads' into for-linus 2022-06-23 19:11:28 +02:00
tty.h tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH 2023-05-11 23:03:01 +09:00
tty_audit.c tty: audit: move some local functions out of tty.h 2021-04-15 10:24:58 +02:00
tty_baudrate.c tty: Fix comment style in tty_termios_input_baud_rate() 2022-08-30 14:22:34 +02:00
tty_buffer.c tty: Fix lookahead_buf crash with serdev 2022-08-30 14:31:53 +02:00
tty_io.c tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH 2023-05-11 23:03:01 +09:00
tty_ioctl.c tty: Prevent writing chars during tcsetattr TCSADRAIN/FLUSH 2023-05-11 23:03:01 +09:00
tty_jobctrl.c tty: tty_jobctrl: fix pid memleak in disassociate_ctty() 2023-11-20 11:52:09 +01:00
tty_ldisc.c tty: reformat kernel-doc in tty_ldisc.c 2021-11-26 16:27:43 +01:00
tty_ldsem.c tty/ldsem: Fix syntax errors in comments 2021-12-21 09:15:49 +01:00
tty_mutex.c tty: remove TTY_MAGIC 2022-09-22 16:12:34 +02:00
tty_port.c tty: Implement lookahead to process XON/XOFF timely 2022-06-10 13:51:31 +02:00
ttynull.c tty: drop put_tty_driver 2021-07-27 12:17:21 +02:00
vcc.c termios: start unifying non-UAPI parts of asm/termios.h 2022-09-09 10:44:34 +02:00