diff options
| -rw-r--r-- | include/linux/cred.h | 6 | ||||
| -rw-r--r-- | include/linux/security.h | 28 | ||||
| -rw-r--r-- | kernel/cred.c | 113 | ||||
| -rw-r--r-- | security/capability.c | 12 | ||||
| -rw-r--r-- | security/security.c | 10 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 46 | ||||
| -rw-r--r-- | security/smack/smack_lsm.c | 37 |
7 files changed, 252 insertions, 0 deletions
diff --git a/include/linux/cred.h b/include/linux/cred.h index 55a9c995d694..26c1ab179946 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | struct user_struct; | 19 | struct user_struct; |
| 20 | struct cred; | 20 | struct cred; |
| 21 | struct inode; | ||
| 21 | 22 | ||
| 22 | /* | 23 | /* |
| 23 | * COW Supplementary groups list | 24 | * COW Supplementary groups list |
| @@ -148,6 +149,11 @@ extern int commit_creds(struct cred *); | |||
| 148 | extern void abort_creds(struct cred *); | 149 | extern void abort_creds(struct cred *); |
| 149 | extern const struct cred *override_creds(const struct cred *); | 150 | extern const struct cred *override_creds(const struct cred *); |
| 150 | extern void revert_creds(const struct cred *); | 151 | extern void revert_creds(const struct cred *); |
| 152 | extern struct cred *prepare_kernel_cred(struct task_struct *); | ||
| 153 | extern int change_create_files_as(struct cred *, struct inode *); | ||
| 154 | extern int set_security_override(struct cred *, u32); | ||
| 155 | extern int set_security_override_from_ctx(struct cred *, const char *); | ||
| 156 | extern int set_create_files_as(struct cred *, struct inode *); | ||
| 151 | extern void __init cred_init(void); | 157 | extern void __init cred_init(void); |
| 152 | 158 | ||
| 153 | /** | 159 | /** |
diff --git a/include/linux/security.h b/include/linux/security.h index 56a0eed65673..59a11e19b617 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -587,6 +587,19 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) | |||
| 587 | * @new points to the new credentials. | 587 | * @new points to the new credentials. |
| 588 | * @old points to the original credentials. | 588 | * @old points to the original credentials. |
| 589 | * Install a new set of credentials. | 589 | * Install a new set of credentials. |
| 590 | * @kernel_act_as: | ||
| 591 | * Set the credentials for a kernel service to act as (subjective context). | ||
| 592 | * @new points to the credentials to be modified. | ||
| 593 | * @secid specifies the security ID to be set | ||
| 594 | * The current task must be the one that nominated @secid. | ||
| 595 | * Return 0 if successful. | ||
| 596 | * @kernel_create_files_as: | ||
| 597 | * Set the file creation context in a set of credentials to be the same as | ||
| 598 | * the objective context of the specified inode. | ||
| 599 | * @new points to the credentials to be modified. | ||
| 600 | * @inode points to the inode to use as a reference. | ||
| 601 | * The current task must be the one that nominated @inode. | ||
| 602 | * Return 0 if successful. | ||
| 590 | * @task_setuid: | 603 | * @task_setuid: |
| 591 | * Check permission before setting one or more of the user identity | 604 | * Check permission before setting one or more of the user identity |
| 592 | * attributes of the current process. The @flags parameter indicates | 605 | * attributes of the current process. The @flags parameter indicates |
| @@ -1381,6 +1394,8 @@ struct security_operations { | |||
| 1381 | int (*cred_prepare)(struct cred *new, const struct cred *old, | 1394 | int (*cred_prepare)(struct cred *new, const struct cred *old, |
| 1382 | gfp_t gfp); | 1395 | gfp_t gfp); |
| 1383 | void (*cred_commit)(struct cred *new, const struct cred *old); | 1396 | void (*cred_commit)(struct cred *new, const struct cred *old); |
| 1397 | int (*kernel_act_as)(struct cred *new, u32 secid); | ||
| 1398 | int (*kernel_create_files_as)(struct cred *new, struct inode *inode); | ||
| 1384 | int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); | 1399 | int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); |
| 1385 | int (*task_fix_setuid) (struct cred *new, const struct cred *old, | 1400 | int (*task_fix_setuid) (struct cred *new, const struct cred *old, |
| 1386 | int flags); | 1401 | int flags); |
| @@ -1632,6 +1647,8 @@ int security_task_create(unsigned long clone_flags); | |||
| 1632 | void security_cred_free(struct cred *cred); | 1647 | void security_cred_free(struct cred *cred); |
| 1633 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); | 1648 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); |
| 1634 | void security_commit_creds(struct cred *new, const struct cred *old); | 1649 | void security_commit_creds(struct cred *new, const struct cred *old); |
| 1650 | int security_kernel_act_as(struct cred *new, u32 secid); | ||
| 1651 | int security_kernel_create_files_as(struct cred *new, struct inode *inode); | ||
| 1635 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); | 1652 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); |
| 1636 | int security_task_fix_setuid(struct cred *new, const struct cred *old, | 1653 | int security_task_fix_setuid(struct cred *new, const struct cred *old, |
| 1637 | int flags); | 1654 | int flags); |
| @@ -2151,6 +2168,17 @@ static inline void security_commit_creds(struct cred *new, | |||
| 2151 | { | 2168 | { |
| 2152 | } | 2169 | } |
| 2153 | 2170 | ||
| 2171 | static inline int security_kernel_act_as(struct cred *cred, u32 secid) | ||
| 2172 | { | ||
| 2173 | return 0; | ||
| 2174 | } | ||
| 2175 | |||
| 2176 | static inline int security_kernel_create_files_as(struct cred *cred, | ||
| 2177 | struct inode *inode) | ||
| 2178 | { | ||
| 2179 | return 0; | ||
| 2180 | } | ||
| 2181 | |||
| 2154 | static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, | 2182 | static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, |
| 2155 | int flags) | 2183 | int flags) |
| 2156 | { | 2184 | { |
diff --git a/kernel/cred.c b/kernel/cred.c index f3ca10660617..13697ca2bb38 100644 --- a/kernel/cred.c +++ b/kernel/cred.c | |||
| @@ -462,3 +462,116 @@ void __init cred_init(void) | |||
| 462 | cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), | 462 | cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), |
| 463 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); | 463 | 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); |
| 464 | } | 464 | } |
| 465 | |||
| 466 | /** | ||
| 467 | * prepare_kernel_cred - Prepare a set of credentials for a kernel service | ||
| 468 | * @daemon: A userspace daemon to be used as a reference | ||
| 469 | * | ||
| 470 | * Prepare a set of credentials for a kernel service. This can then be used to | ||
| 471 | * override a task's own credentials so that work can be done on behalf of that | ||
| 472 | * task that requires a different subjective context. | ||
| 473 | * | ||
| 474 | * @daemon is used to provide a base for the security record, but can be NULL. | ||
| 475 | * If @daemon is supplied, then the security data will be derived from that; | ||
| 476 | * otherwise they'll be set to 0 and no groups, full capabilities and no keys. | ||
| 477 | * | ||
| 478 | * The caller may change these controls afterwards if desired. | ||
| 479 | * | ||
| 480 | * Returns the new credentials or NULL if out of memory. | ||
| 481 | * | ||
| 482 | * Does not take, and does not return holding current->cred_replace_mutex. | ||
| 483 | */ | ||
| 484 | struct cred *prepare_kernel_cred(struct task_struct *daemon) | ||
| 485 | { | ||
| 486 | const struct cred *old; | ||
| 487 | struct cred *new; | ||
| 488 | |||
| 489 | new = kmem_cache_alloc(cred_jar, GFP_KERNEL); | ||
| 490 | if (!new) | ||
| 491 | return NULL; | ||
| 492 | |||
| 493 | if (daemon) | ||
| 494 | old = get_task_cred(daemon); | ||
| 495 | else | ||
| 496 | old = get_cred(&init_cred); | ||
| 497 | |||
| 498 | get_uid(new->user); | ||
| 499 | get_group_info(new->group_info); | ||
| 500 | |||
| 501 | #ifdef CONFIG_KEYS | ||
| 502 | atomic_inc(&init_tgcred.usage); | ||
| 503 | new->tgcred = &init_tgcred; | ||
| 504 | new->request_key_auth = NULL; | ||
| 505 | new->thread_keyring = NULL; | ||
| 506 | new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; | ||
| 507 | #endif | ||
| 508 | |||
| 509 | #ifdef CONFIG_SECURITY | ||
| 510 | new->security = NULL; | ||
| 511 | #endif | ||
| 512 | if (security_prepare_creds(new, old, GFP_KERNEL) < 0) | ||
| 513 | goto error; | ||
| 514 | |||
| 515 | atomic_set(&new->usage, 1); | ||
| 516 | put_cred(old); | ||
| 517 | return new; | ||
| 518 | |||
| 519 | error: | ||
| 520 | put_cred(new); | ||
| 521 | return NULL; | ||
| 522 | } | ||
| 523 | EXPORT_SYMBOL(prepare_kernel_cred); | ||
| 524 | |||
| 525 | /** | ||
| 526 | * set_security_override - Set the security ID in a set of credentials | ||
| 527 | * @new: The credentials to alter | ||
| 528 | * @secid: The LSM security ID to set | ||
| 529 | * | ||
| 530 | * Set the LSM security ID in a set of credentials so that the subjective | ||
| 531 | * security is overridden when an alternative set of credentials is used. | ||
| 532 | */ | ||
| 533 | int set_security_override(struct cred *new, u32 secid) | ||
| 534 | { | ||
| 535 | return security_kernel_act_as(new, secid); | ||
| 536 | } | ||
| 537 | EXPORT_SYMBOL(set_security_override); | ||
| 538 | |||
| 539 | /** | ||
| 540 | * set_security_override_from_ctx - Set the security ID in a set of credentials | ||
| 541 | * @new: The credentials to alter | ||
| 542 | * @secctx: The LSM security context to generate the security ID from. | ||
| 543 | * | ||
| 544 | * Set the LSM security ID in a set of credentials so that the subjective | ||
| 545 | * security is overridden when an alternative set of credentials is used. The | ||
| 546 | * security ID is specified in string form as a security context to be | ||
| 547 | * interpreted by the LSM. | ||
| 548 | */ | ||
| 549 | int set_security_override_from_ctx(struct cred *new, const char *secctx) | ||
| 550 | { | ||
| 551 | u32 secid; | ||
| 552 | int ret; | ||
| 553 | |||
| 554 | ret = security_secctx_to_secid(secctx, strlen(secctx), &secid); | ||
| 555 | if (ret < 0) | ||
| 556 | return ret; | ||
| 557 | |||
| 558 | return set_security_override(new, secid); | ||
| 559 | } | ||
| 560 | EXPORT_SYMBOL(set_security_override_from_ctx); | ||
| 561 | |||
| 562 | /** | ||
| 563 | * set_create_files_as - Set the LSM file create context in a set of credentials | ||
| 564 | * @new: The credentials to alter | ||
| 565 | * @inode: The inode to take the context from | ||
| 566 | * | ||
| 567 | * Change the LSM file creation context in a set of credentials to be the same | ||
| 568 | * as the object context of the specified inode, so that the new inodes have | ||
| 569 | * the same MAC context as that inode. | ||
| 570 | */ | ||
| 571 | int set_create_files_as(struct cred *new, struct inode *inode) | ||
| 572 | { | ||
| 573 | new->fsuid = inode->i_uid; | ||
| 574 | new->fsgid = inode->i_gid; | ||
| 575 | return security_kernel_create_files_as(new, inode); | ||
| 576 | } | ||
| 577 | EXPORT_SYMBOL(set_create_files_as); | ||
diff --git a/security/capability.c b/security/capability.c index 185804f99ad1..b9e391425e6f 100644 --- a/security/capability.c +++ b/security/capability.c | |||
| @@ -348,6 +348,16 @@ static void cap_cred_commit(struct cred *new, const struct cred *old) | |||
| 348 | { | 348 | { |
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | static int cap_kernel_act_as(struct cred *new, u32 secid) | ||
| 352 | { | ||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | |||
| 356 | static int cap_kernel_create_files_as(struct cred *new, struct inode *inode) | ||
| 357 | { | ||
| 358 | return 0; | ||
| 359 | } | ||
| 360 | |||
| 351 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 361 | static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 352 | { | 362 | { |
| 353 | return 0; | 363 | return 0; |
| @@ -889,6 +899,8 @@ void security_fixup_ops(struct security_operations *ops) | |||
| 889 | set_to_cap_if_null(ops, cred_free); | 899 | set_to_cap_if_null(ops, cred_free); |
| 890 | set_to_cap_if_null(ops, cred_prepare); | 900 | set_to_cap_if_null(ops, cred_prepare); |
| 891 | set_to_cap_if_null(ops, cred_commit); | 901 | set_to_cap_if_null(ops, cred_commit); |
| 902 | set_to_cap_if_null(ops, kernel_act_as); | ||
| 903 | set_to_cap_if_null(ops, kernel_create_files_as); | ||
| 892 | set_to_cap_if_null(ops, task_setuid); | 904 | set_to_cap_if_null(ops, task_setuid); |
| 893 | set_to_cap_if_null(ops, task_fix_setuid); | 905 | set_to_cap_if_null(ops, task_fix_setuid); |
| 894 | set_to_cap_if_null(ops, task_setgid); | 906 | set_to_cap_if_null(ops, task_setgid); |
diff --git a/security/security.c b/security/security.c index dc5babb2d6d8..038ef04b2c7f 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -616,6 +616,16 @@ void security_commit_creds(struct cred *new, const struct cred *old) | |||
| 616 | return security_ops->cred_commit(new, old); | 616 | return security_ops->cred_commit(new, old); |
| 617 | } | 617 | } |
| 618 | 618 | ||
| 619 | int security_kernel_act_as(struct cred *new, u32 secid) | ||
| 620 | { | ||
| 621 | return security_ops->kernel_act_as(new, secid); | ||
| 622 | } | ||
| 623 | |||
| 624 | int security_kernel_create_files_as(struct cred *new, struct inode *inode) | ||
| 625 | { | ||
| 626 | return security_ops->kernel_create_files_as(new, inode); | ||
| 627 | } | ||
| 628 | |||
| 619 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 629 | int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 620 | { | 630 | { |
| 621 | return security_ops->task_setuid(id0, id1, id2, flags); | 631 | return security_ops->task_setuid(id0, id1, id2, flags); |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 91b06f2aa963..520f82ab3fbf 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -3277,6 +3277,50 @@ static void selinux_cred_commit(struct cred *new, const struct cred *old) | |||
| 3277 | secondary_ops->cred_commit(new, old); | 3277 | secondary_ops->cred_commit(new, old); |
| 3278 | } | 3278 | } |
| 3279 | 3279 | ||
| 3280 | /* | ||
| 3281 | * set the security data for a kernel service | ||
| 3282 | * - all the creation contexts are set to unlabelled | ||
| 3283 | */ | ||
| 3284 | static int selinux_kernel_act_as(struct cred *new, u32 secid) | ||
| 3285 | { | ||
| 3286 | struct task_security_struct *tsec = new->security; | ||
| 3287 | u32 sid = current_sid(); | ||
| 3288 | int ret; | ||
| 3289 | |||
| 3290 | ret = avc_has_perm(sid, secid, | ||
| 3291 | SECCLASS_KERNEL_SERVICE, | ||
| 3292 | KERNEL_SERVICE__USE_AS_OVERRIDE, | ||
| 3293 | NULL); | ||
| 3294 | if (ret == 0) { | ||
| 3295 | tsec->sid = secid; | ||
| 3296 | tsec->create_sid = 0; | ||
| 3297 | tsec->keycreate_sid = 0; | ||
| 3298 | tsec->sockcreate_sid = 0; | ||
| 3299 | } | ||
| 3300 | return ret; | ||
| 3301 | } | ||
| 3302 | |||
| 3303 | /* | ||
| 3304 | * set the file creation context in a security record to the same as the | ||
| 3305 | * objective context of the specified inode | ||
| 3306 | */ | ||
| 3307 | static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) | ||
| 3308 | { | ||
| 3309 | struct inode_security_struct *isec = inode->i_security; | ||
| 3310 | struct task_security_struct *tsec = new->security; | ||
| 3311 | u32 sid = current_sid(); | ||
| 3312 | int ret; | ||
| 3313 | |||
| 3314 | ret = avc_has_perm(sid, isec->sid, | ||
| 3315 | SECCLASS_KERNEL_SERVICE, | ||
| 3316 | KERNEL_SERVICE__CREATE_FILES_AS, | ||
| 3317 | NULL); | ||
| 3318 | |||
| 3319 | if (ret == 0) | ||
| 3320 | tsec->create_sid = isec->sid; | ||
| 3321 | return 0; | ||
| 3322 | } | ||
| 3323 | |||
| 3280 | static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) | 3324 | static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) |
| 3281 | { | 3325 | { |
| 3282 | /* Since setuid only affects the current process, and | 3326 | /* Since setuid only affects the current process, and |
| @@ -5593,6 +5637,8 @@ static struct security_operations selinux_ops = { | |||
| 5593 | .cred_free = selinux_cred_free, | 5637 | .cred_free = selinux_cred_free, |
| 5594 | .cred_prepare = selinux_cred_prepare, | 5638 | .cred_prepare = selinux_cred_prepare, |
| 5595 | .cred_commit = selinux_cred_commit, | 5639 | .cred_commit = selinux_cred_commit, |
| 5640 | .kernel_act_as = selinux_kernel_act_as, | ||
| 5641 | .kernel_create_files_as = selinux_kernel_create_files_as, | ||
| 5596 | .task_setuid = selinux_task_setuid, | 5642 | .task_setuid = selinux_task_setuid, |
| 5597 | .task_fix_setuid = selinux_task_fix_setuid, | 5643 | .task_fix_setuid = selinux_task_fix_setuid, |
| 5598 | .task_setgid = selinux_task_setgid, | 5644 | .task_setgid = selinux_task_setgid, |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index de396742abf4..8ad48161cef5 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
| @@ -1012,6 +1012,41 @@ static void smack_cred_commit(struct cred *new, const struct cred *old) | |||
| 1012 | } | 1012 | } |
| 1013 | 1013 | ||
| 1014 | /** | 1014 | /** |
| 1015 | * smack_kernel_act_as - Set the subjective context in a set of credentials | ||
| 1016 | * @new points to the set of credentials to be modified. | ||
| 1017 | * @secid specifies the security ID to be set | ||
| 1018 | * | ||
| 1019 | * Set the security data for a kernel service. | ||
| 1020 | */ | ||
| 1021 | static int smack_kernel_act_as(struct cred *new, u32 secid) | ||
| 1022 | { | ||
| 1023 | char *smack = smack_from_secid(secid); | ||
| 1024 | |||
| 1025 | if (smack == NULL) | ||
| 1026 | return -EINVAL; | ||
| 1027 | |||
| 1028 | new->security = smack; | ||
| 1029 | return 0; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | /** | ||
| 1033 | * smack_kernel_create_files_as - Set the file creation label in a set of creds | ||
| 1034 | * @new points to the set of credentials to be modified | ||
| 1035 | * @inode points to the inode to use as a reference | ||
| 1036 | * | ||
| 1037 | * Set the file creation context in a set of credentials to the same | ||
| 1038 | * as the objective context of the specified inode | ||
| 1039 | */ | ||
| 1040 | static int smack_kernel_create_files_as(struct cred *new, | ||
| 1041 | struct inode *inode) | ||
| 1042 | { | ||
| 1043 | struct inode_smack *isp = inode->i_security; | ||
| 1044 | |||
| 1045 | new->security = isp->smk_inode; | ||
| 1046 | return 0; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | /** | ||
| 1015 | * smack_task_setpgid - Smack check on setting pgid | 1050 | * smack_task_setpgid - Smack check on setting pgid |
| 1016 | * @p: the task object | 1051 | * @p: the task object |
| 1017 | * @pgid: unused | 1052 | * @pgid: unused |
| @@ -2641,6 +2676,8 @@ struct security_operations smack_ops = { | |||
| 2641 | .cred_free = smack_cred_free, | 2676 | .cred_free = smack_cred_free, |
| 2642 | .cred_prepare = smack_cred_prepare, | 2677 | .cred_prepare = smack_cred_prepare, |
| 2643 | .cred_commit = smack_cred_commit, | 2678 | .cred_commit = smack_cred_commit, |
| 2679 | .kernel_act_as = smack_kernel_act_as, | ||
| 2680 | .kernel_create_files_as = smack_kernel_create_files_as, | ||
| 2644 | .task_fix_setuid = cap_task_fix_setuid, | 2681 | .task_fix_setuid = cap_task_fix_setuid, |
| 2645 | .task_setpgid = smack_task_setpgid, | 2682 | .task_setpgid = smack_task_setpgid, |
| 2646 | .task_getpgid = smack_task_getpgid, | 2683 | .task_getpgid = smack_task_getpgid, |
