mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
signals: check_kill_permission: check session under tasklist_lock
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>
This commit is contained in:
parent
53c30337f2
commit
2e2ba22ea4
1 changed files with 19 additions and 5 deletions
|
@ -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,
|
static int check_kill_permission(int sig, struct siginfo *info,
|
||||||
struct task_struct *t)
|
struct task_struct *t)
|
||||||
{
|
{
|
||||||
|
struct pid *sid;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!valid_signal(sig))
|
if (!valid_signal(sig))
|
||||||
|
@ -545,11 +546,24 @@ static int check_kill_permission(int sig, struct siginfo *info,
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (((sig != SIGCONT) || (task_session_nr(current) != task_session_nr(t)))
|
if ((current->euid ^ t->suid) && (current->euid ^ t->uid) &&
|
||||||
&& (current->euid ^ t->suid) && (current->euid ^ t->uid)
|
(current->uid ^ t->suid) && (current->uid ^ t->uid) &&
|
||||||
&& (current->uid ^ t->suid) && (current->uid ^ t->uid)
|
!capable(CAP_KILL)) {
|
||||||
&& !capable(CAP_KILL))
|
switch (sig) {
|
||||||
return -EPERM;
|
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);
|
return security_task_kill(t, info, sig, 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue