/** * __tty_check_change - check for POSIX terminal changes * @tty: tty to check * @sig: signal to send * * If we try to write to, or set the state of, a terminal and we're * not in the foreground, send a SIGTTOU. If the signal is blocked or * ignored, go ahead and perform the operation. (POSIX 7.2) * * Locking: ctrl.lock
*/ int __tty_check_change(struct tty_struct *tty, int sig)
{ unsignedlong flags; struct pid *pgrp, *tty_pgrp; int ret = 0;
/** * __proc_set_tty - set the controlling terminal * @tty: tty structure * * Only callable by the session leader and only if it does not already have * a controlling terminal. * * Caller must hold: tty_lock() * a readlock on tasklist_lock * sighand lock
*/ staticvoid __proc_set_tty(struct tty_struct *tty)
{ unsignedlong flags;
spin_lock_irqsave(&tty->ctrl.lock, flags); /* * The session and fg pgrp references will be non-NULL if * tiocsctty() is stealing the controlling tty
*/
put_pid(tty->ctrl.session);
put_pid(tty->ctrl.pgrp);
tty->ctrl.pgrp = get_pid(task_pgrp(current));
tty->ctrl.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);
tty_kref_put(current->signal->tty);
}
put_pid(current->signal->tty_old_pgrp);
current->signal->tty = tty_kref_get(tty);
current->signal->tty_old_pgrp = NULL;
}
/* * Called by tty_open() to set the controlling tty if applicable.
*/ void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty)
{
read_lock(&tasklist_lock);
spin_lock_irq(¤t->sighand->siglock); if (current->signal->leader &&
!current->signal->tty &&
tty->ctrl.session == NULL) { /* * Don't let a process that only has write access to the tty * obtain the privileges associated with having a tty as * controlling terminal (being able to reopen it with full * access through /dev/tty, being able to perform pushback). * Many distributions set the group of all ttys to "tty" and * grant write-only access to all terminals for setgid tty * binaries, which should not imply full privileges on all ttys. * * This could theoretically break old code that performs open() * on a write-only file descriptor. In that case, it might be * necessary to also permit this if * inode_permission(inode, MAY_READ) == 0.
*/ if (filp->f_mode & FMODE_READ)
__proc_set_tty(tty);
}
spin_unlock_irq(¤t->sighand->siglock);
read_unlock(&tasklist_lock);
}
/** * tty_signal_session_leader - sends SIGHUP to session leader * @tty: controlling tty * @exit_session: if non-zero, signal all foreground group processes * * Send SIGHUP and SIGCONT to the session leader and its process group. * Optionally, signal all processes in the foreground process group. * * Returns the number of processes in the session with this tty * as their controlling terminal. This value is used to drop * tty references for those processes.
*/ int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
{ struct task_struct *p; int refs = 0; struct pid *tty_pgrp = NULL;
read_lock(&tasklist_lock); if (tty->ctrl.session) {
do_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p) {
spin_lock_irq(&p->sighand->siglock); if (p->signal->tty == tty) {
p->signal->tty = NULL; /* * We defer the dereferences outside of * the tasklist lock.
*/
refs++;
} if (!p->signal->leader) {
spin_unlock_irq(&p->sighand->siglock); continue;
}
send_signal_locked(SIGHUP, SEND_SIG_PRIV, p, PIDTYPE_TGID);
send_signal_locked(SIGCONT, SEND_SIG_PRIV, p, PIDTYPE_TGID);
put_pid(p->signal->tty_old_pgrp); /* A noop */
spin_lock(&tty->ctrl.lock);
tty_pgrp = get_pid(tty->ctrl.pgrp); if (tty->ctrl.pgrp)
p->signal->tty_old_pgrp =
get_pid(tty->ctrl.pgrp);
spin_unlock(&tty->ctrl.lock);
spin_unlock_irq(&p->sighand->siglock);
} while_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
if (tty_pgrp) { if (exit_session)
kill_pgrp(tty_pgrp, SIGHUP, exit_session);
put_pid(tty_pgrp);
}
return refs;
}
/** * disassociate_ctty - disconnect controlling tty * @on_exit: true if exiting so need to "hang up" the session * * This function is typically called only by the session leader, when * it wants to disassociate itself from its controlling tty. * * It performs the following functions: * (1) Sends a SIGHUP and SIGCONT to the foreground process group * (2) Clears the tty from being controlling the session * (3) Clears the controlling tty for all processes in the * session group. * * The argument on_exit is set to 1 if called when a process is * exiting; it is 0 if called by the ioctl TIOCNOTTY. * * Locking: * BTM is taken for hysterical raisons, and held when * called from no_tty(). * tty_mutex is taken to protect tty * ->siglock is taken to protect ->signal/->sighand * tasklist_lock is taken to walk process list for sessions * ->siglock is taken to protect ->signal/->sighand
*/ void disassociate_ctty(int on_exit)
{ struct tty_struct *tty;
/* If tty->ctrl.pgrp is not NULL, it may be assigned to * current->signal->tty_old_pgrp in a race condition, and * cause pid memleak. Release current->signal->tty_old_pgrp * after tty->ctrl.pgrp set to NULL.
*/
spin_lock_irq(¤t->sighand->siglock);
put_pid(current->signal->tty_old_pgrp);
current->signal->tty_old_pgrp = NULL;
spin_unlock_irq(¤t->sighand->siglock);
/* Now clear signal->tty under the lock */
read_lock(&tasklist_lock);
session_clear_tty(task_session(current));
read_unlock(&tasklist_lock);
}
/* * * no_tty - Ensure the current process does not have a controlling tty
*/ void no_tty(void)
{ /* * FIXME: Review locking here. The tty_lock never covered any race * between a new association and proc_clear_tty but possibly we need * to protect against this anyway.
*/ struct task_struct *tsk = current;
disassociate_ctty(0);
proc_clear_tty(tsk);
}
/** * tiocsctty - set controlling tty * @tty: tty structure * @file: file structure used to check permissions * @arg: user argument * * This ioctl is used to manage job control. It permits a session * leader to set this tty as the controlling tty for the session. * * Locking: * Takes tty_lock() to serialize proc_set_tty() for this tty * Takes tasklist_lock internally to walk sessions * Takes ->siglock() when updating signal->tty
*/ staticint tiocsctty(struct tty_struct *tty, struct file *file, int arg)
{ int ret = 0;
tty_lock(tty);
read_lock(&tasklist_lock);
if (current->signal->leader &&
task_session(current) == tty->ctrl.session) goto unlock;
/* * The process must be a session leader and * not have a controlling tty already.
*/ if (!current->signal->leader || current->signal->tty) {
ret = -EPERM; goto unlock;
}
if (tty->ctrl.session) { /* * This tty is already the controlling * tty for another session group!
*/ if (arg == 1 && capable(CAP_SYS_ADMIN)) { /* * Steal it away
*/
session_clear_tty(tty->ctrl.session);
} else {
ret = -EPERM; goto unlock;
}
}
/* See the comment in tty_open_proc_set_tty(). */ if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) {
ret = -EPERM; goto unlock;
}
/** * 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)
{ unsignedlong flags; struct pid *pgrp;
/* * This checks not only the pgrp, but falls back on the pid if no * satisfactory pgrp is found. I dunno - gdb doesn't work correctly * without this... * * The caller must hold rcu lock or the tasklist lock.
*/ staticstruct pid *session_of_pgrp(struct pid *pgrp)
{ struct task_struct *p; struct pid *sid = NULL;
p = pid_task(pgrp, PIDTYPE_PGID); if (p == NULL)
p = pid_task(pgrp, PIDTYPE_PID); if (p != NULL)
sid = task_session(p);
return sid;
}
/** * tiocgpgrp - get process group * @tty: tty passed by user * @real_tty: tty side of the tty passed by the user if a pty else the tty * @p: returned pid * * Obtain the process group of the tty. If there is no process group * return an error. * * Locking: none. Reference to current->signal->tty is safe.
*/ staticint 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;
pid = tty_get_pgrp(real_tty);
ret = put_user(pid_vnr(pid), p);
put_pid(pid); return ret;
}
/** * tiocspgrp - attempt to set process group * @tty: tty passed by user * @real_tty: tty side device matching tty passed by user * @p: pid pointer * * Set the process group of the tty to the session passed. Only * permitted where the tty session is our session. * * Locking: RCU, ctrl lock
*/ staticint tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{ struct pid *pgrp;
pid_t pgrp_nr; int retval = tty_check_change(real_tty);
if (retval == -EIO) return -ENOTTY; if (retval) return retval;
if (get_user(pgrp_nr, p)) return -EFAULT; if (pgrp_nr < 0) return -EINVAL;
/** * tiocgsid - get session id * @tty: tty passed by user * @real_tty: tty side of the tty passed by the user if a pty else the tty * @p: pointer to returned session id * * Obtain the session id of the tty. If there is no session * return an error.
*/ staticint tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{ unsignedlong 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;
/* * Called from tty_ioctl(). If tty is a pty then real_tty is the slave side, * if not then tty == real_tty.
*/ long tty_jobctrl_ioctl(struct tty_struct *tty, struct tty_struct *real_tty, struct file *file, unsignedint cmd, unsignedlong arg)
{ void __user *p = (void __user *)arg;
switch (cmd) { case TIOCNOTTY: if (current->signal->tty != tty) return -ENOTTY;
no_tty(); return 0; case TIOCSCTTY: return tiocsctty(real_tty, file, arg); case TIOCGPGRP: return tiocgpgrp(tty, real_tty, p); case TIOCSPGRP: return tiocspgrp(tty, real_tty, p); case TIOCGSID: return tiocgsid(tty, real_tty, p);
} return -ENOIOCTLCMD;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.