From patchwork Fri May 11 00:52:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Casey Schaufler X-Patchwork-Id: 10392835 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 062C86028E for ; Fri, 11 May 2018 00:58:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D39A828516 for ; Fri, 11 May 2018 00:57:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C700C28553; Fri, 11 May 2018 00:57:59 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3D3B828516 for ; Fri, 11 May 2018 00:57:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751893AbeEKAw6 (ORCPT ); Thu, 10 May 2018 20:52:58 -0400 Received: from sonic311-29.consmr.mail.ne1.yahoo.com ([66.163.188.210]:40503 "EHLO sonic311-29.consmr.mail.ne1.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751839AbeEKAwz (ORCPT ); Thu, 10 May 2018 20:52:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1525999974; bh=qh2a476E6mWjPwbU/hs6l/l+DIjRcUctzHEMqxBvBx0=; h=Subject:To:References:From:Date:In-Reply-To:From:Subject; b=PT/hYQiqXP5PfVfW0D87ioh7xcPadSXHDkzyumiEU3OZ9WcHhMn9E4AGXtGujaJRmYfFHPftHWqsx1CwpVIATthF3lQVvMOeZlKM0sLM8BEpI9ljD/3RIjcaX6OvNiqofS7wFT86tnI+smot7pXgJBy6ly//butdBoG59rC1s1lw0mfy7JJmDeCj6wTOnABGVzlMm8XVT3Cwk18/QzWeymnIeRfHTdZxTucgfqNlHPmM6F+/bYLPGbX+zoTYdWSUkjWFGL/r0tvaiU40piB2S0e8d+sRL7dE+1ager+Sk1y56Lq+XNHo2W6mHoHFRu6vfJ7P6qMa0CnPk5MhIHC7nQ== X-YMail-OSG: 1zS0ynQVM1mE4fB8_JWsyu26EuHF3yo_ysw.J5h5HmwV9onGevlYCfzgb9iqM5l 2jo4CANCfb3XlSdifnd5pb10S4l_r2YDtLyWtIPjr_kIoyWC9gDzRG0USAj1B4iQLzoiy6FNyIwd j1BhejXni2OmoiX3tsQ_zTBq7VUeSNvkzVzQEFcek9yjngSGHYqedZ69i_TXnZG9rGU34nhCdgBJ PZeo7eYrZcDFzd3D1pcrF_iBlRZm4WI6b5rEyOBtyqwbDriLjj8EernvNsrXdpWeI3KwWZpPzDj9 tXekVSpxchqjoAQyVpRBSVUsHEgZe._gywmA6efdVVjV60O5uAytkx27lSE5ZmqXbI2xIYIU3rjy QCRQ2BYtZg0LTdxEZmRW2GIPH0cKui.26yXcJglPovk_DQ8P66TFa0L0xmD4ZMfnWGrm9xixX0OL M0de8AyrM2uOLvY8a8kbZd6Lk.BjQOjLry6n2i4iz9nVSZTrbBO0_Q4.X8uoir_xl4qGTvq0nC2I Q6kVcZZ1JWKRcY4WuHTWQ04J_CxZSI3Zm0C0v4CgA9EVJYMYYyATolE6D_cy5HDvfa95vsCJoP_k RaHCNDQjUtMy3Yd3jxY92mXKTvFpAPwt5vA6CHhIL1cKZ2.C9G9jiYe9SomA99jykKfEvuW8dQ8J .Pus- Received: from sonic.gate.mail.ne1.yahoo.com by sonic311.consmr.mail.ne1.yahoo.com with HTTP; Fri, 11 May 2018 00:52:54 +0000 Received: from c-67-169-65-224.hsd1.ca.comcast.net (EHLO [192.168.0.105]) ([67.169.65.224]) by smtp413.mail.ne1.yahoo.com (Oath Hermes SMTP Server) with ESMTPA ID ba3965a0c758cca8fa01e2e4307280b0; Fri, 11 May 2018 00:52:50 +0000 (UTC) Subject: [PATCH 04/23] LSM: Infrastructure management of the cred security To: LSM , LKLM , Paul Moore , Stephen Smalley , SE Linux , "SMACK-discuss@lists.01.org" , John Johansen , Kees Cook , Tetsuo Handa , James Morris References: <7e8702ce-2598-e0a3-31a2-bc29157fb73d@schaufler-ca.com> From: Casey Schaufler Message-ID: <50f5db54-b621-5293-9e53-eaf44f86fc68@schaufler-ca.com> Date: Thu, 10 May 2018 17:52:47 -0700 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <7e8702ce-2598-e0a3-31a2-bc29157fb73d@schaufler-ca.com> Content-Language: en-US Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: Casey Schaufler Date: Thu, 10 May 2018 13:53:07 -0700 Subject: [PATCH 04/23] LSM: 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. Some SELinux memory management debug code has been removed. Signed-off-by: Casey Schaufler --- include/linux/lsm_hooks.h | 14 +++++ kernel/cred.c | 13 ----- security/Kconfig | 11 ++++ security/apparmor/domain.c | 2 +- security/apparmor/include/cred.h | 16 +++++- security/apparmor/lsm.c | 28 ++++++++-- security/apparmor/task.c | 6 +-- security/security.c | 106 ++++++++++++++++++++++++++++++++++++-- security/selinux/hooks.c | 63 ++++++---------------- security/selinux/include/objsec.h | 4 ++ security/selinux/selinuxfs.c | 1 + security/smack/smack.h | 1 + security/smack/smack_access.c | 2 +- security/smack/smack_lsm.c | 85 +++++++++++------------------- security/tomoyo/common.h | 21 +++++++- security/tomoyo/domain.c | 4 +- security/tomoyo/securityfs_if.c | 15 ++++-- security/tomoyo/tomoyo.c | 56 ++++++++++++++++---- 18 files changed, 304 insertions(+), 144 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9d0b286f3dba..ee22b2b9b458 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2011,6 +2011,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 @@ -2023,6 +2030,7 @@ struct security_hook_list { extern struct security_hook_heads security_hook_heads; extern char *lsm_names; +extern void security_add_blobs(struct lsm_blob_sizes *needed); extern void security_add_hooks(struct security_hook_list *hooks, int count, char *lsm); @@ -2069,4 +2077,10 @@ void __init loadpin_add_hooks(void); static inline void loadpin_add_hooks(void) { }; #endif +extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp); + +#ifdef CONFIG_SECURITY +void lsm_early_cred(struct cred *cred); +#endif + #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/kernel/cred.c b/kernel/cred.c index ecf03657e71c..fa2061ee4955 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -704,19 +704,6 @@ bool creds_are_invalid(const struct cred *cred) { if (cred->magic != CRED_MAGIC) return true; -#ifdef CONFIG_SECURITY_SELINUX - /* - * cred->security == NULL if security_cred_alloc_blank() or - * security_prepare_creds() returned an error. - */ - if (selinux_is_enabled() && cred->security) { - if ((unsigned long) cred->security < PAGE_SIZE) - return true; - if ((*(u32 *)cred->security & 0xffffff00) == - (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) - return true; - } -#endif return false; } EXPORT_SYMBOL(creds_are_invalid); diff --git a/security/Kconfig b/security/Kconfig index c4302067a3ad..116dba966553 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -36,6 +36,17 @@ config SECURITY_WRITABLE_HOOKS bool default n +config SECURITY_LSM_DEBUG + bool "Enable debugging of the LSM infrastructure" + depends on SECURITY + help + This allows you to choose debug messages related to + security modules configured into your kernel. These + messages may be helpful in determining how a security + module is using security blobs. + + If you are unsure how to answer this question, answer N. + config SECURITYFS bool "Enable the securityfs filesystem" help diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 590b7e8cd21c..1fe17fba2a95 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -975,7 +975,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) } aa_put_label(cred_label(bprm->cred)); /* transfer reference, released when cred is freed */ - cred_label(bprm->cred) = new; + set_cred_label(bprm->cred, new); done: aa_put_label(label); diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h index e287b7d0d4be..a90eae76d7c1 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 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index ce2b89e9ad94..a35ef9473b71 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -56,7 +56,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers); static void apparmor_cred_free(struct cred *cred) { aa_put_label(cred_label(cred)); - cred_label(cred) = NULL; + set_cred_label(cred, NULL); } /* @@ -64,7 +64,7 @@ static void apparmor_cred_free(struct cred *cred) */ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) { - cred_label(cred) = NULL; + set_cred_label(cred, NULL); return 0; } @@ -74,7 +74,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) static int apparmor_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - cred_label(new) = aa_get_newest_label(cred_label(old)); + set_cred_label(new, aa_get_newest_label(cred_label(old))); return 0; } @@ -83,7 +83,7 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, */ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) { - cred_label(new) = aa_get_newest_label(cred_label(old)); + set_cred_label(new, aa_get_newest_label(cred_label(old))); } static void apparmor_task_free(struct task_struct *task) @@ -1117,6 +1117,13 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent) ctx->label = aa_get_current_label(); } +/* + * The cred blob is a pointer to, not an instance of, an aa_task_ctx. + */ +struct lsm_blob_sizes apparmor_blob_sizes = { + .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), @@ -1437,7 +1444,8 @@ static int __init set_init_ctx(void) if (!ctx) return -ENOMEM; - cred_label(cred) = aa_get_label(ns_unconfined(root_ns)); + lsm_early_cred(cred); + set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); task_ctx(current) = ctx; return 0; @@ -1522,8 +1530,18 @@ static inline int apparmor_init_sysctl(void) static int __init apparmor_init(void) { + static int finish; int error; + if (!finish) { + if (apparmor_enabled && security_module_enable("apparmor")) + security_add_blobs(&apparmor_blob_sizes); + else + apparmor_enabled = false; + finish = 1; + return 0; + } + if (!apparmor_enabled || !security_module_enable("apparmor")) { aa_info_message("AppArmor disabled by boot time parameter"); apparmor_enabled = false; diff --git a/security/apparmor/task.c b/security/apparmor/task.c index c6b78a14da91..4551110f0496 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -81,7 +81,7 @@ int aa_replace_current_label(struct aa_label *label) */ aa_get_label(label); aa_put_label(cred_label(new)); - cred_label(new) = label; + set_cred_label(new, label); commit_creds(new); return 0; @@ -138,7 +138,7 @@ int aa_set_current_hat(struct aa_label *label, u64 token) return -EACCES; } - cred_label(new) = aa_get_newest_label(label); + set_cred_label(new, aa_get_newest_label(label)); /* clear exec on switching context */ aa_put_label(ctx->onexec); ctx->onexec = NULL; @@ -172,7 +172,7 @@ int aa_restore_previous_label(u64 token) return -ENOMEM; aa_put_label(cred_label(new)); - cred_label(new) = aa_get_newest_label(ctx->previous); + set_cred_label(new, aa_get_newest_label(ctx->previous)); AA_BUG(!cred_label(new)); /* clear exec && prev information when restoring to previous context */ aa_clear_task_ctx_trans(ctx); diff --git a/security/security.c b/security/security.c index 3d3c746fd517..16e8fb077412 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; + /* Boot-time LSM user choice */ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_DEFAULT_SECURITY; @@ -82,10 +84,22 @@ int __init security_init(void) loadpin_add_hooks(); /* - * Load all the remaining security modules. + * The first call to a module specific init function + * updates the blob size requirements. + */ + do_security_initcalls(); + + /* + * The second call to a module specific init function + * adds hooks to the hook lists and does any other early + * initializations required. */ do_security_initcalls(); +#ifdef CONFIG_SECURITY_LSM_DEBUG + pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred); +#endif + return 0; } @@ -193,6 +207,73 @@ 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. + */ +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 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__); +} + +static void __init lsm_set_size(int *need, int *lbs) +{ + int offset; + + if (*need > 0) { + offset = *lbs; + *lbs += *need; + *need = offset; + } +} + +/** + * security_add_blobs - Report blob sizes + * @needed: the size of blobs needed by the module + * + * Each LSM has to register its blobs with the infrastructure. + * The "needed" data tells the infrastructure how much memory + * the module requires for each of its blobs. On return the + * structure is filled with the offset that module should use + * from the blob pointer. + */ +void __init security_add_blobs(struct lsm_blob_sizes *needed) +{ + lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred); +} + /* * Hook list operation macros. * @@ -993,17 +1074,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 81b1715a1998..f4179eb572e8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -213,12 +213,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; } /* @@ -3886,53 +3883,17 @@ 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); - - /* - * cred->security == NULL if security_cred_alloc_blank() or - * security_prepare_creds() returned an error. - */ - BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE); - cred->security = (void *) 0x7UL; - 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); + const struct task_security_struct *old_tsec = selinux_cred(old); + struct task_security_struct *tsec = selinux_cred(new); - tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); - if (!tsec) - return -ENOMEM; + *tsec = *old_tsec; - new->security = tsec; return 0; } @@ -6848,6 +6809,10 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif +struct lsm_blob_sizes selinux_blob_sizes = { + .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), @@ -6930,8 +6895,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), @@ -7085,11 +7048,19 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { static __init int selinux_init(void) { + static int finish; + if (!security_module_enable("selinux")) { selinux_enabled = 0; return 0; } + if (!finish) { + security_add_blobs(&selinux_blob_sizes); + finish = 1; + return 0; + } + if (!selinux_enabled) { printk(KERN_INFO "SELinux: Disabled at boot.\n"); return 0; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 734b6833bdff..db1c7000ada3 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include "flask.h" #include "avc.h" @@ -158,6 +161,7 @@ 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; diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 245160373dab..a1a389c09857 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -31,6 +31,7 @@ #include #include #include +#include /* selinuxfs pseudo filesystem for exporting the security policy API. Based on the proc code and the fs/nfsd/nfsctl.c code. */ diff --git a/security/smack/smack.h b/security/smack/smack.h index 0b55d6a55b26..0c6dce446825 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -24,6 +24,7 @@ #include #include #include +#include /* * Use IPv6 port labeling if IPv6 is enabled and secmarks diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 489d49a20b47..133774805594 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -635,7 +635,7 @@ DEFINE_MUTEX(smack_onlycap_lock); */ bool smack_privileged_cred(int cap, const struct cred *cred) { - struct task_smack *tsp = smack_cred(cred); + struct task_smack *tsp = cred->security; struct smack_known *skp = tsp->smk_task; struct smack_known_list_elem *sklep; int rc; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d9307a172ab7..bcba72d760f4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -308,29 +308,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; } /** @@ -1957,14 +1948,7 @@ static int smack_file_open(struct file *file, const struct cred *cred) */ 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; } @@ -1981,10 +1965,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) { @@ -1992,7 +1972,6 @@ static void smack_cred_free(struct cred *cred) list_del(&rp->list); kfree(rp); } - kfree(tsp); } /** @@ -2007,14 +1986,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) @@ -2022,10 +1997,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; } /** @@ -4622,6 +4594,10 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, return 0; } +struct lsm_blob_sizes smack_blob_sizes = { + .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), @@ -4799,23 +4775,35 @@ static __init void init_smack_known_list(void) */ static __init int smack_init(void) { - struct cred *cred; + static int finish; + struct cred *cred = (struct cred *) current->cred; struct task_smack *tsp; if (!security_module_enable("smack")) return 0; + if (!finish) { + security_add_blobs(&smack_blob_sizes); + finish = 1; + return 0; + } + 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"); @@ -4829,20 +4817,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; } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 539bcdd30bb8..0110bebe86e2 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1062,6 +1063,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt, /********** External variable definitions. **********/ extern bool tomoyo_policy_loaded; +extern bool tomoyo_enabled; extern const char * const tomoyo_condition_keyword [TOMOYO_MAX_CONDITION_KEYWORD]; extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; @@ -1196,6 +1198,17 @@ static inline void tomoyo_put_group(struct tomoyo_group *group) atomic_dec(&group->head.users); } +/** + * tomoyo_cred - Get a pointer to the tomoyo cred security blob + * @cred - the relevant cred + * + * Returns pointer to the tomoyo cred blob. + */ +static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred) +{ + return cred->security; +} + /** * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread. * @@ -1203,7 +1216,9 @@ static inline void tomoyo_put_group(struct tomoyo_group *group) */ static inline struct tomoyo_domain_info *tomoyo_domain(void) { - return current_cred()->security; + struct tomoyo_domain_info **blob = tomoyo_cred(current_cred()); + + return *blob; } /** @@ -1216,7 +1231,9 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void) static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct *task) { - return task_cred_xxx(task, security); + struct tomoyo_domain_info **blob = tomoyo_cred(get_task_cred(task)); + + return *blob; } /** diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index f6758dad981f..b7469fdbff01 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -678,6 +678,7 @@ static int tomoyo_environ(struct tomoyo_execve *ee) */ int tomoyo_find_next_domain(struct linux_binprm *bprm) { + struct tomoyo_domain_info **blob; struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *domain = NULL; const char *original_name = bprm->filename; @@ -843,7 +844,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) domain = old_domain; /* Update reference count on "struct tomoyo_domain_info". */ atomic_inc(&domain->users); - bprm->cred->security = domain; + blob = tomoyo_cred(bprm->cred); + *blob = domain; kfree(exename.name); if (!retval) { ee->r.domain = domain; diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index 1d3d7e7a1f05..768dff9608b1 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -71,9 +71,12 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, if (!cred) { error = -ENOMEM; } else { - struct tomoyo_domain_info *old_domain = - cred->security; - cred->security = new_domain; + struct tomoyo_domain_info **blob; + struct tomoyo_domain_info *old_domain; + + blob = tomoyo_cred(cred); + old_domain = *blob; + *blob = new_domain; atomic_inc(&new_domain->users); atomic_dec(&old_domain->users); commit_creds(cred); @@ -234,10 +237,14 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode, */ static int __init tomoyo_initerface_init(void) { + struct tomoyo_domain_info *domain; struct dentry *tomoyo_dir; + if (!tomoyo_enabled) + return 0; + domain = tomoyo_domain(); /* Don't create securityfs entries unless registered. */ - if (current_cred()->security != &tomoyo_kernel_domain) + if (domain != &tomoyo_kernel_domain) return 0; tomoyo_dir = securityfs_create_dir("tomoyo", NULL); diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 213b8c593668..821ca242a194 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -18,7 +18,9 @@ */ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) { - new->security = NULL; + struct tomoyo_domain_info **blob = tomoyo_cred(new); + + *blob = NULL; return 0; } @@ -34,8 +36,13 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - struct tomoyo_domain_info *domain = old->security; - new->security = domain; + struct tomoyo_domain_info **old_blob = tomoyo_cred(old); + struct tomoyo_domain_info **new_blob = tomoyo_cred(new); + struct tomoyo_domain_info *domain; + + domain = *old_blob; + *new_blob = domain; + if (domain) atomic_inc(&domain->users); return 0; @@ -59,7 +66,9 @@ static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) */ static void tomoyo_cred_free(struct cred *cred) { - struct tomoyo_domain_info *domain = cred->security; + struct tomoyo_domain_info **blob = tomoyo_cred(cred); + struct tomoyo_domain_info *domain = *blob; + if (domain) atomic_dec(&domain->users); } @@ -73,6 +82,9 @@ static void tomoyo_cred_free(struct cred *cred) */ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) { + struct tomoyo_domain_info **blob; + struct tomoyo_domain_info *domain; + /* * Do only if this function is called for the first time of an execve * operation. @@ -93,13 +105,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) * stored inside "bprm->cred->security" will be acquired later inside * tomoyo_find_next_domain(). */ - atomic_dec(&((struct tomoyo_domain_info *) - bprm->cred->security)->users); + blob = tomoyo_cred(bprm->cred); + domain = *blob; + atomic_dec(&domain->users); /* * Tell tomoyo_bprm_check_security() is called for the first time of an * execve operation. */ - bprm->cred->security = NULL; + *blob = NULL; return 0; } @@ -112,8 +125,11 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) */ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) { - struct tomoyo_domain_info *domain = bprm->cred->security; + struct tomoyo_domain_info **blob; + struct tomoyo_domain_info *domain; + blob = tomoyo_cred(bprm->cred); + domain = *blob; /* * Execute permission is checked against pathname passed to do_execve() * using current domain. @@ -493,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 = { + .lbs_cred = sizeof(struct tomoyo_domain_info *), +}; + /* * tomoyo_security_ops is a "struct security_operations" which is used for * registering TOMOYO. @@ -531,6 +551,8 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { /* Lock for GC. */ DEFINE_SRCU(tomoyo_ss); +bool tomoyo_enabled; + /** * tomoyo_init - Register TOMOYO Linux as a LSM module. * @@ -538,14 +560,28 @@ DEFINE_SRCU(tomoyo_ss); */ static int __init tomoyo_init(void) { + static int finish; struct cred *cred = (struct cred *) current_cred(); + struct tomoyo_domain_info **blob; + + if (!security_module_enable("tomoyo")) { + tomoyo_enabled = false; + return 0; + } + tomoyo_enabled = true; - if (!security_module_enable("tomoyo")) + if (!finish) { + security_add_blobs(&tomoyo_blob_sizes); + finish = 1; return 0; + } + /* register ourselves with the security framework */ security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); printk(KERN_INFO "TOMOYO Linux initialized\n"); - cred->security = &tomoyo_kernel_domain; + lsm_early_cred(cred); + blob = tomoyo_cred(cred); + *blob = &tomoyo_kernel_domain; tomoyo_mm_init(); return 0; }