aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/cred.h6
-rw-r--r--include/linux/security.h28
-rw-r--r--kernel/cred.c113
-rw-r--r--security/capability.c12
-rw-r--r--security/security.c10
-rw-r--r--security/selinux/hooks.c46
-rw-r--r--security/smack/smack_lsm.c37
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
19struct user_struct; 19struct user_struct;
20struct cred; 20struct cred;
21struct 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 *);
148extern void abort_creds(struct cred *); 149extern void abort_creds(struct cred *);
149extern const struct cred *override_creds(const struct cred *); 150extern const struct cred *override_creds(const struct cred *);
150extern void revert_creds(const struct cred *); 151extern void revert_creds(const struct cred *);
152extern struct cred *prepare_kernel_cred(struct task_struct *);
153extern int change_create_files_as(struct cred *, struct inode *);
154extern int set_security_override(struct cred *, u32);
155extern int set_security_override_from_ctx(struct cred *, const char *);
156extern int set_create_files_as(struct cred *, struct inode *);
151extern void __init cred_init(void); 157extern 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);
1632void security_cred_free(struct cred *cred); 1647void security_cred_free(struct cred *cred);
1633int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); 1648int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp);
1634void security_commit_creds(struct cred *new, const struct cred *old); 1649void security_commit_creds(struct cred *new, const struct cred *old);
1650int security_kernel_act_as(struct cred *new, u32 secid);
1651int security_kernel_create_files_as(struct cred *new, struct inode *inode);
1635int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags); 1652int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags);
1636int security_task_fix_setuid(struct cred *new, const struct cred *old, 1653int 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
2171static inline int security_kernel_act_as(struct cred *cred, u32 secid)
2172{
2173 return 0;
2174}
2175
2176static inline int security_kernel_create_files_as(struct cred *cred,
2177 struct inode *inode)
2178{
2179 return 0;
2180}
2181
2154static inline int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, 2182static 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 */
484struct 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
519error:
520 put_cred(new);
521 return NULL;
522}
523EXPORT_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 */
533int set_security_override(struct cred *new, u32 secid)
534{
535 return security_kernel_act_as(new, secid);
536}
537EXPORT_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 */
549int 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}
560EXPORT_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 */
571int 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}
577EXPORT_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
351static int cap_kernel_act_as(struct cred *new, u32 secid)
352{
353 return 0;
354}
355
356static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
357{
358 return 0;
359}
360
351static int cap_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) 361static 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
619int security_kernel_act_as(struct cred *new, u32 secid)
620{
621 return security_ops->kernel_act_as(new, secid);
622}
623
624int security_kernel_create_files_as(struct cred *new, struct inode *inode)
625{
626 return security_ops->kernel_create_files_as(new, inode);
627}
628
619int security_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) 629int 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 */
3284static 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 */
3307static 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
3280static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) 3324static 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 */
1021static 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 */
1040static 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,