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, |