1e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2a1235b3eSNicolas Pitre /* 3a1235b3eSNicolas Pitre * Copyright (C) 1991, 1992 Linus Torvalds 4a1235b3eSNicolas Pitre */ 5a1235b3eSNicolas Pitre 6a1235b3eSNicolas Pitre #include <linux/types.h> 7a1235b3eSNicolas Pitre #include <linux/errno.h> 8a1235b3eSNicolas Pitre #include <linux/signal.h> 9a1235b3eSNicolas Pitre #include <linux/sched/signal.h> 10a1235b3eSNicolas Pitre #include <linux/sched/task.h> 11a1235b3eSNicolas Pitre #include <linux/tty.h> 12a1235b3eSNicolas Pitre #include <linux/fcntl.h> 13a1235b3eSNicolas Pitre #include <linux/uaccess.h> 1498602c01SGreg Kroah-Hartman #include "tty.h" 15a1235b3eSNicolas Pitre 16a1235b3eSNicolas Pitre static int is_ignored(int sig) 17a1235b3eSNicolas Pitre { 18a1235b3eSNicolas Pitre return (sigismember(¤t->blocked, sig) || 19a1235b3eSNicolas Pitre current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); 20a1235b3eSNicolas Pitre } 21a1235b3eSNicolas Pitre 22a1235b3eSNicolas Pitre /** 23a1235b3eSNicolas Pitre * tty_check_change - check for POSIX terminal changes 24a1235b3eSNicolas Pitre * @tty: tty to check 25bc38fe24SLee Jones * @sig: signal to send 26a1235b3eSNicolas Pitre * 27a1235b3eSNicolas Pitre * If we try to write to, or set the state of, a terminal and we're 28a1235b3eSNicolas Pitre * not in the foreground, send a SIGTTOU. If the signal is blocked or 29a1235b3eSNicolas Pitre * ignored, go ahead and perform the operation. (POSIX 7.2) 30a1235b3eSNicolas Pitre * 31*64d608dbSJiri Slaby * Locking: ctrl.lock 32a1235b3eSNicolas Pitre */ 33a1235b3eSNicolas Pitre int __tty_check_change(struct tty_struct *tty, int sig) 34a1235b3eSNicolas Pitre { 35a1235b3eSNicolas Pitre unsigned long flags; 36a1235b3eSNicolas Pitre struct pid *pgrp, *tty_pgrp; 37a1235b3eSNicolas Pitre int ret = 0; 38a1235b3eSNicolas Pitre 39a1235b3eSNicolas Pitre if (current->signal->tty != tty) 40a1235b3eSNicolas Pitre return 0; 41a1235b3eSNicolas Pitre 42a1235b3eSNicolas Pitre rcu_read_lock(); 43a1235b3eSNicolas Pitre pgrp = task_pgrp(current); 44a1235b3eSNicolas Pitre 45*64d608dbSJiri Slaby spin_lock_irqsave(&tty->ctrl.lock, flags); 46*64d608dbSJiri Slaby tty_pgrp = tty->ctrl.pgrp; 47*64d608dbSJiri Slaby spin_unlock_irqrestore(&tty->ctrl.lock, flags); 48a1235b3eSNicolas Pitre 49cf90c06fSDavid Emett if (tty_pgrp && pgrp != tty_pgrp) { 50a1235b3eSNicolas Pitre if (is_ignored(sig)) { 51a1235b3eSNicolas Pitre if (sig == SIGTTIN) 52a1235b3eSNicolas Pitre ret = -EIO; 53a1235b3eSNicolas Pitre } else if (is_current_pgrp_orphaned()) 54a1235b3eSNicolas Pitre ret = -EIO; 55a1235b3eSNicolas Pitre else { 56a1235b3eSNicolas Pitre kill_pgrp(pgrp, sig, 1); 57a1235b3eSNicolas Pitre set_thread_flag(TIF_SIGPENDING); 58a1235b3eSNicolas Pitre ret = -ERESTARTSYS; 59a1235b3eSNicolas Pitre } 60a1235b3eSNicolas Pitre } 61a1235b3eSNicolas Pitre rcu_read_unlock(); 62a1235b3eSNicolas Pitre 63a1235b3eSNicolas Pitre if (!tty_pgrp) 64a1235b3eSNicolas Pitre tty_warn(tty, "sig=%d, tty->pgrp == NULL!\n", sig); 65a1235b3eSNicolas Pitre 66a1235b3eSNicolas Pitre return ret; 67a1235b3eSNicolas Pitre } 68a1235b3eSNicolas Pitre 69a1235b3eSNicolas Pitre int tty_check_change(struct tty_struct *tty) 70a1235b3eSNicolas Pitre { 71a1235b3eSNicolas Pitre return __tty_check_change(tty, SIGTTOU); 72a1235b3eSNicolas Pitre } 73a1235b3eSNicolas Pitre EXPORT_SYMBOL(tty_check_change); 74a1235b3eSNicolas Pitre 75a1235b3eSNicolas Pitre void proc_clear_tty(struct task_struct *p) 76a1235b3eSNicolas Pitre { 77a1235b3eSNicolas Pitre unsigned long flags; 78a1235b3eSNicolas Pitre struct tty_struct *tty; 79d4e1d903SXiaofei Tan 80a1235b3eSNicolas Pitre spin_lock_irqsave(&p->sighand->siglock, flags); 81a1235b3eSNicolas Pitre tty = p->signal->tty; 82a1235b3eSNicolas Pitre p->signal->tty = NULL; 83a1235b3eSNicolas Pitre spin_unlock_irqrestore(&p->sighand->siglock, flags); 84a1235b3eSNicolas Pitre tty_kref_put(tty); 85a1235b3eSNicolas Pitre } 86a1235b3eSNicolas Pitre 87a1235b3eSNicolas Pitre /** 88a1235b3eSNicolas Pitre * proc_set_tty - set the controlling terminal 89bc38fe24SLee Jones * @tty: tty structure 90a1235b3eSNicolas Pitre * 91a1235b3eSNicolas Pitre * Only callable by the session leader and only if it does not already have 92a1235b3eSNicolas Pitre * a controlling terminal. 93a1235b3eSNicolas Pitre * 94a1235b3eSNicolas Pitre * Caller must hold: tty_lock() 95a1235b3eSNicolas Pitre * a readlock on tasklist_lock 96a1235b3eSNicolas Pitre * sighand lock 97a1235b3eSNicolas Pitre */ 98a1235b3eSNicolas Pitre static void __proc_set_tty(struct tty_struct *tty) 99a1235b3eSNicolas Pitre { 100a1235b3eSNicolas Pitre unsigned long flags; 101a1235b3eSNicolas Pitre 102*64d608dbSJiri Slaby spin_lock_irqsave(&tty->ctrl.lock, flags); 103a1235b3eSNicolas Pitre /* 104a1235b3eSNicolas Pitre * The session and fg pgrp references will be non-NULL if 105a1235b3eSNicolas Pitre * tiocsctty() is stealing the controlling tty 106a1235b3eSNicolas Pitre */ 107*64d608dbSJiri Slaby put_pid(tty->ctrl.session); 108*64d608dbSJiri Slaby put_pid(tty->ctrl.pgrp); 109*64d608dbSJiri Slaby tty->ctrl.pgrp = get_pid(task_pgrp(current)); 110*64d608dbSJiri Slaby tty->ctrl.session = get_pid(task_session(current)); 111*64d608dbSJiri Slaby spin_unlock_irqrestore(&tty->ctrl.lock, flags); 112a1235b3eSNicolas Pitre if (current->signal->tty) { 113a1235b3eSNicolas Pitre tty_debug(tty, "current tty %s not NULL!!\n", 114a1235b3eSNicolas Pitre current->signal->tty->name); 115a1235b3eSNicolas Pitre tty_kref_put(current->signal->tty); 116a1235b3eSNicolas Pitre } 117a1235b3eSNicolas Pitre put_pid(current->signal->tty_old_pgrp); 118a1235b3eSNicolas Pitre current->signal->tty = tty_kref_get(tty); 119a1235b3eSNicolas Pitre current->signal->tty_old_pgrp = NULL; 120a1235b3eSNicolas Pitre } 121a1235b3eSNicolas Pitre 122a1235b3eSNicolas Pitre static void proc_set_tty(struct tty_struct *tty) 123a1235b3eSNicolas Pitre { 124a1235b3eSNicolas Pitre spin_lock_irq(¤t->sighand->siglock); 125a1235b3eSNicolas Pitre __proc_set_tty(tty); 126a1235b3eSNicolas Pitre spin_unlock_irq(¤t->sighand->siglock); 127a1235b3eSNicolas Pitre } 128a1235b3eSNicolas Pitre 129a1235b3eSNicolas Pitre /* 130a1235b3eSNicolas Pitre * Called by tty_open() to set the controlling tty if applicable. 131a1235b3eSNicolas Pitre */ 132a1235b3eSNicolas Pitre void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty) 133a1235b3eSNicolas Pitre { 134a1235b3eSNicolas Pitre read_lock(&tasklist_lock); 135a1235b3eSNicolas Pitre spin_lock_irq(¤t->sighand->siglock); 136a1235b3eSNicolas Pitre if (current->signal->leader && 137a1235b3eSNicolas Pitre !current->signal->tty && 138*64d608dbSJiri Slaby tty->ctrl.session == NULL) { 139a1235b3eSNicolas Pitre /* 140a1235b3eSNicolas Pitre * Don't let a process that only has write access to the tty 141a1235b3eSNicolas Pitre * obtain the privileges associated with having a tty as 142a1235b3eSNicolas Pitre * controlling terminal (being able to reopen it with full 143a1235b3eSNicolas Pitre * access through /dev/tty, being able to perform pushback). 144a1235b3eSNicolas Pitre * Many distributions set the group of all ttys to "tty" and 145a1235b3eSNicolas Pitre * grant write-only access to all terminals for setgid tty 146a1235b3eSNicolas Pitre * binaries, which should not imply full privileges on all ttys. 147a1235b3eSNicolas Pitre * 148a1235b3eSNicolas Pitre * This could theoretically break old code that performs open() 149a1235b3eSNicolas Pitre * on a write-only file descriptor. In that case, it might be 150a1235b3eSNicolas Pitre * necessary to also permit this if 151a1235b3eSNicolas Pitre * inode_permission(inode, MAY_READ) == 0. 152a1235b3eSNicolas Pitre */ 153a1235b3eSNicolas Pitre if (filp->f_mode & FMODE_READ) 154a1235b3eSNicolas Pitre __proc_set_tty(tty); 155a1235b3eSNicolas Pitre } 156a1235b3eSNicolas Pitre spin_unlock_irq(¤t->sighand->siglock); 157a1235b3eSNicolas Pitre read_unlock(&tasklist_lock); 158a1235b3eSNicolas Pitre } 159a1235b3eSNicolas Pitre 160a1235b3eSNicolas Pitre struct tty_struct *get_current_tty(void) 161a1235b3eSNicolas Pitre { 162a1235b3eSNicolas Pitre struct tty_struct *tty; 163a1235b3eSNicolas Pitre unsigned long flags; 164a1235b3eSNicolas Pitre 165a1235b3eSNicolas Pitre spin_lock_irqsave(¤t->sighand->siglock, flags); 166a1235b3eSNicolas Pitre tty = tty_kref_get(current->signal->tty); 167a1235b3eSNicolas Pitre spin_unlock_irqrestore(¤t->sighand->siglock, flags); 168a1235b3eSNicolas Pitre return tty; 169a1235b3eSNicolas Pitre } 170a1235b3eSNicolas Pitre EXPORT_SYMBOL_GPL(get_current_tty); 171a1235b3eSNicolas Pitre 172a1235b3eSNicolas Pitre /* 173a1235b3eSNicolas Pitre * Called from tty_release(). 174a1235b3eSNicolas Pitre */ 175a1235b3eSNicolas Pitre void session_clear_tty(struct pid *session) 176a1235b3eSNicolas Pitre { 177a1235b3eSNicolas Pitre struct task_struct *p; 178d4e1d903SXiaofei Tan 179a1235b3eSNicolas Pitre do_each_pid_task(session, PIDTYPE_SID, p) { 180a1235b3eSNicolas Pitre proc_clear_tty(p); 181a1235b3eSNicolas Pitre } while_each_pid_task(session, PIDTYPE_SID, p); 182a1235b3eSNicolas Pitre } 183a1235b3eSNicolas Pitre 184a1235b3eSNicolas Pitre /** 185a1235b3eSNicolas Pitre * tty_signal_session_leader - sends SIGHUP to session leader 186fa441954SJiri Slaby * @tty: controlling tty 187fa441954SJiri Slaby * @exit_session: if non-zero, signal all foreground group processes 188a1235b3eSNicolas Pitre * 189a1235b3eSNicolas Pitre * Send SIGHUP and SIGCONT to the session leader and its process group. 190a1235b3eSNicolas Pitre * Optionally, signal all processes in the foreground process group. 191a1235b3eSNicolas Pitre * 192a1235b3eSNicolas Pitre * Returns the number of processes in the session with this tty 193a1235b3eSNicolas Pitre * as their controlling terminal. This value is used to drop 194a1235b3eSNicolas Pitre * tty references for those processes. 195a1235b3eSNicolas Pitre */ 196a1235b3eSNicolas Pitre int tty_signal_session_leader(struct tty_struct *tty, int exit_session) 197a1235b3eSNicolas Pitre { 198a1235b3eSNicolas Pitre struct task_struct *p; 199a1235b3eSNicolas Pitre int refs = 0; 200a1235b3eSNicolas Pitre struct pid *tty_pgrp = NULL; 201a1235b3eSNicolas Pitre 202a1235b3eSNicolas Pitre read_lock(&tasklist_lock); 203*64d608dbSJiri Slaby if (tty->ctrl.session) { 204*64d608dbSJiri Slaby do_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p) { 205a1235b3eSNicolas Pitre spin_lock_irq(&p->sighand->siglock); 206a1235b3eSNicolas Pitre if (p->signal->tty == tty) { 207a1235b3eSNicolas Pitre p->signal->tty = NULL; 20863eeafd4SXiaofei Tan /* 20963eeafd4SXiaofei Tan * We defer the dereferences outside of 21063eeafd4SXiaofei Tan * the tasklist lock. 21163eeafd4SXiaofei Tan */ 212a1235b3eSNicolas Pitre refs++; 213a1235b3eSNicolas Pitre } 214a1235b3eSNicolas Pitre if (!p->signal->leader) { 215a1235b3eSNicolas Pitre spin_unlock_irq(&p->sighand->siglock); 216a1235b3eSNicolas Pitre continue; 217a1235b3eSNicolas Pitre } 218a1235b3eSNicolas Pitre __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); 219a1235b3eSNicolas Pitre __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); 220a1235b3eSNicolas Pitre put_pid(p->signal->tty_old_pgrp); /* A noop */ 221*64d608dbSJiri Slaby spin_lock(&tty->ctrl.lock); 222*64d608dbSJiri Slaby tty_pgrp = get_pid(tty->ctrl.pgrp); 223*64d608dbSJiri Slaby if (tty->ctrl.pgrp) 224*64d608dbSJiri Slaby p->signal->tty_old_pgrp = 225*64d608dbSJiri Slaby get_pid(tty->ctrl.pgrp); 226*64d608dbSJiri Slaby spin_unlock(&tty->ctrl.lock); 227a1235b3eSNicolas Pitre spin_unlock_irq(&p->sighand->siglock); 228*64d608dbSJiri Slaby } while_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p); 229a1235b3eSNicolas Pitre } 230a1235b3eSNicolas Pitre read_unlock(&tasklist_lock); 231a1235b3eSNicolas Pitre 232a1235b3eSNicolas Pitre if (tty_pgrp) { 233a1235b3eSNicolas Pitre if (exit_session) 234a1235b3eSNicolas Pitre kill_pgrp(tty_pgrp, SIGHUP, exit_session); 235a1235b3eSNicolas Pitre put_pid(tty_pgrp); 236a1235b3eSNicolas Pitre } 237a1235b3eSNicolas Pitre 238a1235b3eSNicolas Pitre return refs; 239a1235b3eSNicolas Pitre } 240a1235b3eSNicolas Pitre 241a1235b3eSNicolas Pitre /** 242a1235b3eSNicolas Pitre * disassociate_ctty - disconnect controlling tty 243a1235b3eSNicolas Pitre * @on_exit: true if exiting so need to "hang up" the session 244a1235b3eSNicolas Pitre * 245a1235b3eSNicolas Pitre * This function is typically called only by the session leader, when 246a1235b3eSNicolas Pitre * it wants to disassociate itself from its controlling tty. 247a1235b3eSNicolas Pitre * 248a1235b3eSNicolas Pitre * It performs the following functions: 249a1235b3eSNicolas Pitre * (1) Sends a SIGHUP and SIGCONT to the foreground process group 250a1235b3eSNicolas Pitre * (2) Clears the tty from being controlling the session 251a1235b3eSNicolas Pitre * (3) Clears the controlling tty for all processes in the 252a1235b3eSNicolas Pitre * session group. 253a1235b3eSNicolas Pitre * 254a1235b3eSNicolas Pitre * The argument on_exit is set to 1 if called when a process is 255a1235b3eSNicolas Pitre * exiting; it is 0 if called by the ioctl TIOCNOTTY. 256a1235b3eSNicolas Pitre * 257a1235b3eSNicolas Pitre * Locking: 258a1235b3eSNicolas Pitre * BTM is taken for hysterical raisons, and held when 259a1235b3eSNicolas Pitre * called from no_tty(). 260a1235b3eSNicolas Pitre * tty_mutex is taken to protect tty 261a1235b3eSNicolas Pitre * ->siglock is taken to protect ->signal/->sighand 262a1235b3eSNicolas Pitre * tasklist_lock is taken to walk process list for sessions 263a1235b3eSNicolas Pitre * ->siglock is taken to protect ->signal/->sighand 264a1235b3eSNicolas Pitre */ 265a1235b3eSNicolas Pitre void disassociate_ctty(int on_exit) 266a1235b3eSNicolas Pitre { 267a1235b3eSNicolas Pitre struct tty_struct *tty; 268a1235b3eSNicolas Pitre 269a1235b3eSNicolas Pitre if (!current->signal->leader) 270a1235b3eSNicolas Pitre return; 271a1235b3eSNicolas Pitre 272a1235b3eSNicolas Pitre tty = get_current_tty(); 273a1235b3eSNicolas Pitre if (tty) { 274a1235b3eSNicolas Pitre if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) { 275a1235b3eSNicolas Pitre tty_vhangup_session(tty); 276a1235b3eSNicolas Pitre } else { 277a1235b3eSNicolas Pitre struct pid *tty_pgrp = tty_get_pgrp(tty); 278d4e1d903SXiaofei Tan 279a1235b3eSNicolas Pitre if (tty_pgrp) { 280a1235b3eSNicolas Pitre kill_pgrp(tty_pgrp, SIGHUP, on_exit); 281a1235b3eSNicolas Pitre if (!on_exit) 282a1235b3eSNicolas Pitre kill_pgrp(tty_pgrp, SIGCONT, on_exit); 283a1235b3eSNicolas Pitre put_pid(tty_pgrp); 284a1235b3eSNicolas Pitre } 285a1235b3eSNicolas Pitre } 286a1235b3eSNicolas Pitre tty_kref_put(tty); 287a1235b3eSNicolas Pitre 288a1235b3eSNicolas Pitre } else if (on_exit) { 289a1235b3eSNicolas Pitre struct pid *old_pgrp; 290d4e1d903SXiaofei Tan 291a1235b3eSNicolas Pitre spin_lock_irq(¤t->sighand->siglock); 292a1235b3eSNicolas Pitre old_pgrp = current->signal->tty_old_pgrp; 293a1235b3eSNicolas Pitre current->signal->tty_old_pgrp = NULL; 294a1235b3eSNicolas Pitre spin_unlock_irq(¤t->sighand->siglock); 295a1235b3eSNicolas Pitre if (old_pgrp) { 296a1235b3eSNicolas Pitre kill_pgrp(old_pgrp, SIGHUP, on_exit); 297a1235b3eSNicolas Pitre kill_pgrp(old_pgrp, SIGCONT, on_exit); 298a1235b3eSNicolas Pitre put_pid(old_pgrp); 299a1235b3eSNicolas Pitre } 300a1235b3eSNicolas Pitre return; 301a1235b3eSNicolas Pitre } 302a1235b3eSNicolas Pitre 303a1235b3eSNicolas Pitre spin_lock_irq(¤t->sighand->siglock); 304a1235b3eSNicolas Pitre put_pid(current->signal->tty_old_pgrp); 305a1235b3eSNicolas Pitre current->signal->tty_old_pgrp = NULL; 306a1235b3eSNicolas Pitre tty = tty_kref_get(current->signal->tty); 307c8bcd9c5SJann Horn spin_unlock_irq(¤t->sighand->siglock); 308c8bcd9c5SJann Horn 309a1235b3eSNicolas Pitre if (tty) { 310a1235b3eSNicolas Pitre unsigned long flags; 311c8bcd9c5SJann Horn 312c8bcd9c5SJann Horn tty_lock(tty); 313*64d608dbSJiri Slaby spin_lock_irqsave(&tty->ctrl.lock, flags); 314*64d608dbSJiri Slaby put_pid(tty->ctrl.session); 315*64d608dbSJiri Slaby put_pid(tty->ctrl.pgrp); 316*64d608dbSJiri Slaby tty->ctrl.session = NULL; 317*64d608dbSJiri Slaby tty->ctrl.pgrp = NULL; 318*64d608dbSJiri Slaby spin_unlock_irqrestore(&tty->ctrl.lock, flags); 319c8bcd9c5SJann Horn tty_unlock(tty); 320a1235b3eSNicolas Pitre tty_kref_put(tty); 321a1235b3eSNicolas Pitre } 322a1235b3eSNicolas Pitre 323a1235b3eSNicolas Pitre /* Now clear signal->tty under the lock */ 324a1235b3eSNicolas Pitre read_lock(&tasklist_lock); 325a1235b3eSNicolas Pitre session_clear_tty(task_session(current)); 326a1235b3eSNicolas Pitre read_unlock(&tasklist_lock); 327a1235b3eSNicolas Pitre } 328a1235b3eSNicolas Pitre 3293adf2aa8SValdis Klētnieks /* 330a1235b3eSNicolas Pitre * 331a1235b3eSNicolas Pitre * no_tty - Ensure the current process does not have a controlling tty 332a1235b3eSNicolas Pitre */ 333a1235b3eSNicolas Pitre void no_tty(void) 334a1235b3eSNicolas Pitre { 33563eeafd4SXiaofei Tan /* 33663eeafd4SXiaofei Tan * FIXME: Review locking here. The tty_lock never covered any race 33763eeafd4SXiaofei Tan * between a new association and proc_clear_tty but possibly we need 33863eeafd4SXiaofei Tan * to protect against this anyway. 33963eeafd4SXiaofei Tan */ 340a1235b3eSNicolas Pitre struct task_struct *tsk = current; 341d4e1d903SXiaofei Tan 342a1235b3eSNicolas Pitre disassociate_ctty(0); 343a1235b3eSNicolas Pitre proc_clear_tty(tsk); 344a1235b3eSNicolas Pitre } 345a1235b3eSNicolas Pitre 346a1235b3eSNicolas Pitre /** 347a1235b3eSNicolas Pitre * tiocsctty - set controlling tty 348a1235b3eSNicolas Pitre * @tty: tty structure 349bc38fe24SLee Jones * @file: file structure used to check permissions 350a1235b3eSNicolas Pitre * @arg: user argument 351a1235b3eSNicolas Pitre * 352a1235b3eSNicolas Pitre * This ioctl is used to manage job control. It permits a session 353a1235b3eSNicolas Pitre * leader to set this tty as the controlling tty for the session. 354a1235b3eSNicolas Pitre * 355a1235b3eSNicolas Pitre * Locking: 356a1235b3eSNicolas Pitre * Takes tty_lock() to serialize proc_set_tty() for this tty 357a1235b3eSNicolas Pitre * Takes tasklist_lock internally to walk sessions 358a1235b3eSNicolas Pitre * Takes ->siglock() when updating signal->tty 359a1235b3eSNicolas Pitre */ 360a1235b3eSNicolas Pitre static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) 361a1235b3eSNicolas Pitre { 362a1235b3eSNicolas Pitre int ret = 0; 363a1235b3eSNicolas Pitre 364a1235b3eSNicolas Pitre tty_lock(tty); 365a1235b3eSNicolas Pitre read_lock(&tasklist_lock); 366a1235b3eSNicolas Pitre 367*64d608dbSJiri Slaby if (current->signal->leader && 368*64d608dbSJiri Slaby task_session(current) == tty->ctrl.session) 369a1235b3eSNicolas Pitre goto unlock; 370a1235b3eSNicolas Pitre 371a1235b3eSNicolas Pitre /* 372a1235b3eSNicolas Pitre * The process must be a session leader and 373a1235b3eSNicolas Pitre * not have a controlling tty already. 374a1235b3eSNicolas Pitre */ 375a1235b3eSNicolas Pitre if (!current->signal->leader || current->signal->tty) { 376a1235b3eSNicolas Pitre ret = -EPERM; 377a1235b3eSNicolas Pitre goto unlock; 378a1235b3eSNicolas Pitre } 379a1235b3eSNicolas Pitre 380*64d608dbSJiri Slaby if (tty->ctrl.session) { 381a1235b3eSNicolas Pitre /* 382a1235b3eSNicolas Pitre * This tty is already the controlling 383a1235b3eSNicolas Pitre * tty for another session group! 384a1235b3eSNicolas Pitre */ 385a1235b3eSNicolas Pitre if (arg == 1 && capable(CAP_SYS_ADMIN)) { 386a1235b3eSNicolas Pitre /* 387a1235b3eSNicolas Pitre * Steal it away 388a1235b3eSNicolas Pitre */ 389*64d608dbSJiri Slaby session_clear_tty(tty->ctrl.session); 390a1235b3eSNicolas Pitre } else { 391a1235b3eSNicolas Pitre ret = -EPERM; 392a1235b3eSNicolas Pitre goto unlock; 393a1235b3eSNicolas Pitre } 394a1235b3eSNicolas Pitre } 395a1235b3eSNicolas Pitre 396a1235b3eSNicolas Pitre /* See the comment in tty_open_proc_set_tty(). */ 397a1235b3eSNicolas Pitre if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) { 398a1235b3eSNicolas Pitre ret = -EPERM; 399a1235b3eSNicolas Pitre goto unlock; 400a1235b3eSNicolas Pitre } 401a1235b3eSNicolas Pitre 402a1235b3eSNicolas Pitre proc_set_tty(tty); 403a1235b3eSNicolas Pitre unlock: 404a1235b3eSNicolas Pitre read_unlock(&tasklist_lock); 405a1235b3eSNicolas Pitre tty_unlock(tty); 406a1235b3eSNicolas Pitre return ret; 407a1235b3eSNicolas Pitre } 408a1235b3eSNicolas Pitre 409a1235b3eSNicolas Pitre /** 410a1235b3eSNicolas Pitre * tty_get_pgrp - return a ref counted pgrp pid 411a1235b3eSNicolas Pitre * @tty: tty to read 412a1235b3eSNicolas Pitre * 413a1235b3eSNicolas Pitre * Returns a refcounted instance of the pid struct for the process 414a1235b3eSNicolas Pitre * group controlling the tty. 415a1235b3eSNicolas Pitre */ 416a1235b3eSNicolas Pitre struct pid *tty_get_pgrp(struct tty_struct *tty) 417a1235b3eSNicolas Pitre { 418a1235b3eSNicolas Pitre unsigned long flags; 419a1235b3eSNicolas Pitre struct pid *pgrp; 420a1235b3eSNicolas Pitre 421*64d608dbSJiri Slaby spin_lock_irqsave(&tty->ctrl.lock, flags); 422*64d608dbSJiri Slaby pgrp = get_pid(tty->ctrl.pgrp); 423*64d608dbSJiri Slaby spin_unlock_irqrestore(&tty->ctrl.lock, flags); 424a1235b3eSNicolas Pitre 425a1235b3eSNicolas Pitre return pgrp; 426a1235b3eSNicolas Pitre } 427a1235b3eSNicolas Pitre EXPORT_SYMBOL_GPL(tty_get_pgrp); 428a1235b3eSNicolas Pitre 429a1235b3eSNicolas Pitre /* 430a1235b3eSNicolas Pitre * This checks not only the pgrp, but falls back on the pid if no 431a1235b3eSNicolas Pitre * satisfactory pgrp is found. I dunno - gdb doesn't work correctly 432a1235b3eSNicolas Pitre * without this... 433a1235b3eSNicolas Pitre * 434a1235b3eSNicolas Pitre * The caller must hold rcu lock or the tasklist lock. 435a1235b3eSNicolas Pitre */ 436a1235b3eSNicolas Pitre static struct pid *session_of_pgrp(struct pid *pgrp) 437a1235b3eSNicolas Pitre { 438a1235b3eSNicolas Pitre struct task_struct *p; 439a1235b3eSNicolas Pitre struct pid *sid = NULL; 440a1235b3eSNicolas Pitre 441a1235b3eSNicolas Pitre p = pid_task(pgrp, PIDTYPE_PGID); 442a1235b3eSNicolas Pitre if (p == NULL) 443a1235b3eSNicolas Pitre p = pid_task(pgrp, PIDTYPE_PID); 444a1235b3eSNicolas Pitre if (p != NULL) 445a1235b3eSNicolas Pitre sid = task_session(p); 446a1235b3eSNicolas Pitre 447a1235b3eSNicolas Pitre return sid; 448a1235b3eSNicolas Pitre } 449a1235b3eSNicolas Pitre 450a1235b3eSNicolas Pitre /** 451a1235b3eSNicolas Pitre * tiocgpgrp - get process group 452a1235b3eSNicolas Pitre * @tty: tty passed by user 453a1235b3eSNicolas Pitre * @real_tty: tty side of the tty passed by the user if a pty else the tty 454a1235b3eSNicolas Pitre * @p: returned pid 455a1235b3eSNicolas Pitre * 456a1235b3eSNicolas Pitre * Obtain the process group of the tty. If there is no process group 457a1235b3eSNicolas Pitre * return an error. 458a1235b3eSNicolas Pitre * 459a1235b3eSNicolas Pitre * Locking: none. Reference to current->signal->tty is safe. 460a1235b3eSNicolas Pitre */ 461a1235b3eSNicolas Pitre static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) 462a1235b3eSNicolas Pitre { 463a1235b3eSNicolas Pitre struct pid *pid; 464a1235b3eSNicolas Pitre int ret; 465a1235b3eSNicolas Pitre /* 466a1235b3eSNicolas Pitre * (tty == real_tty) is a cheap way of 467a1235b3eSNicolas Pitre * testing if the tty is NOT a master pty. 468a1235b3eSNicolas Pitre */ 469a1235b3eSNicolas Pitre if (tty == real_tty && current->signal->tty != real_tty) 470a1235b3eSNicolas Pitre return -ENOTTY; 471a1235b3eSNicolas Pitre pid = tty_get_pgrp(real_tty); 472a1235b3eSNicolas Pitre ret = put_user(pid_vnr(pid), p); 473a1235b3eSNicolas Pitre put_pid(pid); 474a1235b3eSNicolas Pitre return ret; 475a1235b3eSNicolas Pitre } 476a1235b3eSNicolas Pitre 477a1235b3eSNicolas Pitre /** 478a1235b3eSNicolas Pitre * tiocspgrp - attempt to set process group 479a1235b3eSNicolas Pitre * @tty: tty passed by user 480a1235b3eSNicolas Pitre * @real_tty: tty side device matching tty passed by user 481a1235b3eSNicolas Pitre * @p: pid pointer 482a1235b3eSNicolas Pitre * 483a1235b3eSNicolas Pitre * Set the process group of the tty to the session passed. Only 484a1235b3eSNicolas Pitre * permitted where the tty session is our session. 485a1235b3eSNicolas Pitre * 486a1235b3eSNicolas Pitre * Locking: RCU, ctrl lock 487a1235b3eSNicolas Pitre */ 488a1235b3eSNicolas Pitre static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) 489a1235b3eSNicolas Pitre { 490a1235b3eSNicolas Pitre struct pid *pgrp; 491a1235b3eSNicolas Pitre pid_t pgrp_nr; 492a1235b3eSNicolas Pitre int retval = tty_check_change(real_tty); 493a1235b3eSNicolas Pitre 494a1235b3eSNicolas Pitre if (retval == -EIO) 495a1235b3eSNicolas Pitre return -ENOTTY; 496a1235b3eSNicolas Pitre if (retval) 497a1235b3eSNicolas Pitre return retval; 498c8bcd9c5SJann Horn 499a1235b3eSNicolas Pitre if (get_user(pgrp_nr, p)) 500a1235b3eSNicolas Pitre return -EFAULT; 501a1235b3eSNicolas Pitre if (pgrp_nr < 0) 502a1235b3eSNicolas Pitre return -EINVAL; 503c8bcd9c5SJann Horn 504*64d608dbSJiri Slaby spin_lock_irq(&real_tty->ctrl.lock); 505c8bcd9c5SJann Horn if (!current->signal->tty || 506c8bcd9c5SJann Horn (current->signal->tty != real_tty) || 507*64d608dbSJiri Slaby (real_tty->ctrl.session != task_session(current))) { 508c8bcd9c5SJann Horn retval = -ENOTTY; 509c8bcd9c5SJann Horn goto out_unlock_ctrl; 510c8bcd9c5SJann Horn } 511a1235b3eSNicolas Pitre rcu_read_lock(); 512a1235b3eSNicolas Pitre pgrp = find_vpid(pgrp_nr); 513a1235b3eSNicolas Pitre retval = -ESRCH; 514a1235b3eSNicolas Pitre if (!pgrp) 515a1235b3eSNicolas Pitre goto out_unlock; 516a1235b3eSNicolas Pitre retval = -EPERM; 517a1235b3eSNicolas Pitre if (session_of_pgrp(pgrp) != task_session(current)) 518a1235b3eSNicolas Pitre goto out_unlock; 519a1235b3eSNicolas Pitre retval = 0; 520*64d608dbSJiri Slaby put_pid(real_tty->ctrl.pgrp); 521*64d608dbSJiri Slaby real_tty->ctrl.pgrp = get_pid(pgrp); 522a1235b3eSNicolas Pitre out_unlock: 523a1235b3eSNicolas Pitre rcu_read_unlock(); 524c8bcd9c5SJann Horn out_unlock_ctrl: 525*64d608dbSJiri Slaby spin_unlock_irq(&real_tty->ctrl.lock); 526a1235b3eSNicolas Pitre return retval; 527a1235b3eSNicolas Pitre } 528a1235b3eSNicolas Pitre 529a1235b3eSNicolas Pitre /** 530a1235b3eSNicolas Pitre * tiocgsid - get session id 531a1235b3eSNicolas Pitre * @tty: tty passed by user 532a1235b3eSNicolas Pitre * @real_tty: tty side of the tty passed by the user if a pty else the tty 533a1235b3eSNicolas Pitre * @p: pointer to returned session id 534a1235b3eSNicolas Pitre * 535a1235b3eSNicolas Pitre * Obtain the session id of the tty. If there is no session 536a1235b3eSNicolas Pitre * return an error. 537a1235b3eSNicolas Pitre */ 538a1235b3eSNicolas Pitre static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) 539a1235b3eSNicolas Pitre { 540c8bcd9c5SJann Horn unsigned long flags; 541c8bcd9c5SJann Horn pid_t sid; 542c8bcd9c5SJann Horn 543a1235b3eSNicolas Pitre /* 544a1235b3eSNicolas Pitre * (tty == real_tty) is a cheap way of 545a1235b3eSNicolas Pitre * testing if the tty is NOT a master pty. 546a1235b3eSNicolas Pitre */ 547a1235b3eSNicolas Pitre if (tty == real_tty && current->signal->tty != real_tty) 548a1235b3eSNicolas Pitre return -ENOTTY; 549c8bcd9c5SJann Horn 550*64d608dbSJiri Slaby spin_lock_irqsave(&real_tty->ctrl.lock, flags); 551*64d608dbSJiri Slaby if (!real_tty->ctrl.session) 552c8bcd9c5SJann Horn goto err; 553*64d608dbSJiri Slaby sid = pid_vnr(real_tty->ctrl.session); 554*64d608dbSJiri Slaby spin_unlock_irqrestore(&real_tty->ctrl.lock, flags); 555c8bcd9c5SJann Horn 556c8bcd9c5SJann Horn return put_user(sid, p); 557c8bcd9c5SJann Horn 558c8bcd9c5SJann Horn err: 559*64d608dbSJiri Slaby spin_unlock_irqrestore(&real_tty->ctrl.lock, flags); 560a1235b3eSNicolas Pitre return -ENOTTY; 561a1235b3eSNicolas Pitre } 562a1235b3eSNicolas Pitre 563a1235b3eSNicolas Pitre /* 564a1235b3eSNicolas Pitre * Called from tty_ioctl(). If tty is a pty then real_tty is the slave side, 565a1235b3eSNicolas Pitre * if not then tty == real_tty. 566a1235b3eSNicolas Pitre */ 567a1235b3eSNicolas Pitre long tty_jobctrl_ioctl(struct tty_struct *tty, struct tty_struct *real_tty, 568a1235b3eSNicolas Pitre struct file *file, unsigned int cmd, unsigned long arg) 569a1235b3eSNicolas Pitre { 570a1235b3eSNicolas Pitre void __user *p = (void __user *)arg; 571a1235b3eSNicolas Pitre 572a1235b3eSNicolas Pitre switch (cmd) { 573a1235b3eSNicolas Pitre case TIOCNOTTY: 574a1235b3eSNicolas Pitre if (current->signal->tty != tty) 575a1235b3eSNicolas Pitre return -ENOTTY; 576a1235b3eSNicolas Pitre no_tty(); 577a1235b3eSNicolas Pitre return 0; 578a1235b3eSNicolas Pitre case TIOCSCTTY: 579a1235b3eSNicolas Pitre return tiocsctty(real_tty, file, arg); 580a1235b3eSNicolas Pitre case TIOCGPGRP: 581a1235b3eSNicolas Pitre return tiocgpgrp(tty, real_tty, p); 582a1235b3eSNicolas Pitre case TIOCSPGRP: 583a1235b3eSNicolas Pitre return tiocspgrp(tty, real_tty, p); 584a1235b3eSNicolas Pitre case TIOCGSID: 585a1235b3eSNicolas Pitre return tiocgsid(tty, real_tty, p); 586a1235b3eSNicolas Pitre } 587a1235b3eSNicolas Pitre return -ENOIOCTLCMD; 588a1235b3eSNicolas Pitre } 589