Skip to content

Commit

Permalink
signals: check_kill_permission: check session under tasklist_lock
Browse files Browse the repository at this point in the history
This wasn't documented, but as Atsushi Tsuji pointed out
check_kill_permission() needs tasklist_lock for task_session_nr().  I missed
this fact when removed tasklist from the callers.

Change check_kill_permission() to take tasklist_lock for the SIGCONT case.
Re-order security checks so that we take tasklist_lock only if/when it is
actually needed.  This is a minimal fix for now, tasklist will be removed
later.

Also change the code to use task_session() instead of task_session_nr().

Also, remove the SIGCONT check from cap_task_kill(), it is bogus (and the
whole function is bogus.  Serge, Eric, why it is still alive?).

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Acked-by: Atsushi Tsuji <a-tsuji@bk.jp.nec.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Oleg Nesterov authored and Linus Torvalds committed Apr 30, 2008
1 parent 53c3033 commit 2e2ba22
Showing 1 changed file with 19 additions and 5 deletions.
24 changes: 19 additions & 5 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s)
static int check_kill_permission(int sig, struct siginfo *info,
struct task_struct *t)
{
struct pid *sid;
int error;

if (!valid_signal(sig))
Expand All @@ -545,11 +546,24 @@ static int check_kill_permission(int sig, struct siginfo *info,
if (error)
return error;

if (((sig != SIGCONT) || (task_session_nr(current) != task_session_nr(t)))
&& (current->euid ^ t->suid) && (current->euid ^ t->uid)
&& (current->uid ^ t->suid) && (current->uid ^ t->uid)
&& !capable(CAP_KILL))
return -EPERM;
if ((current->euid ^ t->suid) && (current->euid ^ t->uid) &&
(current->uid ^ t->suid) && (current->uid ^ t->uid) &&
!capable(CAP_KILL)) {
switch (sig) {
case SIGCONT:
read_lock(&tasklist_lock);
sid = task_session(t);
read_unlock(&tasklist_lock);
/*
* We don't return the error if sid == NULL. The
* task was unhashed, the caller must notice this.
*/
if (!sid || sid == task_session(current))
break;
default:
return -EPERM;
}
}

return security_task_kill(t, info, sig, 0);
}
Expand Down

0 comments on commit 2e2ba22

Please sign in to comment.