CRED: Differentiate objective and effective subjective credentials on a task
Differentiate the objective and real subjective credentials from the effective
subjective credentials on a task by introducing a second credentials pointer
into the task_struct.
task_struct::real_cred then refers to the objective and apparent real
subjective credentials of a task, as perceived by the other tasks in the
system.
task_struct::cred then refers to the effective subjective credentials of a
task, as used by that task when it's actually running. These are not visible
to the other tasks in the system.
__task_cred(task) then refers to the objective/real credentials of the task in
question.
current_cred() refers to the effective subjective credentials of the current
task.
prepare_creds() uses the objective creds as a base and commit_creds() changes
both pointers in the task_struct (indeed commit_creds() requires them to be the
same).
override_creds() and revert_creds() change the subjective creds pointer only,
and the former returns the old subjective creds. These are used by NFSD,
faccessat() and do_coredump(), and will by used by CacheFiles.
In SELinux, current_has_perm() is provided as an alternative to
task_has_perm(). This uses the effective subjective context of current,
whereas task_has_perm() uses the objective/real context of the subject.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 21a5921..91b06f2 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -161,7 +161,7 @@
*/
static void cred_init_security(void)
{
- struct cred *cred = (struct cred *) current->cred;
+ struct cred *cred = (struct cred *) current->real_cred;
struct task_security_struct *tsec;
tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
@@ -184,7 +184,7 @@
}
/*
- * get the security ID of a task
+ * get the objective security ID of a task
*/
static inline u32 task_sid(const struct task_struct *task)
{
@@ -197,7 +197,7 @@
}
/*
- * get the security ID of the current task
+ * get the subjective security ID of the current task
*/
static inline u32 current_sid(void)
{
@@ -1395,6 +1395,7 @@
* Check permission between a pair of tasks, e.g. signal checks,
* fork check, ptrace check, etc.
* tsk1 is the actor and tsk2 is the target
+ * - this uses the default subjective creds of tsk1
*/
static int task_has_perm(const struct task_struct *tsk1,
const struct task_struct *tsk2,
@@ -1410,6 +1411,22 @@
return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
}
+/*
+ * Check permission between current and another task, e.g. signal checks,
+ * fork check, ptrace check, etc.
+ * current is the actor and tsk2 is the target
+ * - this uses current's subjective creds
+ */
+static int current_has_perm(const struct task_struct *tsk,
+ u32 perms)
+{
+ u32 sid, tsid;
+
+ sid = current_sid();
+ tsid = task_sid(tsk);
+ return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL);
+}
+
#if CAP_LAST_CAP > 63
#error Fix SELinux to handle capabilities > 63.
#endif
@@ -1807,7 +1824,7 @@
return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
}
- return task_has_perm(current, child, PROCESS__PTRACE);
+ return current_has_perm(child, PROCESS__PTRACE);
}
static int selinux_ptrace_traceme(struct task_struct *parent)
@@ -1826,7 +1843,7 @@
{
int error;
- error = task_has_perm(current, target, PROCESS__GETCAP);
+ error = current_has_perm(target, PROCESS__GETCAP);
if (error)
return error;
@@ -3071,7 +3088,7 @@
} else if (!vma->vm_file &&
vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack) {
- rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+ rc = current_has_perm(current, PROCESS__EXECSTACK);
} else if (vma->vm_file && vma->anon_vma) {
/*
* We are making executable a file mapping that has
@@ -3220,7 +3237,7 @@
if (rc)
return rc;
- return task_has_perm(current, current, PROCESS__FORK);
+ return current_has_perm(current, PROCESS__FORK);
}
/*
@@ -3285,17 +3302,17 @@
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return task_has_perm(current, p, PROCESS__SETPGID);
+ return current_has_perm(p, PROCESS__SETPGID);
}
static int selinux_task_getpgid(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETPGID);
+ return current_has_perm(p, PROCESS__GETPGID);
}
static int selinux_task_getsid(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETSESSION);
+ return current_has_perm(p, PROCESS__GETSESSION);
}
static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
@@ -3317,7 +3334,7 @@
if (rc)
return rc;
- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
@@ -3328,12 +3345,12 @@
if (rc)
return rc;
- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}
static int selinux_task_getioprio(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETSCHED);
+ return current_has_perm(p, PROCESS__GETSCHED);
}
static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
@@ -3350,7 +3367,7 @@
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return task_has_perm(current, current, PROCESS__SETRLIMIT);
+ return current_has_perm(current, PROCESS__SETRLIMIT);
return 0;
}
@@ -3363,17 +3380,17 @@
if (rc)
return rc;
- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__GETSCHED);
+ return current_has_perm(p, PROCESS__GETSCHED);
}
static int selinux_task_movememory(struct task_struct *p)
{
- return task_has_perm(current, p, PROCESS__SETSCHED);
+ return current_has_perm(p, PROCESS__SETSCHED);
}
static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
@@ -3394,7 +3411,7 @@
rc = avc_has_perm(secid, task_sid(p),
SECCLASS_PROCESS, perm, NULL);
else
- rc = task_has_perm(current, p, perm);
+ rc = current_has_perm(p, perm);
return rc;
}
@@ -5250,7 +5267,7 @@
unsigned len;
if (current != p) {
- error = task_has_perm(current, p, PROCESS__GETATTR);
+ error = current_has_perm(p, PROCESS__GETATTR);
if (error)
return error;
}
@@ -5309,15 +5326,15 @@
* above restriction is ever removed.
*/
if (!strcmp(name, "exec"))
- error = task_has_perm(current, p, PROCESS__SETEXEC);
+ error = current_has_perm(p, PROCESS__SETEXEC);
else if (!strcmp(name, "fscreate"))
- error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+ error = current_has_perm(p, PROCESS__SETFSCREATE);
else if (!strcmp(name, "keycreate"))
- error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
+ error = current_has_perm(p, PROCESS__SETKEYCREATE);
else if (!strcmp(name, "sockcreate"))
- error = task_has_perm(current, p, PROCESS__SETSOCKCREATE);
+ error = current_has_perm(p, PROCESS__SETSOCKCREATE);
else if (!strcmp(name, "current"))
- error = task_has_perm(current, p, PROCESS__SETCURRENT);
+ error = current_has_perm(p, PROCESS__SETCURRENT);
else
error = -EINVAL;
if (error)