All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, stable@kernel.org,
	Jann Horn <jannh@google.com>, Jiri Slaby <jirislaby@kernel.org>
Subject: [PATCH 5.4 12/54] tty: Fix ->session locking
Date: Thu, 10 Dec 2020 15:26:49 +0100	[thread overview]
Message-ID: <20201210142602.635230368@linuxfoundation.org> (raw)
In-Reply-To: <20201210142602.037095225@linuxfoundation.org>

From: Jann Horn <jannh@google.com>

commit c8bcd9c5be24fb9e6132e97da5a35e55a83e36b9 upstream.

Currently, locking of ->session is very inconsistent; most places
protect it using the legacy tty mutex, but disassociate_ctty(),
__do_SAK(), tiocspgrp() and tiocgsid() don't.
Two of the writers hold the ctrl_lock (because they already need it for
->pgrp), but __proc_set_tty() doesn't do that yet.

On a PREEMPT=y system, an unprivileged user can theoretically abuse
this broken locking to read 4 bytes of freed memory via TIOCGSID if
tiocgsid() is preempted long enough at the right point. (Other things
might also go wrong, especially if root-only ioctls are involved; I'm
not sure about that.)

Change the locking on ->session such that:

 - tty_lock() is held by all writers: By making disassociate_ctty()
   hold it. This should be fine because the same lock can already be
   taken through the call to tty_vhangup_session().
   The tricky part is that we need to shorten the area covered by
   siglock to be able to take tty_lock() without ugly retry logic; as
   far as I can tell, this should be fine, since nothing in the
   signal_struct is touched in the `if (tty)` branch.
 - ctrl_lock is held by all writers: By changing __proc_set_tty() to
   hold the lock a little longer.
 - All readers that aren't holding tty_lock() hold ctrl_lock: By
   adding locking to tiocgsid() and __do_SAK(), and expanding the area
   covered by ctrl_lock in tiocspgrp().

Cc: stable@kernel.org
Signed-off-by: Jann Horn <jannh@google.com>
Reviewed-by: Jiri Slaby <jirislaby@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

---
 drivers/tty/tty_io.c      |    7 ++++++-
 drivers/tty/tty_jobctrl.c |   44 +++++++++++++++++++++++++++++++-------------
 include/linux/tty.h       |    4 ++++
 3 files changed, 41 insertions(+), 14 deletions(-)

--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2894,10 +2894,14 @@ void __do_SAK(struct tty_struct *tty)
 	struct task_struct *g, *p;
 	struct pid *session;
 	int		i;
+	unsigned long flags;
 
 	if (!tty)
 		return;
-	session = tty->session;
+
+	spin_lock_irqsave(&tty->ctrl_lock, flags);
+	session = get_pid(tty->session);
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
 	tty_ldisc_flush(tty);
 
@@ -2929,6 +2933,7 @@ void __do_SAK(struct tty_struct *tty)
 		task_unlock(p);
 	} while_each_thread(g, p);
 	read_unlock(&tasklist_lock);
+	put_pid(session);
 #endif
 }
 
