From 69b5a44a95bb86f3ad8a50bf2e354057ec450082 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Fri, 21 Sep 2018 17:17:59 -0700 Subject: AppArmor: Abstract use of cred security blob Don't use the cred->security pointer directly. Provide a helper function that provides the security blob pointer. Signed-off-by: Casey Schaufler Reviewed-by: Kees Cook [kees: adjusted for ordered init series] Signed-off-by: Kees Cook --- security/apparmor/include/cred.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'security/apparmor/include') diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h index 265ae6641a06..a757370f2a0c 100644 --- a/security/apparmor/include/cred.h +++ b/security/apparmor/include/cred.h @@ -23,8 +23,22 @@ #include "policy_ns.h" #include "task.h" -#define cred_label(X) ((X)->security) +static inline struct aa_label *cred_label(const struct cred *cred) +{ + struct aa_label **blob = cred->security; + + AA_BUG(!blob); + return *blob; +} +static inline void set_cred_label(const struct cred *cred, + struct aa_label *label) +{ + struct aa_label **blob = cred->security; + + AA_BUG(!blob); + *blob = label; +} /** * aa_cred_raw_label - obtain cred's label -- cgit v1.2.3 From bbd3662a834813730912a58efb44dd6df6d952e6 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Mon, 12 Nov 2018 09:30:56 -0800 Subject: Infrastructure management of the cred security blob Move management of the cred security blob out of the security modules and into the security infrastructre. Instead of allocating and freeing space the security modules tell the infrastructure how much space they require. Signed-off-by: Casey Schaufler Reviewed-by: Kees Cook [kees: adjusted for ordered init series] Signed-off-by: Kees Cook --- include/linux/lsm_hooks.h | 12 ++++++ security/apparmor/include/cred.h | 4 +- security/apparmor/include/lib.h | 4 ++ security/apparmor/lsm.c | 9 ++++ security/security.c | 89 ++++++++++++++++++++++++++++++++++++++- security/selinux/hooks.c | 51 +++++----------------- security/selinux/include/objsec.h | 4 +- security/smack/smack.h | 3 +- security/smack/smack_lsm.c | 79 +++++++++++----------------------- security/tomoyo/common.h | 3 +- security/tomoyo/tomoyo.c | 6 +++ 11 files changed, 162 insertions(+), 102 deletions(-) (limited to 'security/apparmor/include') diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 0c908c091a03..dd33666567bc 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2027,6 +2027,13 @@ struct security_hook_list { char *lsm; } __randomize_layout; +/* + * Security blob size or offset data. + */ +struct lsm_blob_sizes { + int lbs_cred; +}; + /* * Initializing a security_hook_list structure takes * up a lot of space in a source file. This macro takes @@ -2056,6 +2063,7 @@ struct lsm_info { unsigned long flags; /* Optional: flags describing LSM */ int *enabled; /* Optional: controlled by CONFIG_LSM */ int (*init)(void); /* Required. */ + struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */ }; extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; @@ -2095,4 +2103,8 @@ static inline void security_delete_hooks(struct security_hook_list *hooks, #define __lsm_ro_after_init __ro_after_init #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ +#ifdef CONFIG_SECURITY +void __init lsm_early_cred(struct cred *cred); +#endif + #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h index a757370f2a0c..b9504a05fddc 100644 --- a/security/apparmor/include/cred.h +++ b/security/apparmor/include/cred.h @@ -25,7 +25,7 @@ static inline struct aa_label *cred_label(const struct cred *cred) { - struct aa_label **blob = cred->security; + struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; AA_BUG(!blob); return *blob; @@ -34,7 +34,7 @@ static inline struct aa_label *cred_label(const struct cred *cred) static inline void set_cred_label(const struct cred *cred, struct aa_label *label) { - struct aa_label **blob = cred->security; + struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; AA_BUG(!blob); *blob = label; diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 6505e1ad9e23..bbe9b384d71d 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -16,6 +16,7 @@ #include #include +#include #include "match.h" @@ -55,6 +56,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, size_t *ns_len); void aa_info_message(const char *str); +/* Security blob offsets */ +extern struct lsm_blob_sizes apparmor_blob_sizes; + /** * aa_strneq - compare null terminated @str to a non null terminated substring * @str: a null terminated string diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8c2cb4b1a6c3..d5e4a384f205 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1151,6 +1151,13 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, } #endif +/* + * The cred blob is a pointer to, not an instance of, an aa_task_ctx. + */ +struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { + .lbs_cred = sizeof(struct aa_task_ctx *), +}; + static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), @@ -1485,6 +1492,7 @@ static int __init set_init_ctx(void) if (!ctx) return -ENOMEM; + lsm_early_cred(cred); set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); task_ctx(current) = ctx; @@ -1725,5 +1733,6 @@ DEFINE_LSM(apparmor) = { .name = "apparmor", .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, .enabled = &apparmor_enabled, + .blobs = &apparmor_blob_sizes, .init = apparmor_init, }; diff --git a/security/security.c b/security/security.c index 60b39db95c2f..09be8ce007a2 100644 --- a/security/security.c +++ b/security/security.c @@ -41,6 +41,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init; static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); char *lsm_names; +static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; + /* Boot-time LSM user choice */ static __initdata const char *chosen_lsm_order; static __initdata const char *chosen_major_lsm; @@ -139,6 +141,25 @@ static bool __init lsm_allowed(struct lsm_info *lsm) return true; } +static void __init lsm_set_blob_size(int *need, int *lbs) +{ + int offset; + + if (*need > 0) { + offset = *lbs; + *lbs += *need; + *need = offset; + } +} + +static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) +{ + if (!needed) + return; + + lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred); +} + /* Prepare LSM for initialization. */ static void __init prepare_lsm(struct lsm_info *lsm) { @@ -153,6 +174,8 @@ static void __init prepare_lsm(struct lsm_info *lsm) exclusive = lsm; init_debug("exclusive chosen: %s\n", lsm->name); } + + lsm_set_blob_sizes(lsm->blobs); } } @@ -255,6 +278,8 @@ static void __init ordered_lsm_init(void) for (lsm = ordered_lsms; *lsm; lsm++) prepare_lsm(*lsm); + init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); + for (lsm = ordered_lsms; *lsm; lsm++) initialize_lsm(*lsm); @@ -382,6 +407,47 @@ int unregister_lsm_notifier(struct notifier_block *nb) } EXPORT_SYMBOL(unregister_lsm_notifier); +/** + * lsm_cred_alloc - allocate a composite cred blob + * @cred: the cred that needs a blob + * @gfp: allocation type + * + * Allocate the cred blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) +{ + if (blob_sizes.lbs_cred == 0) { + cred->security = NULL; + return 0; + } + + cred->security = kzalloc(blob_sizes.lbs_cred, gfp); + if (cred->security == NULL) + return -ENOMEM; + return 0; +} + +/** + * lsm_early_cred - during initialization allocate a composite cred blob + * @cred: the cred that needs a blob + * + * Allocate the cred blob for all the modules if it's not already there + */ +void __init lsm_early_cred(struct cred *cred) +{ + int rc; + + if (cred == NULL) + panic("%s: NULL cred.\n", __func__); + if (cred->security != NULL) + return; + rc = lsm_cred_alloc(cred, GFP_KERNEL); + if (rc) + panic("%s: Early cred alloc failed.\n", __func__); +} + /* * Hook list operation macros. * @@ -1195,17 +1261,36 @@ void security_task_free(struct task_struct *task) int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { - return call_int_hook(cred_alloc_blank, 0, cred, gfp); + int rc = lsm_cred_alloc(cred, gfp); + + if (rc) + return rc; + + rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); + if (rc) + security_cred_free(cred); + return rc; } void security_cred_free(struct cred *cred) { call_void_hook(cred_free, cred); + + kfree(cred->security); + cred->security = NULL; } int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) { - return call_int_hook(cred_prepare, 0, new, old, gfp); + int rc = lsm_cred_alloc(new, gfp); + + if (rc) + return rc; + + rc = call_int_hook(cred_prepare, 0, new, old, gfp); + if (rc) + security_cred_free(new); + return rc; } void security_transfer_creds(struct cred *new, const struct cred *old) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 169cf5b3334b..239b13b442e7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -210,12 +210,9 @@ static void cred_init_security(void) struct cred *cred = (struct cred *) current->real_cred; struct task_security_struct *tsec; - tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); - if (!tsec) - panic("SELinux: Failed to initialize initial task.\n"); - + lsm_early_cred(cred); + tsec = selinux_cred(cred); tsec->osid = tsec->sid = SECINITSID_KERNEL; - cred->security = tsec; } /* @@ -3685,47 +3682,16 @@ static int selinux_task_alloc(struct task_struct *task, sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); } -/* - * allocate the SELinux part of blank credentials - */ -static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) -{ - struct task_security_struct *tsec; - - tsec = kzalloc(sizeof(struct task_security_struct), gfp); - if (!tsec) - return -ENOMEM; - - cred->security = tsec; - return 0; -} - -/* - * detach and free the LSM part of a set of credentials - */ -static void selinux_cred_free(struct cred *cred) -{ - struct task_security_struct *tsec = selinux_cred(cred); - - kfree(tsec); -} - /* * prepare a new set of credentials for modification */ static int selinux_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - const struct task_security_struct *old_tsec; - struct task_security_struct *tsec; - - old_tsec = selinux_cred(old); - - tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); - if (!tsec) - return -ENOMEM; + const struct task_security_struct *old_tsec = selinux_cred(old); + struct task_security_struct *tsec = selinux_cred(new); - new->security = tsec; + *tsec = *old_tsec; return 0; } @@ -6678,6 +6644,10 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif +struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { + .lbs_cred = sizeof(struct task_security_struct), +}; + static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), @@ -6761,8 +6731,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(file_open, selinux_file_open), LSM_HOOK_INIT(task_alloc, selinux_task_alloc), - LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank), - LSM_HOOK_INIT(cred_free, selinux_cred_free), LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), @@ -6981,6 +6949,7 @@ DEFINE_LSM(selinux) = { .name = "selinux", .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, .enabled = &selinux_enabled, + .blobs = &selinux_blob_sizes, .init = selinux_init, }; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 734b6833bdff..c2974b031d05 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "flask.h" #include "avc.h" @@ -158,9 +159,10 @@ struct bpf_security_struct { u32 sid; /*SID of bpf obj creater*/ }; +extern struct lsm_blob_sizes selinux_blob_sizes; static inline struct task_security_struct *selinux_cred(const struct cred *cred) { - return cred->security; + return cred->security + selinux_blob_sizes.lbs_cred; } #endif /* _SELINUX_OBJSEC_H_ */ diff --git a/security/smack/smack.h b/security/smack/smack.h index 01a922856eba..b27eb252e953 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -336,6 +336,7 @@ extern struct smack_known *smack_syslog_label; extern struct smack_known *smack_unconfined; #endif extern int smack_ptrace_rule; +extern struct lsm_blob_sizes smack_blob_sizes; extern struct smack_known smack_known_floor; extern struct smack_known smack_known_hat; @@ -358,7 +359,7 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; static inline struct task_smack *smack_cred(const struct cred *cred) { - return cred->security; + return cred->security + smack_blob_sizes.lbs_cred; } /* diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 9a050ca17296..bad27a8e1631 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -326,29 +326,20 @@ static struct inode_smack *new_inode_smack(struct smack_known *skp) } /** - * new_task_smack - allocate a task security blob + * init_task_smack - initialize a task security blob + * @tsp: blob to initialize * @task: a pointer to the Smack label for the running task * @forked: a pointer to the Smack label for the forked task - * @gfp: type of the memory for the allocation * - * Returns the new blob or NULL if there's no memory available */ -static struct task_smack *new_task_smack(struct smack_known *task, - struct smack_known *forked, gfp_t gfp) +static void init_task_smack(struct task_smack *tsp, struct smack_known *task, + struct smack_known *forked) { - struct task_smack *tsp; - - tsp = kzalloc(sizeof(struct task_smack), gfp); - if (tsp == NULL) - return NULL; - tsp->smk_task = task; tsp->smk_forked = forked; INIT_LIST_HEAD(&tsp->smk_rules); INIT_LIST_HEAD(&tsp->smk_relabel); mutex_init(&tsp->smk_rules_lock); - - return tsp; } /** @@ -1881,14 +1872,7 @@ static int smack_file_open(struct file *file) */ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) { - struct task_smack *tsp; - - tsp = new_task_smack(NULL, NULL, gfp); - if (tsp == NULL) - return -ENOMEM; - - cred->security = tsp; - + init_task_smack(smack_cred(cred), NULL, NULL); return 0; } @@ -1905,10 +1889,6 @@ static void smack_cred_free(struct cred *cred) struct list_head *l; struct list_head *n; - if (tsp == NULL) - return; - cred->security = NULL; - smk_destroy_label_list(&tsp->smk_relabel); list_for_each_safe(l, n, &tsp->smk_rules) { @@ -1916,7 +1896,6 @@ static void smack_cred_free(struct cred *cred) list_del(&rp->list); kfree(rp); } - kfree(tsp); } /** @@ -1931,14 +1910,10 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { struct task_smack *old_tsp = smack_cred(old); - struct task_smack *new_tsp; + struct task_smack *new_tsp = smack_cred(new); int rc; - new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp); - if (new_tsp == NULL) - return -ENOMEM; - - new->security = new_tsp; + init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task); rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); if (rc != 0) @@ -1946,10 +1921,7 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel, gfp); - if (rc != 0) - return rc; - - return 0; + return rc; } /** @@ -4581,6 +4553,10 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, return 0; } +struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { + .lbs_cred = sizeof(struct task_smack), +}; + static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), @@ -4758,20 +4734,25 @@ static __init void init_smack_known_list(void) */ static __init int smack_init(void) { - struct cred *cred; + struct cred *cred = (struct cred *) current->cred; struct task_smack *tsp; smack_inode_cache = KMEM_CACHE(inode_smack, 0); if (!smack_inode_cache) return -ENOMEM; - tsp = new_task_smack(&smack_known_floor, &smack_known_floor, - GFP_KERNEL); - if (tsp == NULL) { - kmem_cache_destroy(smack_inode_cache); - return -ENOMEM; - } + lsm_early_cred(cred); + /* + * Set the security state for the initial task. + */ + tsp = smack_cred(cred); + init_task_smack(tsp, &smack_known_floor, &smack_known_floor); + + /* + * Register with LSM + */ + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); smack_enabled = 1; pr_info("Smack: Initializing.\n"); @@ -4785,20 +4766,9 @@ static __init int smack_init(void) pr_info("Smack: IPv6 Netfilter enabled.\n"); #endif - /* - * Set the security state for the initial task. - */ - cred = (struct cred *) current->cred; - cred->security = tsp; - /* initialize the smack_known_list */ init_smack_known_list(); - /* - * Register with LSM - */ - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); - return 0; } @@ -4809,5 +4779,6 @@ static __init int smack_init(void) DEFINE_LSM(smack) = { .name = "smack", .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, + .blobs = &smack_blob_sizes, .init = smack_init, }; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 41898613d93b..4fc17294a12d 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -1087,6 +1087,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; +extern struct lsm_blob_sizes tomoyo_blob_sizes; /********** Inlined functions. **********/ @@ -1206,7 +1207,7 @@ static inline void tomoyo_put_group(struct tomoyo_group *group) */ static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred) { - return (struct tomoyo_domain_info **)&cred->security; + return cred->security + tomoyo_blob_sizes.lbs_cred; } /** diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 15864307925d..9094cf41a247 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -509,6 +509,10 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, return tomoyo_socket_sendmsg_permission(sock, msg, size); } +struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = { + .lbs_cred = sizeof(struct tomoyo_domain_info *), +}; + /* * tomoyo_security_ops is a "struct security_operations" which is used for * registering TOMOYO. @@ -562,6 +566,7 @@ static int __init tomoyo_init(void) /* register ourselves with the security framework */ security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); printk(KERN_INFO "TOMOYO Linux initialized\n"); + lsm_early_cred(cred); blob = tomoyo_cred(cred); *blob = &tomoyo_kernel_domain; tomoyo_mm_init(); @@ -573,5 +578,6 @@ DEFINE_LSM(tomoyo) = { .name = "tomoyo", .enabled = &tomoyo_enabled, .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, + .blobs = &tomoyo_blob_sizes, .init = tomoyo_init, }; -- cgit v1.2.3 From 33bf60cabcc7687b194a689b068b65e9ecd556be Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Mon, 12 Nov 2018 12:02:49 -0800 Subject: LSM: Infrastructure management of the file security Move management of the file->f_security blob out of the individual security modules and into the infrastructure. The modules no longer allocate or free the data, instead they tell the infrastructure how much space they require. Signed-off-by: Casey Schaufler Reviewed-by: Kees Cook [kees: adjusted for ordered init series] Signed-off-by: Kees Cook --- include/linux/lsm_hooks.h | 1 + security/apparmor/include/file.h | 5 +++- security/apparmor/lsm.c | 19 +++++++------- security/security.c | 54 ++++++++++++++++++++++++++++++++++++--- security/selinux/hooks.c | 25 ++---------------- security/selinux/include/objsec.h | 2 +- security/smack/smack.h | 3 ++- security/smack/smack_lsm.c | 14 +--------- 8 files changed, 72 insertions(+), 51 deletions(-) (limited to 'security/apparmor/include') diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index dd33666567bc..e8cef019b645 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2032,6 +2032,7 @@ struct security_hook_list { */ struct lsm_blob_sizes { int lbs_cred; + int lbs_file; }; /* diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 4c2c8ac8842f..8be09208cf7c 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -32,7 +32,10 @@ struct path; AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \ AA_EXEC_MMAP | AA_MAY_LINK) -#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security) +static inline struct aa_file_ctx *file_ctx(struct file *file) +{ + return file->f_security + apparmor_blob_sizes.lbs_file; +} /* struct aa_file_ctx - the AppArmor context the file was opened in * @lock: lock to update the ctx diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d5e4a384f205..6821187b06ad 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -434,21 +434,21 @@ static int apparmor_file_open(struct file *file) static int apparmor_file_alloc_security(struct file *file) { - int error = 0; - - /* freed by apparmor_file_free_security */ + struct aa_file_ctx *ctx = file_ctx(file); struct aa_label *label = begin_current_label_crit_section(); - file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL); - if (!file_ctx(file)) - error = -ENOMEM; - end_current_label_crit_section(label); - return error; + spin_lock_init(&ctx->lock); + rcu_assign_pointer(ctx->label, aa_get_label(label)); + end_current_label_crit_section(label); + return 0; } static void apparmor_file_free_security(struct file *file) { - aa_free_file_ctx(file_ctx(file)); + struct aa_file_ctx *ctx = file_ctx(file); + + if (ctx) + aa_put_label(rcu_access_pointer(ctx->label)); } static int common_file_perm(const char *op, struct file *file, u32 mask) @@ -1156,6 +1156,7 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, */ struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct aa_task_ctx *), + .lbs_file = sizeof(struct aa_file_ctx), }; static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { diff --git a/security/security.c b/security/security.c index 09be8ce007a2..f32d7d2075c6 100644 --- a/security/security.c +++ b/security/security.c @@ -40,6 +40,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init; static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); +static struct kmem_cache *lsm_file_cache; + char *lsm_names; static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; @@ -158,6 +160,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) return; lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred); + lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file); } /* Prepare LSM for initialization. */ @@ -279,6 +282,15 @@ static void __init ordered_lsm_init(void) prepare_lsm(*lsm); init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); + init_debug("file blob size = %d\n", blob_sizes.lbs_file); + + /* + * Create any kmem_caches needed for blobs + */ + if (blob_sizes.lbs_file) + lsm_file_cache = kmem_cache_create("lsm_file_cache", + blob_sizes.lbs_file, 0, + SLAB_PANIC, NULL); for (lsm = ordered_lsms; *lsm; lsm++) initialize_lsm(*lsm); @@ -448,6 +460,27 @@ void __init lsm_early_cred(struct cred *cred) panic("%s: Early cred alloc failed.\n", __func__); } +/** + * lsm_file_alloc - allocate a composite file blob + * @file: the file that needs a blob + * + * Allocate the file blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +static int lsm_file_alloc(struct file *file) +{ + if (!lsm_file_cache) { + file->f_security = NULL; + return 0; + } + + file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL); + if (file->f_security == NULL) + return -ENOMEM; + return 0; +} + /* * Hook list operation macros. * @@ -1144,12 +1177,27 @@ int security_file_permission(struct file *file, int mask) int security_file_alloc(struct file *file) { - return call_int_hook(file_alloc_security, 0, file); + int rc = lsm_file_alloc(file); + + if (rc) + return rc; + rc = call_int_hook(file_alloc_security, 0, file); + if (unlikely(rc)) + security_file_free(file); + return rc; } void security_file_free(struct file *file) { + void *blob; + call_void_hook(file_free_security, file); + + blob = file->f_security; + if (blob) { + file->f_security = NULL; + kmem_cache_free(lsm_file_cache, blob); + } } int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -1267,7 +1315,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) return rc; rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); - if (rc) + if (unlikely(rc)) security_cred_free(cred); return rc; } @@ -1288,7 +1336,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) return rc; rc = call_int_hook(cred_prepare, 0, new, old, gfp); - if (rc) + if (unlikely(rc)) security_cred_free(new); return rc; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 620be0367c0b..632813821da6 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -146,7 +146,6 @@ static int __init checkreqprot_setup(char *str) __setup("checkreqprot=", checkreqprot_setup); static struct kmem_cache *sel_inode_cache; -static struct kmem_cache *file_security_cache; /** * selinux_secmark_enabled - Check to see if SECMARK is currently enabled @@ -378,27 +377,15 @@ static void inode_free_security(struct inode *inode) static int file_alloc_security(struct file *file) { - struct file_security_struct *fsec; + struct file_security_struct *fsec = selinux_file(file); u32 sid = current_sid(); - fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL); - if (!fsec) - return -ENOMEM; - fsec->sid = sid; fsec->fown_sid = sid; - file->f_security = fsec; return 0; } -static void file_free_security(struct file *file) -{ - struct file_security_struct *fsec = selinux_file(file); - file->f_security = NULL; - kmem_cache_free(file_security_cache, fsec); -} - static int superblock_alloc_security(struct super_block *sb) { struct superblock_security_struct *sbsec; @@ -3345,11 +3332,6 @@ static int selinux_file_alloc_security(struct file *file) return file_alloc_security(file); } -static void selinux_file_free_security(struct file *file) -{ - file_free_security(file); -} - /* * Check whether a task has the ioctl permission and cmd * operation to an inode. @@ -6646,6 +6628,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct task_security_struct), + .lbs_file = sizeof(struct file_security_struct), }; static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { @@ -6717,7 +6700,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), - LSM_HOOK_INIT(file_free_security, selinux_file_free_security), LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), LSM_HOOK_INIT(mmap_file, selinux_mmap_file), LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr), @@ -6902,9 +6884,6 @@ static __init int selinux_init(void) sel_inode_cache = kmem_cache_create("selinux_inode_security", sizeof(struct inode_security_struct), 0, SLAB_PANIC, NULL); - file_security_cache = kmem_cache_create("selinux_file_security", - sizeof(struct file_security_struct), - 0, SLAB_PANIC, NULL); avc_init(); avtab_cache_init(); diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index e0ac2992e059..96374dbf4ace 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -167,7 +167,7 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred) static inline struct file_security_struct *selinux_file(const struct file *file) { - return file->f_security; + return file->f_security + selinux_blob_sizes.lbs_file; } #endif /* _SELINUX_OBJSEC_H_ */ diff --git a/security/smack/smack.h b/security/smack/smack.h index 50854969a391..2007d38d0e46 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -364,7 +364,8 @@ static inline struct task_smack *smack_cred(const struct cred *cred) static inline struct smack_known **smack_file(const struct file *file) { - return (struct smack_known **)&file->f_security; + return (struct smack_known **)(file->f_security + + smack_blob_sizes.lbs_file); } /* diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 8f72641f94ab..7c76668ea3a6 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1495,18 +1495,6 @@ static int smack_file_alloc_security(struct file *file) return 0; } -/** - * smack_file_free_security - clear a file security blob - * @file: the object - * - * The security blob for a file is a pointer to the master - * label list, so no memory is freed. - */ -static void smack_file_free_security(struct file *file) -{ - file->f_security = NULL; -} - /** * smack_file_ioctl - Smack check on ioctls * @file: the object @@ -4559,6 +4547,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct task_smack), + .lbs_file = sizeof(struct smack_known *), }; static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { @@ -4595,7 +4584,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), - LSM_HOOK_INIT(file_free_security, smack_file_free_security), LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), LSM_HOOK_INIT(file_lock, smack_file_lock), LSM_HOOK_INIT(file_fcntl, smack_file_fcntl), -- cgit v1.2.3 From f4ad8f2c40769b3cc9497ba0883bbaf823f7752f Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Fri, 21 Sep 2018 17:19:37 -0700 Subject: LSM: Infrastructure management of the task security Move management of the task_struct->security blob out of the individual security modules and into the security infrastructure. Instead of allocating the blobs from within the modules the modules tell the infrastructure how much space is required, and the space is allocated there. The only user of this blob is AppArmor. The AppArmor use is abstracted to avoid future conflict. Signed-off-by: Casey Schaufler Reviewed-by: Kees Cook [kees: adjusted for ordered init series] Signed-off-by: Kees Cook --- include/linux/lsm_hooks.h | 2 ++ security/apparmor/include/task.h | 18 +++----------- security/apparmor/lsm.c | 15 +++-------- security/security.c | 54 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 62 insertions(+), 27 deletions(-) (limited to 'security/apparmor/include') diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 1c798e842de2..9b39fefa88c4 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2034,6 +2034,7 @@ struct lsm_blob_sizes { int lbs_cred; int lbs_file; int lbs_inode; + int lbs_task; }; /* @@ -2109,6 +2110,7 @@ extern int lsm_inode_alloc(struct inode *inode); #ifdef CONFIG_SECURITY void __init lsm_early_cred(struct cred *cred); +void __init lsm_early_task(struct task_struct *task); #endif #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index 55edaa1d83f8..039c1e60887a 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h @@ -14,7 +14,10 @@ #ifndef __AA_TASK_H #define __AA_TASK_H -#define task_ctx(X) ((X)->security) +static inline struct aa_task_ctx *task_ctx(struct task_struct *task) +{ + return task->security; +} /* * struct aa_task_ctx - information for current task label change @@ -36,17 +39,6 @@ int aa_set_current_hat(struct aa_label *label, u64 token); int aa_restore_previous_label(u64 cookie); struct aa_label *aa_get_task_label(struct task_struct *task); -/** - * aa_alloc_task_ctx - allocate a new task_ctx - * @flags: gfp flags for allocation - * - * Returns: allocated buffer or NULL on failure - */ -static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags) -{ - return kzalloc(sizeof(struct aa_task_ctx), flags); -} - /** * aa_free_task_ctx - free a task_ctx * @ctx: task_ctx to free (MAYBE NULL) @@ -57,8 +49,6 @@ static inline void aa_free_task_ctx(struct aa_task_ctx *ctx) aa_put_label(ctx->nnp); aa_put_label(ctx->previous); aa_put_label(ctx->onexec); - - kzfree(ctx); } } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 6821187b06ad..60ef71268ccf 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -94,19 +94,14 @@ static void apparmor_task_free(struct task_struct *task) { aa_free_task_ctx(task_ctx(task)); - task_ctx(task) = NULL; } static int apparmor_task_alloc(struct task_struct *task, unsigned long clone_flags) { - struct aa_task_ctx *new = aa_alloc_task_ctx(GFP_KERNEL); - - if (!new) - return -ENOMEM; + struct aa_task_ctx *new = task_ctx(task); aa_dup_task_ctx(new, task_ctx(current)); - task_ctx(task) = new; return 0; } @@ -1157,6 +1152,7 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { .lbs_cred = sizeof(struct aa_task_ctx *), .lbs_file = sizeof(struct aa_file_ctx), + .lbs_task = sizeof(struct aa_task_ctx), }; static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { @@ -1487,15 +1483,10 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) static int __init set_init_ctx(void) { struct cred *cred = (struct cred *)current->real_cred; - struct aa_task_ctx *ctx; - - ctx = aa_alloc_task_ctx(GFP_KERNEL); - if (!ctx) - return -ENOMEM; lsm_early_cred(cred); + lsm_early_task(current); set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); - task_ctx(current) = ctx; return 0; } diff --git a/security/security.c b/security/security.c index 4989fb65e662..e59a1e1514ee 100644 --- a/security/security.c +++ b/security/security.c @@ -169,6 +169,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) if (needed->lbs_inode && blob_sizes.lbs_inode == 0) blob_sizes.lbs_inode = sizeof(struct rcu_head); lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode); + lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task); } /* Prepare LSM for initialization. */ @@ -292,6 +293,7 @@ static void __init ordered_lsm_init(void) init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); init_debug("file blob size = %d\n", blob_sizes.lbs_file); init_debug("inode blob size = %d\n", blob_sizes.lbs_inode); + init_debug("task blob size = %d\n", blob_sizes.lbs_task); /* * Create any kmem_caches needed for blobs @@ -515,6 +517,46 @@ int lsm_inode_alloc(struct inode *inode) return 0; } +/** + * lsm_task_alloc - allocate a composite task blob + * @task: the task that needs a blob + * + * Allocate the task blob for all the modules + * + * Returns 0, or -ENOMEM if memory can't be allocated. + */ +int lsm_task_alloc(struct task_struct *task) +{ + if (blob_sizes.lbs_task == 0) { + task->security = NULL; + return 0; + } + + task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL); + if (task->security == NULL) + return -ENOMEM; + return 0; +} + +/** + * lsm_early_task - during initialization allocate a composite task blob + * @task: the task that needs a blob + * + * Allocate the task blob for all the modules if it's not already there + */ +void __init lsm_early_task(struct task_struct *task) +{ + int rc; + + if (task == NULL) + panic("%s: task cred.\n", __func__); + if (task->security != NULL) + return; + rc = lsm_task_alloc(task); + if (rc) + panic("%s: Early task alloc failed.\n", __func__); +} + /* * Hook list operation macros. * @@ -1359,12 +1401,22 @@ int security_file_open(struct file *file) int security_task_alloc(struct task_struct *task, unsigned long clone_flags) { - return call_int_hook(task_alloc, 0, task, clone_flags); + int rc = lsm_task_alloc(task); + + if (rc) + return rc; + rc = call_int_hook(task_alloc, 0, task, clone_flags); + if (unlikely(rc)) + security_task_free(task); + return rc; } void security_task_free(struct task_struct *task) { call_void_hook(task_free, task); + + kfree(task->security); + task->security = NULL; } int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) -- cgit v1.2.3 From c1a85a00ea66cb6f0bd0f14e47c28c2b0999799f Mon Sep 17 00:00:00 2001 From: Micah Morton Date: Mon, 7 Jan 2019 16:10:53 -0800 Subject: LSM: generalize flag passing to security_capable This patch provides a general mechanism for passing flags to the security_capable LSM hook. It replaces the specific 'audit' flag that is used to tell security_capable whether it should log an audit message for the given capability check. The reason for generalizing this flag passing is so we can add an additional flag that signifies whether security_capable is being called by a setid syscall (which is needed by the proposed SafeSetID LSM). Signed-off-by: Micah Morton Reviewed-by: Kees Cook Signed-off-by: James Morris --- include/linux/lsm_hooks.h | 8 +++++--- include/linux/security.h | 28 ++++++++++++++-------------- kernel/capability.c | 22 +++++++++++++--------- kernel/seccomp.c | 4 ++-- security/apparmor/capability.c | 14 +++++++------- security/apparmor/include/capability.h | 2 +- security/apparmor/ipc.c | 3 ++- security/apparmor/lsm.c | 4 ++-- security/apparmor/resource.c | 2 +- security/commoncap.c | 17 +++++++++-------- security/security.c | 14 +++++--------- security/selinux/hooks.c | 18 +++++++++--------- security/smack/smack_access.c | 2 +- 13 files changed, 71 insertions(+), 67 deletions(-) (limited to 'security/apparmor/include') diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 40511a8a5ae6..195707210975 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1270,7 +1270,7 @@ * @cred contains the credentials to use. * @ns contains the user namespace we want the capability in * @cap contains the capability . - * @audit contains whether to write an audit message or not + * @opts contains options for the capable check * Return 0 if the capability is granted for @tsk. * @syslog: * Check permission before accessing the kernel message ring or changing @@ -1446,8 +1446,10 @@ union security_list_options { const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); - int (*capable)(const struct cred *cred, struct user_namespace *ns, - int cap, int audit); + int (*capable)(const struct cred *cred, + struct user_namespace *ns, + int cap, + unsigned int opts); int (*quotactl)(int cmds, int type, int id, struct super_block *sb); int (*quota_on)(struct dentry *dentry); int (*syslog)(int type); diff --git a/include/linux/security.h b/include/linux/security.h index b2c5333ed4b5..13537a49ae97 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -54,9 +54,12 @@ struct xattr; struct xfrm_sec_ctx; struct mm_struct; +/* Default (no) options for the capable function */ +#define CAP_OPT_NONE 0x0 /* If capable should audit the security request */ -#define SECURITY_CAP_NOAUDIT 0 -#define SECURITY_CAP_AUDIT 1 +#define CAP_OPT_NOAUDIT BIT(1) +/* If capable is being called by a setid function */ +#define CAP_OPT_INSETID BIT(2) /* LSM Agnostic defines for sb_set_mnt_opts */ #define SECURITY_LSM_NATIVE_LABELS 1 @@ -72,7 +75,7 @@ enum lsm_event { /* These functions are in security/commoncap.c */ extern int cap_capable(const struct cred *cred, struct user_namespace *ns, - int cap, int audit); + int cap, unsigned int opts); extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz); extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); extern int cap_ptrace_traceme(struct task_struct *parent); @@ -207,10 +210,10 @@ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted); -int security_capable(const struct cred *cred, struct user_namespace *ns, - int cap); -int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, - int cap); +int security_capable(const struct cred *cred, + struct user_namespace *ns, + int cap, + unsigned int opts); int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); @@ -464,14 +467,11 @@ static inline int security_capset(struct cred *new, } static inline int security_capable(const struct cred *cred, - struct user_namespace *ns, int cap) + struct user_namespace *ns, + int cap, + unsigned int opts) { - return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); -} - -static inline int security_capable_noaudit(const struct cred *cred, - struct user_namespace *ns, int cap) { - return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); + return cap_capable(cred, ns, cap, opts); } static inline int security_quotactl(int cmds, int type, int id, diff --git a/kernel/capability.c b/kernel/capability.c index 1e1c0236f55b..7718d7dcadc7 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -299,7 +299,7 @@ bool has_ns_capability(struct task_struct *t, int ret; rcu_read_lock(); - ret = security_capable(__task_cred(t), ns, cap); + ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE); rcu_read_unlock(); return (ret == 0); @@ -340,7 +340,7 @@ bool has_ns_capability_noaudit(struct task_struct *t, int ret; rcu_read_lock(); - ret = security_capable_noaudit(__task_cred(t), ns, cap); + ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT); rcu_read_unlock(); return (ret == 0); @@ -363,7 +363,9 @@ bool has_capability_noaudit(struct task_struct *t, int cap) return has_ns_capability_noaudit(t, &init_user_ns, cap); } -static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) +static bool ns_capable_common(struct user_namespace *ns, + int cap, + unsigned int opts) { int capable; @@ -372,8 +374,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) BUG(); } - capable = audit ? security_capable(current_cred(), ns, cap) : - security_capable_noaudit(current_cred(), ns, cap); + capable = security_capable(current_cred(), ns, cap, opts); if (capable == 0) { current->flags |= PF_SUPERPRIV; return true; @@ -394,7 +395,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) */ bool ns_capable(struct user_namespace *ns, int cap) { - return ns_capable_common(ns, cap, true); + return ns_capable_common(ns, cap, CAP_OPT_NONE); } EXPORT_SYMBOL(ns_capable); @@ -412,7 +413,7 @@ EXPORT_SYMBOL(ns_capable); */ bool ns_capable_noaudit(struct user_namespace *ns, int cap) { - return ns_capable_common(ns, cap, false); + return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT); } EXPORT_SYMBOL(ns_capable_noaudit); @@ -448,10 +449,11 @@ EXPORT_SYMBOL(capable); bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap) { + if (WARN_ON_ONCE(!cap_valid(cap))) return false; - if (security_capable(file->f_cred, ns, cap) == 0) + if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE) == 0) return true; return false; @@ -500,10 +502,12 @@ bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns) { int ret = 0; /* An absent tracer adds no restrictions */ const struct cred *cred; + rcu_read_lock(); cred = rcu_dereference(tsk->ptracer_cred); if (cred) - ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE); + ret = security_capable(cred, ns, CAP_SYS_PTRACE, + CAP_OPT_NOAUDIT); rcu_read_unlock(); return (ret == 0); } diff --git a/kernel/seccomp.c b/kernel/seccomp.c index d7f538847b84..38a77800def6 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -443,8 +443,8 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog) * behavior of privileged children. */ if (!task_no_new_privs(current) && - security_capable_noaudit(current_cred(), current_user_ns(), - CAP_SYS_ADMIN) != 0) + security_capable(current_cred(), current_user_ns(), + CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0) return ERR_PTR(-EACCES); /* Allocate a new seccomp_filter */ diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 253ef6e9d445..752f73980e30 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -110,13 +110,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile, * profile_capable - test if profile allows use of capability @cap * @profile: profile being enforced (NOT NULL, NOT unconfined) * @cap: capability to test if allowed - * @audit: whether an audit record should be generated + * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated * @sa: audit data (MAY BE NULL indicating no auditing) * * Returns: 0 if allowed else -EPERM */ -static int profile_capable(struct aa_profile *profile, int cap, int audit, - struct common_audit_data *sa) +static int profile_capable(struct aa_profile *profile, int cap, + unsigned int opts, struct common_audit_data *sa) { int error; @@ -126,7 +126,7 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit, else error = -EPERM; - if (audit == SECURITY_CAP_NOAUDIT) { + if (opts & CAP_OPT_NOAUDIT) { if (!COMPLAIN_MODE(profile)) return error; /* audit the cap request in complain mode but note that it @@ -142,13 +142,13 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit, * aa_capable - test permission to use capability * @label: label being tested for capability (NOT NULL) * @cap: capability to be tested - * @audit: whether an audit record should be generated + * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated * * Look up capability in profile capability set. * * Returns: 0 on success, or else an error code. */ -int aa_capable(struct aa_label *label, int cap, int audit) +int aa_capable(struct aa_label *label, int cap, unsigned int opts) { struct aa_profile *profile; int error = 0; @@ -156,7 +156,7 @@ int aa_capable(struct aa_label *label, int cap, int audit) sa.u.cap = cap; error = fn_for_each_confined(label, profile, - profile_capable(profile, cap, audit, &sa)); + profile_capable(profile, cap, opts, &sa)); return error; } diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h index e0304e2aeb7f..1b3663b6ab12 100644 --- a/security/apparmor/include/capability.h +++ b/security/apparmor/include/capability.h @@ -40,7 +40,7 @@ struct aa_caps { extern struct aa_sfs_entry aa_sfs_entry_caps[]; -int aa_capable(struct aa_label *label, int cap, int audit); +int aa_capable(struct aa_label *label, int cap, unsigned int opts); static inline void aa_free_cap_rules(struct aa_caps *caps) { diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 527ea1557120..aacd1e95cb59 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -107,7 +107,8 @@ static int profile_tracer_perm(struct aa_profile *tracer, aad(sa)->label = &tracer->label; aad(sa)->peer = tracee; aad(sa)->request = 0; - aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); + aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, + CAP_OPT_NONE); return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 60ef71268ccf..b6c395e2acd0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -172,14 +172,14 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, } static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, - int cap, int audit) + int cap, unsigned int opts) { struct aa_label *label; int error = 0; label = aa_get_newest_cred_label(cred); if (!unconfined(label)) - error = aa_capable(label, cap, audit); + error = aa_capable(label, cap, opts); aa_put_label(label); return error; diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 95fd26d09757..552ed09cb47e 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, */ if (label != peer && - aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0) + aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0) error = fn_for_each(label, profile, audit_resource(profile, resource, new_rlim->rlim_max, peer, diff --git a/security/commoncap.c b/security/commoncap.c index 52e04136bfa8..188eaf59f82f 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -68,7 +68,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname) * kernel's capable() and has_capability() returns 1 for this case. */ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, - int cap, int audit) + int cap, unsigned int opts) { struct user_namespace *ns = targ_ns; @@ -222,12 +222,11 @@ int cap_capget(struct task_struct *target, kernel_cap_t *effective, */ static inline int cap_inh_is_capped(void) { - /* they are so limited unless the current task has the CAP_SETPCAP * capability */ if (cap_capable(current_cred(), current_cred()->user_ns, - CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) + CAP_SETPCAP, CAP_OPT_NONE) == 0) return 0; return 1; } @@ -1208,8 +1207,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ || (cap_capable(current_cred(), - current_cred()->user_ns, CAP_SETPCAP, - SECURITY_CAP_AUDIT) != 0) /*[4]*/ + current_cred()->user_ns, + CAP_SETPCAP, + CAP_OPT_NONE) != 0) /*[4]*/ /* * [1] no changing of bits that are locked * [2] no unlocking of locks @@ -1304,9 +1304,10 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages) { int cap_sys_admin = 0; - if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, - SECURITY_CAP_NOAUDIT) == 0) + if (cap_capable(current_cred(), &init_user_ns, + CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0) cap_sys_admin = 1; + return cap_sys_admin; } @@ -1325,7 +1326,7 @@ int cap_mmap_addr(unsigned long addr) if (addr < dac_mmap_min_addr) { ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, - SECURITY_CAP_AUDIT); + CAP_OPT_NONE); /* set PF_SUPERPRIV if it turns out we allow the low mmap */ if (ret == 0) current->flags |= PF_SUPERPRIV; diff --git a/security/security.c b/security/security.c index 953fc3ea18a9..a618e22df5c6 100644 --- a/security/security.c +++ b/security/security.c @@ -689,16 +689,12 @@ int security_capset(struct cred *new, const struct cred *old, effective, inheritable, permitted); } -int security_capable(const struct cred *cred, struct user_namespace *ns, - int cap) +int security_capable(const struct cred *cred, + struct user_namespace *ns, + int cap, + unsigned int opts) { - return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT); -} - -int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, - int cap) -{ - return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT); + return call_int_hook(capable, 0, cred, ns, cap, opts); } int security_quotactl(int cmds, int type, int id, struct super_block *sb) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d98e1d8d18f6..b2ee49f938f1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1578,7 +1578,7 @@ static inline u32 signal_to_av(int sig) /* Check whether a task is allowed to use a capability. */ static int cred_has_capability(const struct cred *cred, - int cap, int audit, bool initns) + int cap, unsigned int opts, bool initns) { struct common_audit_data ad; struct av_decision avd; @@ -1605,7 +1605,7 @@ static int cred_has_capability(const struct cred *cred, rc = avc_has_perm_noaudit(&selinux_state, sid, sid, sclass, av, 0, &avd); - if (audit == SECURITY_CAP_AUDIT) { + if (!(opts & CAP_OPT_NOAUDIT)) { int rc2 = avc_audit(&selinux_state, sid, sid, sclass, av, &avd, rc, &ad, 0); if (rc2) @@ -2125,9 +2125,9 @@ static int selinux_capset(struct cred *new, const struct cred *old, */ static int selinux_capable(const struct cred *cred, struct user_namespace *ns, - int cap, int audit) + int cap, unsigned int opts) { - return cred_has_capability(cred, cap, audit, ns == &init_user_ns); + return cred_has_capability(cred, cap, opts, ns == &init_user_ns); } static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) @@ -2201,7 +2201,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) int rc, cap_sys_admin = 0; rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, - SECURITY_CAP_NOAUDIT, true); + CAP_OPT_NOAUDIT, true); if (rc == 0) cap_sys_admin = 1; @@ -2988,11 +2988,11 @@ static int selinux_inode_getattr(const struct path *path) static bool has_cap_mac_admin(bool audit) { const struct cred *cred = current_cred(); - int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT; + unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT; - if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit)) + if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts)) return false; - if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true)) + if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true)) return false; return true; } @@ -3387,7 +3387,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, case KDSKBENT: case KDSKBSENT: error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, - SECURITY_CAP_AUDIT, true); + CAP_OPT_NONE, true); break; /* default case assumes that the command will go diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 489d49a20b47..fe2ce3a65822 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -640,7 +640,7 @@ bool smack_privileged_cred(int cap, const struct cred *cred) struct smack_known_list_elem *sklep; int rc; - rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT); + rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE); if (rc) return false; -- cgit v1.2.3 From 6c2976b06f6813768d3e61aeeb2b3fb04597a25f Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 21 Jan 2019 10:25:10 +0900 Subject: apparmor: Adjust offset when accessing task blob. AppArmor will no longer be the only user of task blob after TOMOYO started using task blob. Signed-off-by: Tetsuo Handa Fixes: f4ad8f2c4076 ("LSM: Infrastructure management of the task security") Acked-by: Kees Cook Signed-off-by: James Morris --- security/apparmor/include/task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security/apparmor/include') diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index 039c1e60887a..311e652324e3 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h @@ -16,7 +16,7 @@ static inline struct aa_task_ctx *task_ctx(struct task_struct *task) { - return task->security; + return task->security + apparmor_blob_sizes.lbs_task; } /* -- cgit v1.2.3