diff options
| author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:26 -0500 |
|---|---|---|
| committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:26 -0500 |
| commit | 3b11a1decef07c19443d24ae926982bc8ec9f4c0 (patch) | |
| tree | b6555f0e5b07f4b2badd332a0a900b974920c49d | |
| parent | 98870ab0a5a3f1822aee681d2997017e1c87d026 (diff) | |
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>
| -rw-r--r-- | fs/nfsd/auth.c | 5 | ||||
| -rw-r--r-- | include/linux/cred.h | 29 | ||||
| -rw-r--r-- | include/linux/init_task.h | 1 | ||||
| -rw-r--r-- | include/linux/sched.h | 5 | ||||
| -rw-r--r-- | kernel/cred.c | 38 | ||||
| -rw-r--r-- | kernel/fork.c | 6 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 65 |
7 files changed, 95 insertions, 54 deletions
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 836ffa1047d9..0184fe9b514c 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
| @@ -34,6 +34,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 34 | int flags = nfsexp_flags(rqstp, exp); | 34 | int flags = nfsexp_flags(rqstp, exp); |
| 35 | int ret; | 35 | int ret; |
| 36 | 36 | ||
| 37 | /* discard any old override before preparing the new set */ | ||
| 38 | revert_creds(get_cred(current->real_cred)); | ||
| 37 | new = prepare_creds(); | 39 | new = prepare_creds(); |
| 38 | if (!new) | 40 | if (!new) |
| 39 | return -ENOMEM; | 41 | return -ENOMEM; |
| @@ -82,7 +84,8 @@ int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | |||
| 82 | else | 84 | else |
| 83 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, | 85 | new->cap_effective = cap_raise_nfsd_set(new->cap_effective, |
| 84 | new->cap_permitted); | 86 | new->cap_permitted); |
| 85 | return commit_creds(new); | 87 | put_cred(override_creds(new)); |
| 88 | return 0; | ||
| 86 | 89 | ||
| 87 | oom: | 90 | oom: |
| 88 | ret = -ENOMEM; | 91 | ret = -ENOMEM; |
diff --git a/include/linux/cred.h b/include/linux/cred.h index 794aab5c66e5..55a9c995d694 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
| @@ -146,8 +146,8 @@ extern struct cred *prepare_exec_creds(void); | |||
| 146 | extern struct cred *prepare_usermodehelper_creds(void); | 146 | extern struct cred *prepare_usermodehelper_creds(void); |
| 147 | extern int commit_creds(struct cred *); | 147 | extern int commit_creds(struct cred *); |
| 148 | extern void abort_creds(struct cred *); | 148 | extern void abort_creds(struct cred *); |
| 149 | extern const struct cred *override_creds(const struct cred *) __deprecated; | 149 | extern const struct cred *override_creds(const struct cred *); |
| 150 | extern void revert_creds(const struct cred *) __deprecated; | 150 | extern void revert_creds(const struct cred *); |
| 151 | extern void __init cred_init(void); | 151 | extern void __init cred_init(void); |
| 152 | 152 | ||
| 153 | /** | 153 | /** |
| @@ -202,32 +202,32 @@ static inline void put_cred(const struct cred *_cred) | |||
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | /** | 204 | /** |
| 205 | * current_cred - Access the current task's credentials | 205 | * current_cred - Access the current task's subjective credentials |
| 206 | * | 206 | * |
| 207 | * Access the credentials of the current task. | 207 | * Access the subjective credentials of the current task. |
| 208 | */ | 208 | */ |
| 209 | #define current_cred() \ | 209 | #define current_cred() \ |
| 210 | (current->cred) | 210 | (current->cred) |
| 211 | 211 | ||
| 212 | /** | 212 | /** |
| 213 | * __task_cred - Access another task's credentials | 213 | * __task_cred - Access a task's objective credentials |
| 214 | * @task: The task to query | 214 | * @task: The task to query |
| 215 | * | 215 | * |
| 216 | * Access the credentials of another task. The caller must hold the | 216 | * Access the objective credentials of a task. The caller must hold the RCU |
| 217 | * RCU readlock. | 217 | * readlock. |
| 218 | * | 218 | * |
| 219 | * The caller must make sure task doesn't go away, either by holding a ref on | 219 | * The caller must make sure task doesn't go away, either by holding a ref on |
| 220 | * task or by holding tasklist_lock to prevent it from being unlinked. | 220 | * task or by holding tasklist_lock to prevent it from being unlinked. |
| 221 | */ | 221 | */ |
| 222 | #define __task_cred(task) \ | 222 | #define __task_cred(task) \ |
| 223 | ((const struct cred *)(rcu_dereference((task)->cred))) | 223 | ((const struct cred *)(rcu_dereference((task)->real_cred))) |
| 224 | 224 | ||
| 225 | /** | 225 | /** |
| 226 | * get_task_cred - Get another task's credentials | 226 | * get_task_cred - Get another task's objective credentials |
| 227 | * @task: The task to query | 227 | * @task: The task to query |
| 228 | * | 228 | * |
| 229 | * Get the credentials of a task, pinning them so that they can't go away. | 229 | * Get the objective credentials of a task, pinning them so that they can't go |
| 230 | * Accessing a task's credentials directly is not permitted. | 230 | * away. Accessing a task's credentials directly is not permitted. |
| 231 | * | 231 | * |
| 232 | * The caller must make sure task doesn't go away, either by holding a ref on | 232 | * The caller must make sure task doesn't go away, either by holding a ref on |
| 233 | * task or by holding tasklist_lock to prevent it from being unlinked. | 233 | * task or by holding tasklist_lock to prevent it from being unlinked. |
| @@ -243,10 +243,11 @@ static inline void put_cred(const struct cred *_cred) | |||
| 243 | }) | 243 | }) |
| 244 | 244 | ||
| 245 | /** | 245 | /** |
| 246 | * get_current_cred - Get the current task's credentials | 246 | * get_current_cred - Get the current task's subjective credentials |
| 247 | * | 247 | * |
| 248 | * Get the credentials of the current task, pinning them so that they can't go | 248 | * Get the subjective credentials of the current task, pinning them so that |
| 249 | * away. Accessing the current task's credentials directly is not permitted. | 249 | * they can't go away. Accessing the current task's credentials directly is |
| 250 | * not permitted. | ||
| 250 | */ | 251 | */ |
| 251 | #define get_current_cred() \ | 252 | #define get_current_cred() \ |
| 252 | (get_cred(current_cred())) | 253 | (get_cred(current_cred())) |
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 08c3b24ad9a8..2597858035cd 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
| @@ -149,6 +149,7 @@ extern struct cred init_cred; | |||
| 149 | .children = LIST_HEAD_INIT(tsk.children), \ | 149 | .children = LIST_HEAD_INIT(tsk.children), \ |
| 150 | .sibling = LIST_HEAD_INIT(tsk.sibling), \ | 150 | .sibling = LIST_HEAD_INIT(tsk.sibling), \ |
| 151 | .group_leader = &tsk, \ | 151 | .group_leader = &tsk, \ |
| 152 | .real_cred = &init_cred, \ | ||
| 152 | .cred = &init_cred, \ | 153 | .cred = &init_cred, \ |
| 153 | .cred_exec_mutex = \ | 154 | .cred_exec_mutex = \ |
| 154 | __MUTEX_INITIALIZER(tsk.cred_exec_mutex), \ | 155 | __MUTEX_INITIALIZER(tsk.cred_exec_mutex), \ |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 121d655e460d..3443123b0709 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -1145,7 +1145,10 @@ struct task_struct { | |||
| 1145 | struct list_head cpu_timers[3]; | 1145 | struct list_head cpu_timers[3]; |
| 1146 | 1146 | ||
| 1147 | /* process credentials */ | 1147 | /* process credentials */ |
| 1148 | const struct cred *cred; /* actual/objective task credentials (COW) */ | 1148 | const struct cred *real_cred; /* objective and real subjective task |
| 1149 | * credentials (COW) */ | ||
| 1150 | const struct cred *cred; /* effective (overridable) subjective task | ||
| 1151 | * credentials (COW) */ | ||
| 1149 | struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */ | 1152 | struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */ |
| 1150 | 1153 | ||
| 1151 | char comm[TASK_COMM_LEN]; /* executable name excluding path | 1154 | char comm[TASK_COMM_LEN]; /* executable name excluding path |
diff --git a/kernel/cred.c b/kernel/cred.c index b8bd2f99d8ce..f3ca10660617 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -35,7 +35,7 @@ static struct thread_group_cred init_tgcred = { | |||
| 35 | * The initial credentials for the initial task | 35 | * The initial credentials for the initial task |
| 36 | */ | 36 | */ |
| 37 | struct cred init_cred = { | 37 | struct cred init_cred = { |
| 38 | .usage = ATOMIC_INIT(3), | 38 | .usage = ATOMIC_INIT(4), |
| 39 | .securebits = SECUREBITS_DEFAULT, | 39 | .securebits = SECUREBITS_DEFAULT, |
| 40 | .cap_inheritable = CAP_INIT_INH_SET, | 40 | .cap_inheritable = CAP_INIT_INH_SET, |
| 41 | .cap_permitted = CAP_FULL_SET, | 41 | .cap_permitted = CAP_FULL_SET, |
| @@ -120,6 +120,8 @@ EXPORT_SYMBOL(__put_cred); | |||
| 120 | * prepare a new copy, which the caller then modifies and then commits by | 120 | * prepare a new copy, which the caller then modifies and then commits by |
| 121 | * calling commit_creds(). | 121 | * calling commit_creds(). |
| 122 | * | 122 | * |
| 123 | * Preparation involves making a copy of the objective creds for modification. | ||
| 124 | * | ||
| 123 | * Returns a pointer to the new creds-to-be if successful, NULL otherwise. | 125 | * Returns a pointer to the new creds-to-be if successful, NULL otherwise. |
| 124 | * | 126 | * |
| 125 | * Call commit_creds() or abort_creds() to clean up. | 127 | * Call commit_creds() or abort_creds() to clean up. |
| @@ -130,7 +132,7 @@ struct cred *prepare_creds(void) | |||
| 130 | const struct cred *old; | 132 | const struct cred *old; |
| 131 | struct cred *new; | 133 | struct cred *new; |
| 132 | 134 | ||
| 133 | BUG_ON(atomic_read(&task->cred->usage) < 1); | 135 | BUG_ON(atomic_read(&task->real_cred->usage) < 1); |
| 134 | 136 | ||
| 135 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); | 137 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); |
| 136 | if (!new) | 138 | if (!new) |
| @@ -262,6 +264,9 @@ error: | |||
| 262 | * | 264 | * |
| 263 | * We share if we can, but under some circumstances we have to generate a new | 265 | * We share if we can, but under some circumstances we have to generate a new |
| 264 | * set. | 266 | * set. |
| 267 | * | ||
| 268 | * The new process gets the current process's subjective credentials as its | ||
| 269 | * objective and subjective credentials | ||
| 265 | */ | 270 | */ |
| 266 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | 271 | int copy_creds(struct task_struct *p, unsigned long clone_flags) |
| 267 | { | 272 | { |
| @@ -278,6 +283,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 278 | #endif | 283 | #endif |
| 279 | clone_flags & CLONE_THREAD | 284 | clone_flags & CLONE_THREAD |
| 280 | ) { | 285 | ) { |
| 286 | p->real_cred = get_cred(p->cred); | ||
| 281 | get_cred(p->cred); | 287 | get_cred(p->cred); |
| 282 | atomic_inc(&p->cred->user->processes); | 288 | atomic_inc(&p->cred->user->processes); |
| 283 | return 0; | 289 | return 0; |
| @@ -317,7 +323,7 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 317 | #endif | 323 | #endif |
| 318 | 324 | ||
| 319 | atomic_inc(&new->user->processes); | 325 | atomic_inc(&new->user->processes); |
| 320 | p->cred = new; | 326 | p->cred = p->real_cred = get_cred(new); |
| 321 | return 0; | 327 | return 0; |
| 322 | } | 328 | } |
| 323 | 329 | ||
| @@ -326,7 +332,9 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 326 | * @new: The credentials to be assigned | 332 | * @new: The credentials to be assigned |
| 327 | * | 333 | * |
| 328 | * Install a new set of credentials to the current task, using RCU to replace | 334 | * Install a new set of credentials to the current task, using RCU to replace |
| 329 | * the old set. | 335 | * the old set. Both the objective and the subjective credentials pointers are |
| 336 | * updated. This function may not be called if the subjective credentials are | ||
| 337 | * in an overridden state. | ||
| 330 | * | 338 | * |
| 331 | * This function eats the caller's reference to the new credentials. | 339 | * This function eats the caller's reference to the new credentials. |
| 332 | * | 340 | * |
| @@ -338,12 +346,15 @@ int commit_creds(struct cred *new) | |||
| 338 | struct task_struct *task = current; | 346 | struct task_struct *task = current; |
| 339 | const struct cred *old; | 347 | const struct cred *old; |
| 340 | 348 | ||
| 349 | BUG_ON(task->cred != task->real_cred); | ||
| 350 | BUG_ON(atomic_read(&task->real_cred->usage) < 2); | ||
| 341 | BUG_ON(atomic_read(&new->usage) < 1); | 351 | BUG_ON(atomic_read(&new->usage) < 1); |
| 342 | BUG_ON(atomic_read(&task->cred->usage) < 1); | ||
| 343 | 352 | ||
| 344 | old = task->cred; | 353 | old = task->real_cred; |
| 345 | security_commit_creds(new, old); | 354 | security_commit_creds(new, old); |
| 346 | 355 | ||
| 356 | get_cred(new); /* we will require a ref for the subj creds too */ | ||
| 357 | |||
| 347 | /* dumpability changes */ | 358 | /* dumpability changes */ |
| 348 | if (old->euid != new->euid || | 359 | if (old->euid != new->euid || |
| 349 | old->egid != new->egid || | 360 | old->egid != new->egid || |
| @@ -369,6 +380,7 @@ int commit_creds(struct cred *new) | |||
| 369 | */ | 380 | */ |
| 370 | if (new->user != old->user) | 381 | if (new->user != old->user) |
| 371 | atomic_inc(&new->user->processes); | 382 | atomic_inc(&new->user->processes); |
| 383 | rcu_assign_pointer(task->real_cred, new); | ||
| 372 | rcu_assign_pointer(task->cred, new); | 384 | rcu_assign_pointer(task->cred, new); |
| 373 | if (new->user != old->user) | 385 | if (new->user != old->user) |
| 374 | atomic_dec(&old->user->processes); | 386 | atomic_dec(&old->user->processes); |
| @@ -388,6 +400,8 @@ int commit_creds(struct cred *new) | |||
| 388 | new->fsgid != old->fsgid) | 400 | new->fsgid != old->fsgid) |
| 389 | proc_id_connector(task, PROC_EVENT_GID); | 401 | proc_id_connector(task, PROC_EVENT_GID); |
| 390 | 402 | ||
| 403 | /* release the old obj and subj refs both */ | ||
| 404 | put_cred(old); | ||
| 391 | put_cred(old); | 405 | put_cred(old); |
| 392 | return 0; | 406 | return 0; |
| 393 | } | 407 | } |
| @@ -408,11 +422,11 @@ void abort_creds(struct cred *new) | |||
| 408 | EXPORT_SYMBOL(abort_creds); | 422 | EXPORT_SYMBOL(abort_creds); |
| 409 | 423 | ||
| 410 | /** | 424 | /** |
| 411 | * override_creds - Temporarily override the current process's credentials | 425 | * override_creds - Override the current process's subjective credentials |
| 412 | * @new: The credentials to be assigned | 426 | * @new: The credentials to be assigned |
| 413 | * | 427 | * |
| 414 | * Install a set of temporary override credentials on the current process, | 428 | * Install a set of temporary override subjective credentials on the current |
| 415 | * returning the old set for later reversion. | 429 | * process, returning the old set for later reversion. |
| 416 | */ | 430 | */ |
| 417 | const struct cred *override_creds(const struct cred *new) | 431 | const struct cred *override_creds(const struct cred *new) |
| 418 | { | 432 | { |
| @@ -424,11 +438,11 @@ const struct cred *override_creds(const struct cred *new) | |||
| 424 | EXPORT_SYMBOL(override_creds); | 438 | EXPORT_SYMBOL(override_creds); |
| 425 | 439 | ||
| 426 | /** | 440 | /** |
| 427 | * revert_creds - Revert a temporary credentials override | 441 | * revert_creds - Revert a temporary subjective credentials override |
| 428 | * @old: The credentials to be restored | 442 | * @old: The credentials to be restored |
| 429 | * | 443 | * |
| 430 | * Revert a temporary set of override credentials to an old set, discarding the | 444 | * Revert a temporary set of override subjective credentials to an old set, |
| 431 | * override set. | 445 | * discarding the override set. |
| 432 | */ | 446 | */ |
| 433 | void revert_creds(const struct cred *old) | 447 | void revert_creds(const struct cred *old) |
| 434 | { | 448 | { |
diff --git a/kernel/fork.c b/kernel/fork.c index 82a7948a664e..af0d0f04585c 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -146,6 +146,7 @@ void __put_task_struct(struct task_struct *tsk) | |||
| 146 | WARN_ON(atomic_read(&tsk->usage)); | 146 | WARN_ON(atomic_read(&tsk->usage)); |
| 147 | WARN_ON(tsk == current); | 147 | WARN_ON(tsk == current); |
| 148 | 148 | ||
| 149 | put_cred(tsk->real_cred); | ||
| 149 | put_cred(tsk->cred); | 150 | put_cred(tsk->cred); |
| 150 | delayacct_tsk_free(tsk); | 151 | delayacct_tsk_free(tsk); |
| 151 | 152 | ||
| @@ -961,10 +962,10 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 961 | DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); | 962 | DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); |
| 962 | #endif | 963 | #endif |
| 963 | retval = -EAGAIN; | 964 | retval = -EAGAIN; |
| 964 | if (atomic_read(&p->cred->user->processes) >= | 965 | if (atomic_read(&p->real_cred->user->processes) >= |
| 965 | p->signal->rlim[RLIMIT_NPROC].rlim_cur) { | 966 | p->signal->rlim[RLIMIT_NPROC].rlim_cur) { |
| 966 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && | 967 | if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && |
| 967 | p->cred->user != current->nsproxy->user_ns->root_user) | 968 | p->real_cred->user != current->nsproxy->user_ns->root_user) |
| 968 | goto bad_fork_free; | 969 | goto bad_fork_free; |
| 969 | } | 970 | } |
| 970 | 971 | ||
| @@ -1278,6 +1279,7 @@ bad_fork_cleanup_put_domain: | |||
| 1278 | module_put(task_thread_info(p)->exec_domain->module); | 1279 | module_put(task_thread_info(p)->exec_domain->module); |
| 1279 | bad_fork_cleanup_count: | 1280 | bad_fork_cleanup_count: |
| 1280 | atomic_dec(&p->cred->user->processes); | 1281 | atomic_dec(&p->cred->user->processes); |
| 1282 | put_cred(p->real_cred); | ||
| 1281 | put_cred(p->cred); | 1283 | put_cred(p->cred); |
| 1282 | bad_fork_free: | 1284 | bad_fork_free: |
| 1283 | free_task(p); | 1285 | free_task(p); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 21a592184633..91b06f2aa963 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -161,7 +161,7 @@ static int selinux_secmark_enabled(void) | |||
| 161 | */ | 161 | */ |
| 162 | static void cred_init_security(void) | 162 | static void cred_init_security(void) |
| 163 | { | 163 | { |
| 164 | struct cred *cred = (struct cred *) current->cred; | 164 | struct cred *cred = (struct cred *) current->real_cred; |
| 165 | struct task_security_struct *tsec; | 165 | struct task_security_struct *tsec; |
| 166 | 166 | ||
| 167 | tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); | 167 | tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); |
| @@ -184,7 +184,7 @@ static inline u32 cred_sid(const struct cred *cred) | |||
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | /* | 186 | /* |
| 187 | * get the security ID of a task | 187 | * get the objective security ID of a task |
| 188 | */ | 188 | */ |
| 189 | static inline u32 task_sid(const struct task_struct *task) | 189 | static inline u32 task_sid(const struct task_struct *task) |
| 190 | { | 190 | { |
| @@ -197,7 +197,7 @@ static inline u32 task_sid(const struct task_struct *task) | |||
| 197 | } | 197 | } |
| 198 | 198 | ||
| 199 | /* | 199 | /* |
| 200 | * get the security ID of the current task | 200 | * get the subjective security ID of the current task |
| 201 | */ | 201 | */ |
| 202 | static inline u32 current_sid(void) | 202 | static inline u32 current_sid(void) |
| 203 | { | 203 | { |
| @@ -1395,6 +1395,7 @@ static int cred_has_perm(const struct cred *actor, | |||
| 1395 | * Check permission between a pair of tasks, e.g. signal checks, | 1395 | * Check permission between a pair of tasks, e.g. signal checks, |
| 1396 | * fork check, ptrace check, etc. | 1396 | * fork check, ptrace check, etc. |
| 1397 | * tsk1 is the actor and tsk2 is the target | 1397 | * tsk1 is the actor and tsk2 is the target |
| 1398 | * - this uses the default subjective creds of tsk1 | ||
| 1398 | */ | 1399 | */ |
| 1399 | static int task_has_perm(const struct task_struct *tsk1, | 1400 | static int task_has_perm(const struct task_struct *tsk1, |
| 1400 | const struct task_struct *tsk2, | 1401 | const struct task_struct *tsk2, |
| @@ -1410,6 +1411,22 @@ static int task_has_perm(const struct task_struct *tsk1, | |||
| 1410 | return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); | 1411 | return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); |
| 1411 | } | 1412 | } |
| 1412 | 1413 | ||
| 1414 | /* | ||
| 1415 | * Check permission between current and another task, e.g. signal checks, | ||
| 1416 | * fork check, ptrace check, etc. | ||
| 1417 | * current is the actor and tsk2 is the target | ||
| 1418 | * - this uses current's subjective creds | ||
| 1419 | */ | ||
| 1420 | static int current_has_perm(const struct task_struct *tsk, | ||
| 1421 | u32 perms) | ||
| 1422 | { | ||
| 1423 | u32 sid, tsid; | ||
| 1424 | |||
| 1425 | sid = current_sid(); | ||
| 1426 | tsid = task_sid(tsk); | ||
| 1427 | return avc_has_perm(sid, tsid, SECCLASS_PROCESS, perms, NULL); | ||
| 1428 | } | ||
| 1429 | |||
| 1413 | #if CAP_LAST_CAP > 63 | 1430 | #if CAP_LAST_CAP > 63 |
| 1414 | #error Fix SELinux to handle capabilities > 63. | 1431 | #error Fix SELinux to handle capabilities > 63. |
| 1415 | #endif | 1432 | #endif |
| @@ -1807,7 +1824,7 @@ static int selinux_ptrace_may_access(struct task_struct *child, | |||
| 1807 | return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); | 1824 | return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); |
| 1808 | } | 1825 | } |
| 1809 | 1826 | ||
| 1810 | return task_has_perm(current, child, PROCESS__PTRACE); | 1827 | return current_has_perm(child, PROCESS__PTRACE); |
| 1811 | } | 1828 | } |
| 1812 | 1829 | ||
| 1813 | static int selinux_ptrace_traceme(struct task_struct *parent) | 1830 | static int selinux_ptrace_traceme(struct task_struct *parent) |
| @@ -1826,7 +1843,7 @@ static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, | |||
| 1826 | { | 1843 | { |
| 1827 | int error; | 1844 | int error; |
| 1828 | 1845 | ||
| 1829 | error = task_has_perm(current, target, PROCESS__GETCAP); | 1846 | error = current_has_perm(target, PROCESS__GETCAP); |
| 1830 | if (error) | 1847 | if (error) |
| 1831 | return error; | 1848 | return error; |
| 1832 | 1849 | ||
| @@ -3071,7 +3088,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, | |||
| 3071 | } else if (!vma->vm_file && | 3088 | } else if (!vma->vm_file && |
| 3072 | vma->vm_start <= vma->vm_mm->start_stack && | 3089 | vma->vm_start <= vma->vm_mm->start_stack && |
| 3073 | vma->vm_end >= vma->vm_mm->start_stack) { | 3090 | vma->vm_end >= vma->vm_mm->start_stack) { |
| 3074 | rc = task_has_perm(current, current, PROCESS__EXECSTACK); | 3091 | rc = current_has_perm(current, PROCESS__EXECSTACK); |
| 3075 | } else if (vma->vm_file && vma->anon_vma) { | 3092 | } else if (vma->vm_file && vma->anon_vma) { |
| 3076 | /* | 3093 | /* |
| 3077 | * We are making executable a file mapping that has | 3094 | * We are making executable a file mapping that has |
| @@ -3220,7 +3237,7 @@ static int selinux_task_create(unsigned long clone_flags) | |||
| 3220 | if (rc) | 3237 | if (rc) |
| 3221 | return rc; | 3238 | return rc; |
| 3222 | 3239 | ||
| 3223 | return task_has_perm(current, current, PROCESS__FORK); | 3240 | return current_has_perm(current, PROCESS__FORK); |
| 3224 | } | 3241 | } |
| 3225 | 3242 | ||
| 3226 | /* | 3243 | /* |
| @@ -3285,17 +3302,17 @@ static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) | |||
| 3285 | 3302 | ||
| 3286 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) | 3303 | static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) |
| 3287 | { | 3304 | { |
| 3288 | return task_has_perm(current, p, PROCESS__SETPGID); | 3305 | return current_has_perm(p, PROCESS__SETPGID); |
| 3289 | } | 3306 | } |
| 3290 | 3307 | ||
| 3291 | static int selinux_task_getpgid(struct task_struct *p) | 3308 | static int selinux_task_getpgid(struct task_struct *p) |
| 3292 | { | 3309 | { |
| 3293 | return task_has_perm(current, p, PROCESS__GETPGID); | 3310 | return current_has_perm(p, PROCESS__GETPGID); |
| 3294 | } | 3311 | } |
| 3295 | 3312 | ||
| 3296 | static int selinux_task_getsid(struct task_struct *p) | 3313 | static int selinux_task_getsid(struct task_struct *p) |
| 3297 | { | 3314 | { |
| 3298 | return task_has_perm(current, p, PROCESS__GETSESSION); | 3315 | return current_has_perm(p, PROCESS__GETSESSION); |
| 3299 | } | 3316 | } |
| 3300 | 3317 | ||
| 3301 | static void selinux_task_getsecid(struct task_struct *p, u32 *secid) | 3318 | static void selinux_task_getsecid(struct task_struct *p, u32 *secid) |
| @@ -3317,7 +3334,7 @@ static int selinux_task_setnice(struct task_struct *p, int nice) | |||
| 3317 | if (rc) | 3334 | if (rc) |
| 3318 | return rc; | 3335 | return rc; |
| 3319 | 3336 | ||
| 3320 | return task_has_perm(current, p, PROCESS__SETSCHED); | 3337 | return current_has_perm(p, PROCESS__SETSCHED); |
| 3321 | } | 3338 | } |
| 3322 | 3339 | ||
| 3323 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) | 3340 | static int selinux_task_setioprio(struct task_struct *p, int ioprio) |
| @@ -3328,12 +3345,12 @@ static int selinux_task_setioprio(struct task_struct *p, int ioprio) | |||
| 3328 | if (rc) | 3345 | if (rc) |
| 3329 | return rc; | 3346 | return rc; |
| 3330 | 3347 | ||
| 3331 | return task_has_perm(current, p, PROCESS__SETSCHED); | 3348 | return current_has_perm(p, PROCESS__SETSCHED); |
| 3332 | } | 3349 | } |
| 3333 | 3350 | ||
| 3334 | static int selinux_task_getioprio(struct task_struct *p) | 3351 | static int selinux_task_getioprio(struct task_struct *p) |
| 3335 | { | 3352 | { |
| 3336 | return task_has_perm(current, p, PROCESS__GETSCHED); | 3353 | return current_has_perm(p, PROCESS__GETSCHED); |
| 3337 | } | 3354 | } |
| 3338 | 3355 | ||
| 3339 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) | 3356 | static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) |
| @@ -3350,7 +3367,7 @@ static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim | |||
| 3350 | later be used as a safe reset point for the soft limit | 3367 | later be used as a safe reset point for the soft limit |
| 3351 | upon context transitions. See selinux_bprm_committing_creds. */ | 3368 | upon context transitions. See selinux_bprm_committing_creds. */ |
| 3352 | if (old_rlim->rlim_max != new_rlim->rlim_max) | 3369 | if (old_rlim->rlim_max != new_rlim->rlim_max) |
| 3353 | return task_has_perm(current, current, PROCESS__SETRLIMIT); | 3370 | return current_has_perm(current, PROCESS__SETRLIMIT); |
| 3354 | 3371 | ||
| 3355 | return 0; | 3372 | return 0; |
| 3356 | } | 3373 | } |
| @@ -3363,17 +3380,17 @@ static int selinux_task_setscheduler(struct task_struct *p, int policy, struct s | |||
| 3363 | if (rc) | 3380 | if (rc) |
| 3364 | return rc; | 3381 | return rc; |
| 3365 | 3382 | ||
| 3366 | return task_has_perm(current, p, PROCESS__SETSCHED); | 3383 | return current_has_perm(p, PROCESS__SETSCHED); |
| 3367 | } | 3384 | } |
| 3368 | 3385 | ||
| 3369 | static int selinux_task_getscheduler(struct task_struct *p) | 3386 | static int selinux_task_getscheduler(struct task_struct *p) |
| 3370 | { | 3387 | { |
| 3371 | return task_has_perm(current, p, PROCESS__GETSCHED); | 3388 | return current_has_perm(p, PROCESS__GETSCHED); |
| 3372 | } | 3389 | } |
| 3373 | 3390 | ||
| 3374 | static int selinux_task_movememory(struct task_struct *p) | 3391 | static int selinux_task_movememory(struct task_struct *p) |
| 3375 | { | 3392 | { |
| 3376 | return task_has_perm(current, p, PROCESS__SETSCHED); | 3393 | return current_has_perm(p, PROCESS__SETSCHED); |
| 3377 | } | 3394 | } |
| 3378 | 3395 | ||
| 3379 | static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | 3396 | static int selinux_task_kill(struct task_struct *p, struct siginfo *info, |
| @@ -3394,7 +3411,7 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, | |||
| 3394 | rc = avc_has_perm(secid, task_sid(p), | 3411 | rc = avc_has_perm(secid, task_sid(p), |
| 3395 | SECCLASS_PROCESS, perm, NULL); | 3412 | SECCLASS_PROCESS, perm, NULL); |
| 3396 | else | 3413 | else |
| 3397 | rc = task_has_perm(current, p, perm); | 3414 | rc = current_has_perm(p, perm); |
| 3398 | return rc; | 3415 | return rc; |
| 3399 | } | 3416 | } |
| 3400 | 3417 | ||
| @@ -5250,7 +5267,7 @@ static int selinux_getprocattr(struct task_struct *p, | |||
| 5250 | unsigned len; | 5267 | unsigned len; |
| 5251 | 5268 | ||
| 5252 | if (current != p) { | 5269 | if (current != p) { |
| 5253 | error = task_has_perm(current, p, PROCESS__GETATTR); | 5270 | error = current_has_perm(p, PROCESS__GETATTR); |
| 5254 | if (error) | 5271 | if (error) |
| 5255 | return error; | 5272 | return error; |
| 5256 | } | 5273 | } |
| @@ -5309,15 +5326,15 @@ static int selinux_setprocattr(struct task_struct *p, | |||
| 5309 | * above restriction is ever removed. | 5326 | * above restriction is ever removed. |
| 5310 | */ | 5327 | */ |
| 5311 | if (!strcmp(name, "exec")) | 5328 | if (!strcmp(name, "exec")) |
| 5312 | error = task_has_perm(current, p, PROCESS__SETEXEC); | 5329 | error = current_has_perm(p, PROCESS__SETEXEC); |
| 5313 | else if (!strcmp(name, "fscreate")) | 5330 | else if (!strcmp(name, "fscreate")) |
| 5314 | error = task_has_perm(current, p, PROCESS__SETFSCREATE); | 5331 | error = current_has_perm(p, PROCESS__SETFSCREATE); |
| 5315 | else if (!strcmp(name, "keycreate")) | 5332 | else if (!strcmp(name, "keycreate")) |
| 5316 | error = task_has_perm(current, p, PROCESS__SETKEYCREATE); | 5333 | error = current_has_perm(p, PROCESS__SETKEYCREATE); |
| 5317 | else if (!strcmp(name, "sockcreate")) | 5334 | else if (!strcmp(name, "sockcreate")) |
| 5318 | error = task_has_perm(current, p, PROCESS__SETSOCKCREATE); | 5335 | error = current_has_perm(p, PROCESS__SETSOCKCREATE); |
| 5319 | else if (!strcmp(name, "current")) | 5336 | else if (!strcmp(name, "current")) |
| 5320 | error = task_has_perm(current, p, PROCESS__SETCURRENT); | 5337 | error = current_has_perm(p, PROCESS__SETCURRENT); |
| 5321 | else | 5338 | else |
| 5322 | error = -EINVAL; | 5339 | error = -EINVAL; |
| 5323 | if (error) | 5340 | if (error) |