--- a/drivers/tty/tty_jobctrl.c
+++ b/drivers/tty/tty_jobctrl.c
@@ -103,8 +103,8 @@ static void __proc_set_tty(struct tty_st
 	put_pid(tty->session);
 	put_pid(tty->pgrp);
 	tty->pgrp = get_pid(task_pgrp(current));
-	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 	tty->session = get_pid(task_session(current));
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 	if (current->signal->tty) {
 		tty_debug(tty, "current tty %s not NULL!!\n",
 			  current->signal->tty->name);
@@ -293,20 +293,23 @@ void disassociate_ctty(int on_exit)
 	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);
+
 	if (tty) {
 		unsigned long flags;
+
+		tty_lock(tty);
 		spin_lock_irqsave(&tty->ctrl_lock, flags);
 		put_pid(tty->session);
 		put_pid(tty->pgrp);
 		tty->session = NULL;
 		tty->pgrp = NULL;
 		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+		tty_unlock(tty);
 		tty_kref_put(tty);
 	}
 
-	spin_unlock_irq(&current->sighand->siglock);
 	/* Now clear signal->tty under the lock */
 	read_lock(&tasklist_lock);
 	session_clear_tty(task_session(current));
@@ -477,14 +480,19 @@ static int tiocspgrp(struct tty_struct *
 		return -ENOTTY;
 	if (retval)
 		return retval;
-	if (!current->signal->tty ||
-	    (current->signal->tty != real_tty) ||
-	    (real_tty->session != task_session(current)))
-		return -ENOTTY;
+
 	if (get_user(pgrp_nr, p))
 		return -EFAULT;
 	if (pgrp_nr < 0)
 		return -EINVAL;
+
+	spin_lock_irq(&real_tty->ctrl_lock);
+	if (!current->signal->tty ||
+	    (current->signal->tty != real_tty) ||
+	    (real_tty->session != task_session(current))) {
+		retval = -ENOTTY;
+		goto out_unlock_ctrl;
+	}
 	rcu_read_lock();
 	pgrp = find_vpid(pgrp_nr);
 	retval = -ESRCH;
@@ -494,12 +502,12 @@ static int tiocspgrp(struct tty_struct *
 	if (session_of_pgrp(pgrp) != task_session(current))
 		goto out_unlock;
 	retval = 0;
-	spin_lock_irq(&real_tty->ctrl_lock);
 	put_pid(real_tty->pgrp);
 	real_tty->pgrp = get_pid(pgrp);
-	spin_unlock_irq(&real_tty->ctrl_lock);
 out_unlock:
 	rcu_read_unlock();
+out_unlock_ctrl:
+	spin_unlock_irq(&real_tty->ctrl_lock);
 	return retval;
 }
 
@@ -511,20 +519,30 @@ out_unlock:
  *
  *	Obtain the session id of the tty. If there is no session
  *	return an error.
- *
- *	Locking: none. Reference to current->signal->tty is safe.
  */
 static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
+	unsigned long flags;
+	pid_t sid;
+
 	/*
 	 * (tty == real_tty) is a cheap way of
 	 * testing if the tty is NOT a master pty.
 	*/
 	if (tty == real_tty && current->signal->tty != real_tty)
 		return -ENOTTY;
+
+	spin_lock_irqsave(&real_tty->ctrl_lock, flags);
 	if (!real_tty->session)
-		return -ENOTTY;
-	return put_user(pid_vnr(real_tty->session), p);
+		goto err;
+	sid = pid_vnr(real_tty->session);
+	spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+
+	return put_user(sid, p);
+
+err:
+	spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+	return -ENOTTY;
 }
 
 /*
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -306,6 +306,10 @@ struct tty_struct {
 	struct termiox *termiox;	/* May be NULL for unsupported */
 	char name[64];
 	struct pid *pgrp;		/* Protected by ctrl lock */
+	/*
+	 * Writes protected by both ctrl lock and legacy mutex, readers must use
+	 * at least one of them.
+	 */
 	struct pid *session;
 	unsigned long flags;
 	int count;



  parent reply	other threads:[~2020-12-10 14:39 UTC|newest]

Thread overview: 58+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-10 14:26 [PATCH 5.4 00/54] 5.4.83-rc1 review Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 01/54] pinctrl: baytrail: Replace WARN with dev_info_once when setting direct-irq pin to output Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 02/54] pinctrl: baytrail: Fix pin being driven low for a while on gpiod_get(..., GPIOD_OUT_HIGH) Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 03/54] Partially revert bpf: Zero-fill re-used per-cpu map element Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 04/54] usb: gadget: f_fs: Use local copy of descriptors for userspace copy Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 05/54] USB: serial: kl5kusb105: fix memleak on open Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 06/54] USB: serial: ch341: add new Product ID for CH341A Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 07/54] USB: serial: ch341: sort device-id entries Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 08/54] USB: serial: option: add Fibocom NL668 variants Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 09/54] USB: serial: option: add support for Thales Cinterion EXS82 Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 10/54] USB: serial: option: fix Quectel BG96 matching Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 11/54] tty: Fix ->pgrp locking in tiocspgrp() Greg Kroah-Hartman
2020-12-10 14:26 ` Greg Kroah-Hartman [this message]
2020-12-10 14:26 ` [PATCH 5.4 13/54] ALSA: hda/realtek: Fix bass speaker DAC assignment on Asus Zephyrus G14 Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 14/54] ALSA: hda/realtek: Add mute LED quirk to yet another HP x360 model Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 15/54] ALSA: hda/realtek: Enable headset of ASUS UX482EG & B9400CEA with ALC294 Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 16/54] ALSA: hda/realtek - Add new codec supported for ALC897 Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 17/54] ALSA: hda/generic: Add option to enforce preferred_dacs pairs Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 18/54] ftrace: Fix updating FTRACE_FL_TRAMP Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 19/54] cifs: allow syscalls to be restarted in __smb_send_rqst() Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 20/54] cifs: fix potential use-after-free in cifs_echo_request() Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 21/54] s390/pci: fix CPU address in MSI for directed IRQ Greg Kroah-Hartman
2020-12-10 16:34   ` Niklas Schnelle
2020-12-10 16:46     ` Greg Kroah-Hartman
2020-12-10 14:26 ` [PATCH 5.4 22/54] i2c: imx: Dont generate STOP condition if arbitration has been lost Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 23/54] thunderbolt: Fix use-after-free in remove_unplugged_switch() Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 24/54] drm/i915/gt: Program mocs:63 for cache eviction on gen9 Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 25/54] scsi: mpt3sas: Fix ioctl timeout Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 26/54] dm writecache: fix the maximum number of arguments Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 27/54] powerpc/64s/powernv: Fix memory corruption when saving SLB entries on MCE Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 28/54] genirq/irqdomain: Add an irq_create_mapping_affinity() function Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 29/54] powerpc/pseries: Pass MSI affinity to irq_create_mapping() Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 30/54] dm: fix bug with RCU locking in dm_blk_report_zones Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 31/54] dm: remove invalid sparse __acquires and __releases annotations Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 32/54] x86/uprobes: Do not use prefixes.nbytes when looping over prefixes.bytes Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 33/54] coredump: fix core_pattern parse error Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 34/54] mm: list_lru: set shrinker map bit when child nr_items is not zero Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 35/54] mm/swapfile: do not sleep with a spin lock held Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 36/54] speakup: Reject setting the speakup line discipline outside of speakup Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 37/54] i2c: imx: Fix reset of I2SR_IAL flag Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 38/54] i2c: imx: Check for I2SR_IAL after every byte Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 39/54] spi: bcm2835: Release the DMA channel if probe fails after dma_init Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 40/54] iommu/amd: Set DTE[IntTabLen] to represent 512 IRTEs Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 41/54] tracing: Fix userstacktrace option for instances Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 42/54] lib/syscall: fix syscall registers retrieval on 32-bit platforms Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 43/54] can: af_can: can_rx_unregister(): remove WARN() statement from list operation sanity check Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 44/54] gfs2: check for empty rgrp tree in gfs2_ri_update Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 45/54] netfilter: ipset: prevent uninit-value in hash_ip6_add Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 46/54] tipc: fix a deadlock when flushing scheduled work Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 47/54] ASoC: wm_adsp: fix error return code in wm_adsp_load() Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 48/54] rtw88: debug: Fix uninitialized memory in debugfs code Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 49/54] i2c: qup: Fix error return code in qup_i2c_bam_schedule_desc() Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 50/54] dm writecache: remove BUG() and fail gracefully instead Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 51/54] Input: i8042 - fix error return code in i8042_setup_aux() Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 52/54] netfilter: nf_tables: avoid false-postive lockdep splat Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 53/54] netfilter: nftables_offload: set address type in control dissector Greg Kroah-Hartman
2020-12-10 14:27 ` [PATCH 5.4 54/54] x86/insn-eval: Use new for_each_insn_prefix() macro to loop over prefixes bytes Greg Kroah-Hartman
2020-12-10 21:04 ` [PATCH 5.4 00/54] 5.4.83-rc1 review Jon Hunter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201210142602.635230368@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=jannh@google.com \
    --cc=jirislaby@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable@kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.