mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-22 06:32:08 +00:00
CRED: Use RCU to access another task's creds and to release a task's own creds
Use RCU to access another task's creds and to release a task's own creds. This means that it will be possible for the credentials of a task to be replaced without another task (a) requiring a full lock to read them, and (b) seeing deallocated memory. Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: James Morris <jmorris@namei.org> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
86a264abe5
commit
c69e8d9c01
28 changed files with 353 additions and 202 deletions
|
@ -177,6 +177,11 @@ int next_signal(struct sigpending *pending, sigset_t *mask)
|
|||
return sig;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate a new signal queue record
|
||||
* - this may be called without locks if and only if t == current, otherwise an
|
||||
* appopriate lock must be held to protect t's user_struct
|
||||
*/
|
||||
static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
|
||||
int override_rlimit)
|
||||
{
|
||||
|
@ -184,11 +189,12 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
|
|||
struct user_struct *user;
|
||||
|
||||
/*
|
||||
* In order to avoid problems with "switch_user()", we want to make
|
||||
* sure that the compiler doesn't re-load "t->user"
|
||||
* We won't get problems with the target's UID changing under us
|
||||
* because changing it requires RCU be used, and if t != current, the
|
||||
* caller must be holding the RCU readlock (by way of a spinlock) and
|
||||
* we use RCU protection here
|
||||
*/
|
||||
user = t->cred->user;
|
||||
barrier();
|
||||
user = __task_cred(t)->user;
|
||||
atomic_inc(&user->sigpending);
|
||||
if (override_rlimit ||
|
||||
atomic_read(&user->sigpending) <=
|
||||
|
@ -562,12 +568,13 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s)
|
|||
|
||||
/*
|
||||
* Bad permissions for sending the signal
|
||||
* - the caller must hold at least the RCU read lock
|
||||
*/
|
||||
static int check_kill_permission(int sig, struct siginfo *info,
|
||||
struct task_struct *t)
|
||||
{
|
||||
const struct cred *cred = current_cred(), *tcred;
|
||||
struct pid *sid;
|
||||
uid_t uid, euid;
|
||||
int error;
|
||||
|
||||
if (!valid_signal(sig))
|
||||
|
@ -580,10 +587,11 @@ static int check_kill_permission(int sig, struct siginfo *info,
|
|||
if (error)
|
||||
return error;
|
||||
|
||||
uid = current_uid();
|
||||
euid = current_euid();
|
||||
if ((euid ^ t->cred->suid) && (euid ^ t->cred->uid) &&
|
||||
(uid ^ t->cred->suid) && (uid ^ t->cred->uid) &&
|
||||
tcred = __task_cred(t);
|
||||
if ((cred->euid ^ tcred->suid) &&
|
||||
(cred->euid ^ tcred->uid) &&
|
||||
(cred->uid ^ tcred->suid) &&
|
||||
(cred->uid ^ tcred->uid) &&
|
||||
!capable(CAP_KILL)) {
|
||||
switch (sig) {
|
||||
case SIGCONT:
|
||||
|
@ -1011,6 +1019,10 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long
|
|||
return sighand;
|
||||
}
|
||||
|
||||
/*
|
||||
* send signal info to all the members of a group
|
||||
* - the caller must hold the RCU read lock at least
|
||||
*/
|
||||
int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -1032,8 +1044,8 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|||
/*
|
||||
* __kill_pgrp_info() sends a signal to a process group: this is what the tty
|
||||
* control characters do (^C, ^Z etc)
|
||||
* - the caller must hold at least a readlock on tasklist_lock
|
||||
*/
|
||||
|
||||
int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
|
||||
{
|
||||
struct task_struct *p = NULL;
|
||||
|
@ -1089,6 +1101,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
|
|||
{
|
||||
int ret = -EINVAL;
|
||||
struct task_struct *p;
|
||||
const struct cred *pcred;
|
||||
|
||||
if (!valid_signal(sig))
|
||||
return ret;
|
||||
|
@ -1099,9 +1112,11 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
|
|||
ret = -ESRCH;
|
||||
goto out_unlock;
|
||||
}
|
||||
if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
|
||||
&& (euid != p->cred->suid) && (euid != p->cred->uid)
|
||||
&& (uid != p->cred->suid) && (uid != p->cred->uid)) {
|
||||
pcred = __task_cred(p);
|
||||
if ((info == SEND_SIG_NOINFO ||
|
||||
(!is_si_special(info) && SI_FROMUSER(info))) &&
|
||||
euid != pcred->suid && euid != pcred->uid &&
|
||||
uid != pcred->suid && uid != pcred->uid) {
|
||||
ret = -EPERM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
@ -1372,10 +1387,9 @@ int do_notify_parent(struct task_struct *tsk, int sig)
|
|||
*/
|
||||
rcu_read_lock();
|
||||
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
|
||||
info.si_uid = __task_cred(tsk)->uid;
|
||||
rcu_read_unlock();
|
||||
|
||||
info.si_uid = tsk->cred->uid;
|
||||
|
||||
thread_group_cputime(tsk, &cputime);
|
||||
info.si_utime = cputime_to_jiffies(cputime.utime);
|
||||
info.si_stime = cputime_to_jiffies(cputime.stime);
|
||||
|
@ -1443,10 +1457,9 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why)
|
|||
*/
|
||||
rcu_read_lock();
|
||||
info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns);
|
||||
info.si_uid = __task_cred(tsk)->uid;
|
||||
rcu_read_unlock();
|
||||
|
||||
info.si_uid = tsk->cred->uid;
|
||||
|
||||
info.si_utime = cputime_to_clock_t(tsk->utime);
|
||||
info.si_stime = cputime_to_clock_t(tsk->stime);
|
||||
|
||||
|
@ -1713,7 +1726,7 @@ static int ptrace_signal(int signr, siginfo_t *info,
|
|||
info->si_errno = 0;
|
||||
info->si_code = SI_USER;
|
||||
info->si_pid = task_pid_vnr(current->parent);
|
||||
info->si_uid = current->parent->cred->uid;
|
||||
info->si_uid = task_uid(current->parent);
|
||||
}
|
||||
|
||||
/* If the (new) signal is now blocked, requeue it. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue