diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-16 18:40:50 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-16 18:40:50 -0500 |
| commit | 2a74dbb9a86e8102dcd07d284135b4530a84826e (patch) | |
| tree | a54403e312b6062dfb57bd904ba8b8ce3b11e720 /kernel | |
| parent | 770b6cb4d21fb3e3df2a7a51e186a3c14db1ec30 (diff) | |
| parent | e93072374112db9dc86635934ee761249be28370 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"A quiet cycle for the security subsystem with just a few maintenance
updates."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
Smack: create a sysfs mount point for smackfs
Smack: use select not depends in Kconfig
Yama: remove locking from delete path
Yama: add RCU to drop read locking
drivers/char/tpm: remove tasklet and cleanup
KEYS: Use keyring_alloc() to create special keyrings
KEYS: Reduce initial permissions on keys
KEYS: Make the session and process keyrings per-thread
seccomp: Make syscall skipping and nr changes more consistent
key: Fix resource leak
keys: Fix unreachable code
KEYS: Add payload preparsing opportunity prior to key instantiate or update
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/cred.c | 127 | ||||
| -rw-r--r-- | kernel/seccomp.c | 13 |
2 files changed, 25 insertions, 115 deletions
diff --git a/kernel/cred.c b/kernel/cred.c index 48cea3da6d05..8888afb846e9 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -30,17 +30,6 @@ | |||
| 30 | static struct kmem_cache *cred_jar; | 30 | static struct kmem_cache *cred_jar; |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * The common credentials for the initial task's thread group | ||
| 34 | */ | ||
| 35 | #ifdef CONFIG_KEYS | ||
| 36 | static struct thread_group_cred init_tgcred = { | ||
| 37 | .usage = ATOMIC_INIT(2), | ||
| 38 | .tgid = 0, | ||
| 39 | .lock = __SPIN_LOCK_UNLOCKED(init_cred.tgcred.lock), | ||
| 40 | }; | ||
| 41 | #endif | ||
| 42 | |||
| 43 | /* | ||
| 44 | * The initial credentials for the initial task | 33 | * The initial credentials for the initial task |
| 45 | */ | 34 | */ |
| 46 | struct cred init_cred = { | 35 | struct cred init_cred = { |
| @@ -65,9 +54,6 @@ struct cred init_cred = { | |||
| 65 | .user = INIT_USER, | 54 | .user = INIT_USER, |
| 66 | .user_ns = &init_user_ns, | 55 | .user_ns = &init_user_ns, |
| 67 | .group_info = &init_groups, | 56 | .group_info = &init_groups, |
| 68 | #ifdef CONFIG_KEYS | ||
| 69 | .tgcred = &init_tgcred, | ||
| 70 | #endif | ||
| 71 | }; | 57 | }; |
| 72 | 58 | ||
| 73 | static inline void set_cred_subscribers(struct cred *cred, int n) | 59 | static inline void set_cred_subscribers(struct cred *cred, int n) |
| @@ -96,36 +82,6 @@ static inline void alter_cred_subscribers(const struct cred *_cred, int n) | |||
| 96 | } | 82 | } |
| 97 | 83 | ||
| 98 | /* | 84 | /* |
| 99 | * Dispose of the shared task group credentials | ||
| 100 | */ | ||
| 101 | #ifdef CONFIG_KEYS | ||
| 102 | static void release_tgcred_rcu(struct rcu_head *rcu) | ||
| 103 | { | ||
| 104 | struct thread_group_cred *tgcred = | ||
| 105 | container_of(rcu, struct thread_group_cred, rcu); | ||
| 106 | |||
| 107 | BUG_ON(atomic_read(&tgcred->usage) != 0); | ||
| 108 | |||
| 109 | key_put(tgcred->session_keyring); | ||
| 110 | key_put(tgcred->process_keyring); | ||
| 111 | kfree(tgcred); | ||
| 112 | } | ||
| 113 | #endif | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Release a set of thread group credentials. | ||
| 117 | */ | ||
| 118 | static void release_tgcred(struct cred *cred) | ||
| 119 | { | ||
| 120 | #ifdef CONFIG_KEYS | ||
| 121 | struct thread_group_cred *tgcred = cred->tgcred; | ||
| 122 | |||
| 123 | if (atomic_dec_and_test(&tgcred->usage)) | ||
| 124 | call_rcu(&tgcred->rcu, release_tgcred_rcu); | ||
| 125 | #endif | ||
| 126 | } | ||
| 127 | |||
| 128 | /* | ||
| 129 | * The RCU callback to actually dispose of a set of credentials | 85 | * The RCU callback to actually dispose of a set of credentials |
| 130 | */ | 86 | */ |
| 131 | static void put_cred_rcu(struct rcu_head *rcu) | 87 | static void put_cred_rcu(struct rcu_head *rcu) |
| @@ -150,9 +106,10 @@ static void put_cred_rcu(struct rcu_head *rcu) | |||
| 150 | #endif | 106 | #endif |
| 151 | 107 | ||
| 152 | security_cred_free(cred); | 108 | security_cred_free(cred); |
| 109 | key_put(cred->session_keyring); | ||
| 110 | key_put(cred->process_keyring); | ||
| 153 | key_put(cred->thread_keyring); | 111 | key_put(cred->thread_keyring); |
| 154 | key_put(cred->request_key_auth); | 112 | key_put(cred->request_key_auth); |
| 155 | release_tgcred(cred); | ||
| 156 | if (cred->group_info) | 113 | if (cred->group_info) |
| 157 | put_group_info(cred->group_info); | 114 | put_group_info(cred->group_info); |
| 158 | free_uid(cred->user); | 115 | free_uid(cred->user); |
| @@ -246,15 +203,6 @@ struct cred *cred_alloc_blank(void) | |||
| 246 | if (!new) | 203 | if (!new) |
| 247 | return NULL; | 204 | return NULL; |
| 248 | 205 | ||
| 249 | #ifdef CONFIG_KEYS | ||
| 250 | new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); | ||
| 251 | if (!new->tgcred) { | ||
| 252 | kmem_cache_free(cred_jar, new); | ||
| 253 | return NULL; | ||
| 254 | } | ||
| 255 | atomic_set(&new->tgcred->usage, 1); | ||
| 256 | #endif | ||
| 257 | |||
| 258 | atomic_set(&new->usage, 1); | 206 | atomic_set(&new->usage, 1); |
| 259 | #ifdef CONFIG_DEBUG_CREDENTIALS | 207 | #ifdef CONFIG_DEBUG_CREDENTIALS |
| 260 | new->magic = CRED_MAGIC; | 208 | new->magic = CRED_MAGIC; |
| @@ -308,9 +256,10 @@ struct cred *prepare_creds(void) | |||
| 308 | get_user_ns(new->user_ns); | 256 | get_user_ns(new->user_ns); |
| 309 | 257 | ||
| 310 | #ifdef CONFIG_KEYS | 258 | #ifdef CONFIG_KEYS |
| 259 | key_get(new->session_keyring); | ||
| 260 | key_get(new->process_keyring); | ||
| 311 | key_get(new->thread_keyring); | 261 | key_get(new->thread_keyring); |
| 312 | key_get(new->request_key_auth); | 262 | key_get(new->request_key_auth); |
| 313 | atomic_inc(&new->tgcred->usage); | ||
| 314 | #endif | 263 | #endif |
| 315 | 264 | ||
| 316 | #ifdef CONFIG_SECURITY | 265 | #ifdef CONFIG_SECURITY |
| @@ -334,39 +283,20 @@ EXPORT_SYMBOL(prepare_creds); | |||
| 334 | */ | 283 | */ |
| 335 | struct cred *prepare_exec_creds(void) | 284 | struct cred *prepare_exec_creds(void) |
| 336 | { | 285 | { |
| 337 | struct thread_group_cred *tgcred = NULL; | ||
| 338 | struct cred *new; | 286 | struct cred *new; |
| 339 | 287 | ||
| 340 | #ifdef CONFIG_KEYS | ||
| 341 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
| 342 | if (!tgcred) | ||
| 343 | return NULL; | ||
| 344 | #endif | ||
| 345 | |||
| 346 | new = prepare_creds(); | 288 | new = prepare_creds(); |
| 347 | if (!new) { | 289 | if (!new) |
| 348 | kfree(tgcred); | ||
| 349 | return new; | 290 | return new; |
| 350 | } | ||
| 351 | 291 | ||
| 352 | #ifdef CONFIG_KEYS | 292 | #ifdef CONFIG_KEYS |
| 353 | /* newly exec'd tasks don't get a thread keyring */ | 293 | /* newly exec'd tasks don't get a thread keyring */ |
| 354 | key_put(new->thread_keyring); | 294 | key_put(new->thread_keyring); |
| 355 | new->thread_keyring = NULL; | 295 | new->thread_keyring = NULL; |
| 356 | 296 | ||
| 357 | /* create a new per-thread-group creds for all this set of threads to | ||
| 358 | * share */ | ||
| 359 | memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred)); | ||
| 360 | |||
| 361 | atomic_set(&tgcred->usage, 1); | ||
| 362 | spin_lock_init(&tgcred->lock); | ||
| 363 | |||
| 364 | /* inherit the session keyring; new process keyring */ | 297 | /* inherit the session keyring; new process keyring */ |
| 365 | key_get(tgcred->session_keyring); | 298 | key_put(new->process_keyring); |
| 366 | tgcred->process_keyring = NULL; | 299 | new->process_keyring = NULL; |
| 367 | |||
| 368 | release_tgcred(new); | ||
| 369 | new->tgcred = tgcred; | ||
| 370 | #endif | 300 | #endif |
| 371 | 301 | ||
| 372 | return new; | 302 | return new; |
| @@ -383,9 +313,6 @@ struct cred *prepare_exec_creds(void) | |||
| 383 | */ | 313 | */ |
| 384 | int copy_creds(struct task_struct *p, unsigned long clone_flags) | 314 | int copy_creds(struct task_struct *p, unsigned long clone_flags) |
| 385 | { | 315 | { |
| 386 | #ifdef CONFIG_KEYS | ||
| 387 | struct thread_group_cred *tgcred; | ||
| 388 | #endif | ||
| 389 | struct cred *new; | 316 | struct cred *new; |
| 390 | int ret; | 317 | int ret; |
| 391 | 318 | ||
| @@ -425,22 +352,12 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags) | |||
| 425 | install_thread_keyring_to_cred(new); | 352 | install_thread_keyring_to_cred(new); |
| 426 | } | 353 | } |
| 427 | 354 | ||
| 428 | /* we share the process and session keyrings between all the threads in | 355 | /* The process keyring is only shared between the threads in a process; |
| 429 | * a process - this is slightly icky as we violate COW credentials a | 356 | * anything outside of those threads doesn't inherit. |
| 430 | * bit */ | 357 | */ |
| 431 | if (!(clone_flags & CLONE_THREAD)) { | 358 | if (!(clone_flags & CLONE_THREAD)) { |
| 432 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | 359 | key_put(new->process_keyring); |
| 433 | if (!tgcred) { | 360 | new->process_keyring = NULL; |
| 434 | ret = -ENOMEM; | ||
| 435 | goto error_put; | ||
| 436 | } | ||
| 437 | atomic_set(&tgcred->usage, 1); | ||
| 438 | spin_lock_init(&tgcred->lock); | ||
| 439 | tgcred->process_keyring = NULL; | ||
| 440 | tgcred->session_keyring = key_get(new->tgcred->session_keyring); | ||
| 441 | |||
| 442 | release_tgcred(new); | ||
| 443 | new->tgcred = tgcred; | ||
| 444 | } | 361 | } |
| 445 | #endif | 362 | #endif |
| 446 | 363 | ||
| @@ -643,9 +560,6 @@ void __init cred_init(void) | |||
| 643 | */ | 560 | */ |
| 644 | struct cred *prepare_kernel_cred(struct task_struct *daemon) | 561 | struct cred *prepare_kernel_cred(struct task_struct *daemon) |
| 645 | { | 562 | { |
| 646 | #ifdef CONFIG_KEYS | ||
| 647 | struct thread_group_cred *tgcred; | ||
| 648 | #endif | ||
| 649 | const struct cred *old; | 563 | const struct cred *old; |
| 650 | struct cred *new; | 564 | struct cred *new; |
| 651 | 565 | ||
| @@ -653,14 +567,6 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 653 | if (!new) | 567 | if (!new) |
| 654 | return NULL; | 568 | return NULL; |
| 655 | 569 | ||
| 656 | #ifdef CONFIG_KEYS | ||
| 657 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); | ||
| 658 | if (!tgcred) { | ||
| 659 | kmem_cache_free(cred_jar, new); | ||
| 660 | return NULL; | ||
| 661 | } | ||
| 662 | #endif | ||
| 663 | |||
| 664 | kdebug("prepare_kernel_cred() alloc %p", new); | 570 | kdebug("prepare_kernel_cred() alloc %p", new); |
| 665 | 571 | ||
| 666 | if (daemon) | 572 | if (daemon) |
| @@ -678,13 +584,10 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon) | |||
| 678 | get_group_info(new->group_info); | 584 | get_group_info(new->group_info); |
| 679 | 585 | ||
| 680 | #ifdef CONFIG_KEYS | 586 | #ifdef CONFIG_KEYS |
| 681 | atomic_set(&tgcred->usage, 1); | 587 | new->session_keyring = NULL; |
| 682 | spin_lock_init(&tgcred->lock); | 588 | new->process_keyring = NULL; |
| 683 | tgcred->process_keyring = NULL; | ||
| 684 | tgcred->session_keyring = NULL; | ||
| 685 | new->tgcred = tgcred; | ||
| 686 | new->request_key_auth = NULL; | ||
| 687 | new->thread_keyring = NULL; | 589 | new->thread_keyring = NULL; |
| 590 | new->request_key_auth = NULL; | ||
| 688 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | 591 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; |
| 689 | #endif | 592 | #endif |
| 690 | 593 | ||
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index ee376beedaf9..5af44b593770 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
| @@ -396,25 +396,29 @@ int __secure_computing(int this_syscall) | |||
| 396 | #ifdef CONFIG_SECCOMP_FILTER | 396 | #ifdef CONFIG_SECCOMP_FILTER |
| 397 | case SECCOMP_MODE_FILTER: { | 397 | case SECCOMP_MODE_FILTER: { |
| 398 | int data; | 398 | int data; |
| 399 | struct pt_regs *regs = task_pt_regs(current); | ||
| 399 | ret = seccomp_run_filters(this_syscall); | 400 | ret = seccomp_run_filters(this_syscall); |
| 400 | data = ret & SECCOMP_RET_DATA; | 401 | data = ret & SECCOMP_RET_DATA; |
| 401 | ret &= SECCOMP_RET_ACTION; | 402 | ret &= SECCOMP_RET_ACTION; |
| 402 | switch (ret) { | 403 | switch (ret) { |
| 403 | case SECCOMP_RET_ERRNO: | 404 | case SECCOMP_RET_ERRNO: |
| 404 | /* Set the low-order 16-bits as a errno. */ | 405 | /* Set the low-order 16-bits as a errno. */ |
| 405 | syscall_set_return_value(current, task_pt_regs(current), | 406 | syscall_set_return_value(current, regs, |
| 406 | -data, 0); | 407 | -data, 0); |
| 407 | goto skip; | 408 | goto skip; |
| 408 | case SECCOMP_RET_TRAP: | 409 | case SECCOMP_RET_TRAP: |
| 409 | /* Show the handler the original registers. */ | 410 | /* Show the handler the original registers. */ |
| 410 | syscall_rollback(current, task_pt_regs(current)); | 411 | syscall_rollback(current, regs); |
| 411 | /* Let the filter pass back 16 bits of data. */ | 412 | /* Let the filter pass back 16 bits of data. */ |
| 412 | seccomp_send_sigsys(this_syscall, data); | 413 | seccomp_send_sigsys(this_syscall, data); |
| 413 | goto skip; | 414 | goto skip; |
| 414 | case SECCOMP_RET_TRACE: | 415 | case SECCOMP_RET_TRACE: |
| 415 | /* Skip these calls if there is no tracer. */ | 416 | /* Skip these calls if there is no tracer. */ |
| 416 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) | 417 | if (!ptrace_event_enabled(current, PTRACE_EVENT_SECCOMP)) { |
| 418 | syscall_set_return_value(current, regs, | ||
| 419 | -ENOSYS, 0); | ||
| 417 | goto skip; | 420 | goto skip; |
| 421 | } | ||
| 418 | /* Allow the BPF to provide the event message */ | 422 | /* Allow the BPF to provide the event message */ |
| 419 | ptrace_event(PTRACE_EVENT_SECCOMP, data); | 423 | ptrace_event(PTRACE_EVENT_SECCOMP, data); |
| 420 | /* | 424 | /* |
| @@ -425,6 +429,9 @@ int __secure_computing(int this_syscall) | |||
| 425 | */ | 429 | */ |
| 426 | if (fatal_signal_pending(current)) | 430 | if (fatal_signal_pending(current)) |
| 427 | break; | 431 | break; |
| 432 | if (syscall_get_nr(current, regs) < 0) | ||
| 433 | goto skip; /* Explicit request to skip. */ | ||
| 434 | |||
| 428 | return 0; | 435 | return 0; |
| 429 | case SECCOMP_RET_ALLOW: | 436 | case SECCOMP_RET_ALLOW: |
| 430 | return 0; | 437 | return 0; |
