Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c69e8d9c authored by David Howells's avatar David Howells Committed by James Morris
Browse files

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: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarJames Morris <jmorris@namei.org>
Acked-by: default avatarSerge Hallyn <serue@us.ibm.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 86a264ab
Loading
Loading
Loading
Loading
+20 −12
Original line number Diff line number Diff line
@@ -2399,25 +2399,33 @@ pfm_smpl_buffer_alloc(struct task_struct *task, struct file *filp, pfm_context_t
static int
pfm_bad_permissions(struct task_struct *task)
{
	const struct cred *tcred;
	uid_t uid = current_uid();
	gid_t gid = current_gid();
	int ret;

	rcu_read_lock();
	tcred = __task_cred(task);

	/* inspired by ptrace_attach() */
	DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n",
		uid,
		gid,
		task->euid,
		task->suid,
		task->uid,
		task->egid,
		task->sgid));

	return (uid != task->euid)
	    || (uid != task->suid)
	    || (uid != task->uid)
	    || (gid != task->egid)
	    || (gid != task->sgid)
	    || (gid != task->gid)) && !capable(CAP_SYS_PTRACE);
		tcred->euid,
		tcred->suid,
		tcred->uid,
		tcred->egid,
		tcred->sgid));

	ret = ((uid != tcred->euid)
	       || (uid != tcred->suid)
	       || (uid != tcred->uid)
	       || (gid != tcred->egid)
	       || (gid != tcred->sgid)
	       || (gid != tcred->gid)) && !capable(CAP_SYS_PTRACE);

	rcu_read_unlock();
	return ret;
}

static int
+11 −5
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
	struct proc_event *ev;
	__u8 buffer[CN_PROC_MSG_SIZE];
	struct timespec ts;
	const struct cred *cred;

	if (atomic_read(&proc_event_num_listeners) < 1)
		return;
@@ -115,14 +116,19 @@ void proc_id_connector(struct task_struct *task, int which_id)
	ev->what = which_id;
	ev->event_data.id.process_pid = task->pid;
	ev->event_data.id.process_tgid = task->tgid;
	rcu_read_lock();
	cred = __task_cred(task);
	if (which_id == PROC_EVENT_UID) {
		ev->event_data.id.r.ruid = task->cred->uid;
		ev->event_data.id.e.euid = task->cred->euid;
		ev->event_data.id.r.ruid = cred->uid;
		ev->event_data.id.e.euid = cred->euid;
	} else if (which_id == PROC_EVENT_GID) {
		ev->event_data.id.r.rgid = task->cred->gid;
		ev->event_data.id.e.egid = task->cred->egid;
	} else
		ev->event_data.id.r.rgid = cred->gid;
		ev->event_data.id.e.egid = cred->egid;
	} else {
		rcu_read_unlock();
	     	return;
	}
	rcu_read_unlock();
	get_seq(&msg->seq, &ev->cpu);
	ktime_get_ts(&ts); /* get high res monotonic timestamp */
	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
+6 −2
Original line number Diff line number Diff line
@@ -1361,6 +1361,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
		       struct mm_struct *mm)
{
	const struct cred *cred;
	unsigned int i, len;
	
	/* first copy the parameters from user space */
@@ -1388,8 +1389,11 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
	psinfo->pr_nice = task_nice(p);
	psinfo->pr_flag = p->flags;
	SET_UID(psinfo->pr_uid, p->cred->uid);
	SET_GID(psinfo->pr_gid, p->cred->gid);
	rcu_read_lock();
	cred = __task_cred(p);
	SET_UID(psinfo->pr_uid, cred->uid);
	SET_GID(psinfo->pr_gid, cred->gid);
	rcu_read_unlock();
	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
	
	return 0;
+6 −2
Original line number Diff line number Diff line
@@ -1414,6 +1414,7 @@ static void fill_prstatus(struct elf_prstatus *prstatus,
static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
		       struct mm_struct *mm)
{
	const struct cred *cred;
	unsigned int i, len;

	/* first copy the parameters from user space */
@@ -1441,8 +1442,11 @@ static int fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
	psinfo->pr_nice = task_nice(p);
	psinfo->pr_flag = p->flags;
	SET_UID(psinfo->pr_uid, p->cred->uid);
	SET_GID(psinfo->pr_gid, p->cred->gid);
	rcu_read_lock();
	cred = __task_cred(p);
	SET_UID(psinfo->pr_uid, cred->uid);
	SET_GID(psinfo->pr_gid, cred->gid);
	rcu_read_unlock();
	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));

	return 0;
+11 −4
Original line number Diff line number Diff line
@@ -401,10 +401,17 @@ static const long band_table[NSIGPOLL] = {
static inline int sigio_perm(struct task_struct *p,
                             struct fown_struct *fown, int sig)
{
	return (((fown->euid == 0) ||
		 (fown->euid == p->cred->suid) || (fown->euid == p->cred->uid) ||
		 (fown->uid == p->cred->suid) || (fown->uid == p->cred->uid)) &&
	const struct cred *cred;
	int ret;

	rcu_read_lock();
	cred = __task_cred(p);
	ret = ((fown->euid == 0 ||
		fown->euid == cred->suid || fown->euid == cred->uid ||
		fown->uid  == cred->suid || fown->uid  == cred->uid) &&
	       !security_file_send_sigiotask(p, fown, sig));
	rcu_read_unlock();
	return ret;
}

static void send_sigio_to_task(struct task_struct *p,
Loading