From 5d0fdf1e01899805b6c2c0b789a707dcb731b1ea Mon Sep 17 00:00:00 2001
From: Alan Cox <alan@lxorguk.ukuu.org.uk>
Date: Wed, 30 Apr 2008 00:53:31 -0700
Subject: [PATCH] tty_io: fix remaining pid struct locking

This fixes the last couple of pid struct locking failures I know about.

[oleg@tv-sign.ru: clean up do_task_stat()]
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/char/tty_io.c | 28 +++++++++++++++++++++++++++-
 fs/proc/array.c       |  4 +++-
 include/linux/tty.h   |  1 +
 3 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index c8aa318eaa18..2460c4c76161 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3173,6 +3173,27 @@ unlock:
 	return ret;
 }
 
+/**
+ *	tty_get_pgrp	-	return a ref counted pgrp pid
+ *	@tty: tty to read
+ *
+ *	Returns a refcounted instance of the pid struct for the process
+ *	group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+	unsigned long flags;
+	struct pid *pgrp;
+
+	spin_lock_irqsave(&tty->ctrl_lock, flags);
+	pgrp = get_pid(tty->pgrp);
+	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+	return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
 /**
  *	tiocgpgrp		-	get process group
  *	@tty: tty passed by user
@@ -3187,13 +3208,18 @@ unlock:
 
 static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
 {
+	struct pid *pid;
+	int ret;
 	/*
 	 * (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;
-	return put_user(pid_vnr(real_tty->pgrp), p);
+	pid = tty_get_pgrp(real_tty);
+	ret =  put_user(pid_vnr(pid), p);
+	put_pid(pid);
+	return ret;
 }
 
 /**
diff --git a/fs/proc/array.c b/fs/proc/array.c
index b07a71002f2f..c135cbdd9127 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -429,7 +429,9 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
 		struct signal_struct *sig = task->signal;
 
 		if (sig->tty) {
-			tty_pgrp = pid_nr_ns(sig->tty->pgrp, ns);
+			struct pid *pgrp = tty_get_pgrp(sig->tty);
+			tty_pgrp = pid_nr_ns(pgrp, ns);
+			put_pid(pgrp);
 			tty_nr = new_encode_dev(tty_devnum(sig->tty));
 		}
 
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 381085e45cca..2699298b00ef 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -297,6 +297,7 @@ extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
 extern void tty_write_message(struct tty_struct *tty, char *msg);
 
 extern int is_current_pgrp_orphaned(void);
+extern struct pid *tty_get_pgrp(struct tty_struct *tty);
 extern int is_ignored(int sig);
 extern int tty_signal(int sig, struct tty_struct *tty);
 extern void tty_hangup(struct tty_struct * tty);
-- 
2.20.1