From patchwork Thu Jan 26 02:07:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Casey Schaufler X-Patchwork-Id: 9538305 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 992C6604A7 for ; Thu, 26 Jan 2017 02:07:27 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6C1AB27C0C for ; Thu, 26 Jan 2017 02:07:27 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6097D27F07; Thu, 26 Jan 2017 02:07:27 +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=ham 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 D5B5F27C0C for ; Thu, 26 Jan 2017 02:07:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752447AbdAZCHY (ORCPT ); Wed, 25 Jan 2017 21:07:24 -0500 Received: from nm26-vm5.bullet.mail.ne1.yahoo.com ([98.138.91.248]:33660 "EHLO nm26-vm5.bullet.mail.ne1.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752299AbdAZCHX (ORCPT ); Wed, 25 Jan 2017 21:07:23 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1485396442; bh=j36Q5Ywod0fDOa/G5sD1/74gyeQgb9pOdw8otHSMoio=; h=Subject:To:References:Cc:From:Date:In-Reply-To:From:Subject; b=NjnFOCoG5t68w4hX9xumyg779iWmtUN8tWKmPlrIJNcFQQN0qHUPdegfBnW0nFcdDtqV+JKZKupqRIZyKKrcP7Ww/k/0pidMXD3Wnuad4wYsnmfNoe+meifWhLvmQTT1o0InBe4f+4IBTTbStx48MxIyMHOhCa6/YXKXrmHNxL6HIutZpk79Wp3SrFo8HCom59m+5SToa+v1LVgm8N2Hwiw9p32qiMCd5q5qnzp/fVjvDiQVvPoAbUTlbrINfdbFd6Q8XnHWmuAlP843jFIS2tynmBOxWdBfF1SjeTOKcK2JQWY4GfnOE3FqAtpEesVX0a9Rp1oKxm1z7CRTsN1RIA== Received: from [98.138.101.131] by nm26.bullet.mail.ne1.yahoo.com with NNFMP; 26 Jan 2017 02:07:22 -0000 Received: from [98.138.104.114] by tm19.bullet.mail.ne1.yahoo.com with NNFMP; 26 Jan 2017 02:07:22 -0000 Received: from [127.0.0.1] by smtp223.mail.ne1.yahoo.com with NNFMP; 26 Jan 2017 02:07:21 -0000 X-Yahoo-Newman-Id: 921604.38755.bm@smtp223.mail.ne1.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: 5OGpztgVM1kv8vfcvqQ7D.N0OjZDG8_4vccyi6upR4rw73H fciM1TxbjPtN8BdQ6HQ9nDEZCkyG8Bx7hQ9_f4MfOBkREbUoIZ5CqUv11K3V SNllxS5SPXq2Z7Jcuv0mUjKrNIe3Q0xKzGPlBL4HvtjXqiAj73DYQ3K3n8CZ 33c0iyK33tmEUqUHRhwTCHPFibYFHE2GmMuxUoXZAS.a5Xk3nHQqtXFzoXh2 7a6fZnNfQG0lh.XCVfnMX_vrDfwq6HhitPdxHF4Qudx9IUxpdJ_LxO1slbp2 TMNNgzEdtevtLRlW3wxV6wn1E2IwzMdtI3yuGXdI.OwfgfixH9Urra39DO87 zGQUB38qWUy3jsMfxsrj5GUpJ.eO3mzaXnbO39ho94iXCyDtdcO5EZm.QFJc M8mBJ8Z1PsQc_glydlF4ZIcz8u1DrkqDef7S2xA8ysr5rcGVrSjhNPtFBibE x9BdslzF2YokW5uujSG6BqmwyjlrLFzKq.ljPd.hM1CT._deV1FbHva9V8WJ sT1MVAcGZ5RvDKPKlv..TVAlblZ1PeVfj4QyGLHiLFPxcbE2_otFNCgvx5XW vp_Em9GIwMse2 X-Yahoo-SMTP: OIJXglSswBDfgLtXluJ6wiAYv6_cnw-- Subject: [PATCH RFC 3/9] LSM: Manage credential security blobs To: LSM References: Cc: James Morris , John Johansen , Tetsuo Handa , Paul Moore , Stephen Smalley , Kees Cook From: Casey Schaufler Message-ID: Date: Wed, 25 Jan 2017 18:07:19 -0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.6.0 MIME-Version: 1.0 In-Reply-To: Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH RFC 3/9] LSM: Manage credential security blobs Move the management of credential security blobs from the individual security modules to the security infrastructure. The security modules using credential blobs have been updated accordingly. Modules are required to identify the space they require at module initialization. In some cases a module no longer needs to supply blob management hook, in which case the hook has been removed. Signed-off-by: Casey Schaufler --- include/linux/lsm_hooks.h | 25 +++++++ kernel/cred.c | 13 ---- security/Kconfig | 11 +++ security/apparmor/context.c | 2 - security/apparmor/include/context.h | 10 ++- security/apparmor/lsm.c | 48 +++++-------- security/security.c | 79 ++++++++++++++++++++- security/selinux/hooks.c | 121 ++++++++++++------------------- security/selinux/include/objsec.h | 9 +++ security/selinux/selinuxfs.c | 3 +- security/selinux/xfrm.c | 4 +- security/smack/smack.h | 15 +++- security/smack/smack_access.c | 2 +- security/smack/smack_lsm.c | 138 +++++++++++++++--------------------- security/smack/smackfs.c | 18 ++--- security/tomoyo/common.h | 20 +++++- security/tomoyo/domain.c | 4 +- security/tomoyo/securityfs_if.c | 13 ++-- security/tomoyo/tomoyo.c | 49 ++++++++++--- 19 files changed, 349 insertions(+), 235 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 132650d..f26a5b4 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1880,6 +1880,13 @@ struct security_hook_list { }; /* + * 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 * care of the common case and reduces the amount of @@ -1891,6 +1898,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); @@ -1930,4 +1938,21 @@ 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 +static inline 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__); +} +#endif + #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/kernel/cred.c b/kernel/cred.c index 5f264fb..9dadd0f 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -703,19 +703,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 118f454..3356875 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -31,6 +31,17 @@ config SECURITY If you are unsure how to answer this question, answer 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/context.c b/security/apparmor/context.c index 3064c6c..6e54be2 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -50,8 +50,6 @@ void aa_free_task_context(struct aa_task_cxt *cxt) aa_put_profile(cxt->profile); aa_put_profile(cxt->previous); aa_put_profile(cxt->onexec); - - kzfree(cxt); } } diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 6bf6579..07fb7a1 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -18,10 +18,11 @@ #include #include #include +#include #include "policy.h" -#define cred_cxt(X) (X)->security +#define cred_cxt(X) apparmor_cred(X) #define current_cxt() cred_cxt(current_cred()) /* struct aa_file_cxt - the AppArmor context the file was opened in @@ -85,6 +86,10 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token); int aa_restore_previous_profile(u64 cookie); struct aa_profile *aa_get_task_profile(struct task_struct *task); +static inline struct aa_task_cxt *apparmor_cred(const struct cred *cred) +{ + return cred->security; +} /** * aa_cred_profile - obtain cred's profiles @@ -96,7 +101,8 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task); */ static inline struct aa_profile *aa_cred_profile(const struct cred *cred) { - struct aa_task_cxt *cxt = cred_cxt(cred); + struct aa_task_cxt *cxt = apparmor_cred(cred); + BUG_ON(!cxt || !cxt->profile); return cxt->profile; } diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1d4843d..8e25455 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -44,26 +44,11 @@ int apparmor_initialized __initdata; */ /* - * free the associated aa_task_cxt and put its profiles + * put the associated aa_task_cxt profiles */ static void apparmor_cred_free(struct cred *cred) { aa_free_task_context(cred_cxt(cred)); - cred_cxt(cred) = NULL; -} - -/* - * allocate the apparmor part of blank credentials - */ -static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) -{ - /* freed by apparmor_cred_free */ - struct aa_task_cxt *cxt = aa_alloc_task_context(gfp); - if (!cxt) - return -ENOMEM; - - cred_cxt(cred) = cxt; - return 0; } /* @@ -72,13 +57,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) { - /* freed by apparmor_cred_free */ - struct aa_task_cxt *cxt = aa_alloc_task_context(gfp); - if (!cxt) - return -ENOMEM; - - aa_dup_task_context(cxt, cred_cxt(old)); - cred_cxt(new) = cxt; + aa_dup_task_context(cred_cxt(new), cred_cxt(old)); return 0; } @@ -584,6 +563,10 @@ static int apparmor_task_setrlimit(struct task_struct *task, return error; } +struct lsm_blob_sizes apparmor_blob_sizes = { + .lbs_cred = sizeof(struct aa_task_cxt), +}; + static struct security_hook_list apparmor_hooks[] = { LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), @@ -613,7 +596,6 @@ static struct security_hook_list apparmor_hooks[] = { LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), - LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), LSM_HOOK_INIT(cred_free, apparmor_cred_free), LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer), @@ -854,26 +836,34 @@ static int __init set_init_cxt(void) struct cred *cred = (struct cred *)current->real_cred; struct aa_task_cxt *cxt; - cxt = aa_alloc_task_context(GFP_KERNEL); - if (!cxt) - return -ENOMEM; + lsm_early_cred(cred); + cxt = apparmor_cred(cred); cxt->profile = aa_get_profile(root_ns->unconfined); - cred_cxt(cred) = cxt; return 0; } 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); + finish = 1; + return 0; + } + if (!apparmor_enabled || !security_module_enable("apparmor")) { - aa_info_message("AppArmor disabled by boot time parameter"); + aa_info_message( + "AppArmor disabled by boot time parameter"); apparmor_enabled = 0; return 0; } + error = aa_alloc_root_ns(); if (error) { AA_ERROR("Unable to allocate default profile namespace\n"); diff --git a/security/security.c b/security/security.c index 5365bcb..144d467 100644 --- a/security/security.c +++ b/security/security.c @@ -33,6 +33,8 @@ #define SECURITY_NAME_MAX 10 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; @@ -64,10 +66,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; } @@ -135,6 +149,56 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, panic("%s - Cannot get early memory.\n", __func__); } +/** + * 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) +{ +#ifdef CONFIG_SECURITY_LSM_DEBUG + if (cred->security) + pr_info("%s: Inbound cred blob is not NULL.\n", __func__); +#endif + if (blob_sizes.lbs_cred == 0) + return 0; + + cred->security = kzalloc(blob_sizes.lbs_cred, gfp); + if (cred->security == NULL) + return -ENOMEM; + return 0; +} + +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. * @@ -937,16 +1001,29 @@ void security_task_free(struct task_struct *task) int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { + int rc = lsm_cred_alloc(cred, gfp); + + if (rc) + return rc; + return call_int_hook(cred_alloc_blank, 0, cred, gfp); } 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) { + int rc = lsm_cred_alloc(new, gfp); + + if (rc) + return rc; + return call_int_hook(cred_prepare, 0, new, old, gfp); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index fdc24ea..17f1f7b 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -178,12 +178,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; } /* @@ -193,7 +190,7 @@ static inline u32 cred_sid(const struct cred *cred) { const struct task_security_struct *tsec; - tsec = cred->security; + tsec = selinux_cred(cred); return tsec->sid; } @@ -215,7 +212,7 @@ static inline u32 task_sid(const struct task_struct *task) */ static inline u32 current_sid(void) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); return tsec->sid; } @@ -451,7 +448,7 @@ static int may_context_mount_sb_relabel(u32 sid, struct superblock_security_struct *sbsec, const struct cred *cred) { - const struct task_security_struct *tsec = cred->security; + const struct task_security_struct *tsec = selinux_cred(cred); int rc; rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, @@ -468,7 +465,7 @@ static int may_context_mount_inode_relabel(u32 sid, struct superblock_security_struct *sbsec, const struct cred *cred) { - const struct task_security_struct *tsec = cred->security; + const struct task_security_struct *tsec = selinux_cred(cred); int rc; rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, FILESYSTEM__RELABELFROM, NULL); @@ -1635,8 +1632,8 @@ static int task_has_perm(const struct task_struct *tsk1, u32 sid1, sid2; rcu_read_lock(); - __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid; - __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid; + __tsec1 = selinux_cred(__task_cred(tsk1)); sid1 = __tsec1->sid; + __tsec2 = selinux_cred(__task_cred(tsk2)); sid2 = __tsec2->sid; rcu_read_unlock(); return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); } @@ -1844,7 +1841,7 @@ static int may_create(struct inode *dir, struct dentry *dentry, u16 tclass) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); struct inode_security_struct *dsec; struct superblock_security_struct *sbsec; u32 sid, newsid; @@ -1865,7 +1862,7 @@ static int may_create(struct inode *dir, if (rc) return rc; - rc = selinux_determine_inode_label(current_security(), dir, + rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir, &dentry->d_name, tclass, &newsid); if (rc) return rc; @@ -2334,8 +2331,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) if (bprm->cred_prepared) return 0; - old_tsec = current_security(); - new_tsec = bprm->cred->security; + old_tsec = selinux_cred(current_cred()); + new_tsec = selinux_cred(bprm->cred); isec = inode_security(inode); /* Default to the current task SID. */ @@ -2425,7 +2422,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) static int selinux_bprm_secureexec(struct linux_binprm *bprm) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); u32 sid, osid; int atsecure = 0; @@ -2507,7 +2504,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) struct rlimit *rlim, *initrlim; int rc, i; - new_tsec = bprm->cred->security; + new_tsec = selinux_cred(bprm->cred); if (new_tsec->sid == new_tsec->osid) return; @@ -2549,7 +2546,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) */ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); struct itimerval itimer; u32 osid, sid; int rc, i; @@ -2849,7 +2846,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, u32 newsid; int rc; - rc = selinux_determine_inode_label(current_security(), + rc = selinux_determine_inode_label(selinux_cred(current_cred()), d_inode(dentry->d_parent), name, inode_mode_to_security_class(mode), &newsid); @@ -2868,14 +2865,14 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode, int rc; struct task_security_struct *tsec; - rc = selinux_determine_inode_label(old->security, + rc = selinux_determine_inode_label(selinux_cred(old), d_inode(dentry->d_parent), name, inode_mode_to_security_class(mode), &newsid); if (rc) return rc; - tsec = new->security; + tsec = selinux_cred(new); tsec->create_sid = newsid; return 0; } @@ -2885,7 +2882,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, const char **name, void **value, size_t *len) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); struct superblock_security_struct *sbsec; u32 sid, newsid, clen; int rc; @@ -2896,7 +2893,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - rc = selinux_determine_inode_label(current_security(), + rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir, qstr, inode_mode_to_security_class(inode->i_mode), &newsid); @@ -3342,7 +3339,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new) return -ENOMEM; } - tsec = new_creds->security; + tsec = selinux_cred(new_creds); /* Get label from overlay inode and set it in create_sid */ selinux_inode_getsecid(d_inode(src), &sid); tsec->create_sid = sid; @@ -3715,52 +3712,16 @@ static int selinux_task_create(unsigned long clone_flags) } /* - * 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 = cred->security; - - /* - * 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; + const struct task_security_struct *old_tsec = selinux_cred(old); + struct task_security_struct *tsec = selinux_cred(new); - old_tsec = old->security; - - tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); - if (!tsec) - return -ENOMEM; + *tsec = *old_tsec; - new->security = tsec; return 0; } @@ -3769,8 +3730,8 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, */ static void selinux_cred_transfer(struct cred *new, const struct cred *old) { - const struct task_security_struct *old_tsec = old->security; - struct task_security_struct *tsec = new->security; + const struct task_security_struct *old_tsec = selinux_cred(old); + struct task_security_struct *tsec = selinux_cred(new); *tsec = *old_tsec; } @@ -3781,7 +3742,7 @@ static void selinux_cred_transfer(struct cred *new, const struct cred *old) */ static int selinux_kernel_act_as(struct cred *new, u32 secid) { - struct task_security_struct *tsec = new->security; + struct task_security_struct *tsec = selinux_cred(new); u32 sid = current_sid(); int ret; @@ -3805,7 +3766,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid) static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) { struct inode_security_struct *isec = inode_security(inode); - struct task_security_struct *tsec = new->security; + struct task_security_struct *tsec = selinux_cred(new); u32 sid = current_sid(); int ret; @@ -4274,7 +4235,7 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) static int selinux_socket_create(int family, int type, int protocol, int kern) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); u32 newsid; u16 secclass; int rc; @@ -4293,7 +4254,7 @@ static int selinux_socket_create(int family, int type, static int selinux_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock)); struct sk_security_struct *sksec; u16 sclass = socket_type_to_security_class(family, type, protocol); @@ -4907,7 +4868,7 @@ static int selinux_secmark_relabel_packet(u32 sid) const struct task_security_struct *__tsec; u32 tsid; - __tsec = current_security(); + __tsec = selinux_cred(current_cred()); tsid = __tsec->sid; return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); @@ -5820,7 +5781,7 @@ static int selinux_getprocattr(struct task_struct *p, } rcu_read_lock(); - __tsec = __task_cred(p)->security; + __tsec = selinux_cred(__task_cred(p)); if (!strcmp(name, "current")) sid = __tsec->sid; @@ -5928,7 +5889,7 @@ static int selinux_setprocattr(struct task_struct *p, operation. See selinux_bprm_set_creds for the execve checks and may_create for the file creation checks. The operation will then fail if the context is not permitted. */ - tsec = new->security; + tsec = selinux_cred(new); if (!strcmp(name, "exec")) { tsec->exec_sid = sid; } else if (!strcmp(name, "fscreate")) { @@ -6050,7 +6011,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred, if (!ksec) return -ENOMEM; - tsec = cred->security; + tsec = selinux_cred(cred); if (tsec->keycreate_sid) ksec->sid = tsec->keycreate_sid; else @@ -6106,6 +6067,10 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) #endif +struct lsm_blob_sizes selinux_blob_sizes = { + .lbs_cred = sizeof(struct task_security_struct), +}; + static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), @@ -6189,8 +6154,6 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(file_open, selinux_file_open), LSM_HOOK_INIT(task_create, selinux_task_create), - 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(kernel_act_as, selinux_kernel_act_as), @@ -6324,11 +6287,19 @@ static struct security_hook_list selinux_hooks[] = { 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 e8dab0f..e968b32 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include #include "flask.h" #include "avc.h" @@ -130,5 +133,11 @@ struct key_security_struct { }; extern unsigned int selinux_checkreqprot; +extern struct lsm_blob_sizes selinux_blob_sizes; + +static inline struct task_security_struct *selinux_cred(const struct cred *cred) +{ + return cred->security; +} #endif /* _SELINUX_OBJSEC_H_ */ diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index cf9293e..40a7fad 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -30,6 +30,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. */ @@ -85,7 +86,7 @@ static int task_has_security(struct task_struct *tsk, u32 sid = 0; rcu_read_lock(); - tsec = __task_cred(tsk)->security; + tsec = selinux_cred(__task_cred(tsk)); if (tsec) sid = tsec->sid; rcu_read_unlock(); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 56e354f..789d07b 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -79,7 +79,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, gfp_t gfp) { int rc; - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); struct xfrm_sec_ctx *ctx = NULL; u32 str_len; @@ -136,7 +136,7 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx) */ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) { - const struct task_security_struct *tsec = current_security(); + const struct task_security_struct *tsec = selinux_cred(current_cred()); if (!ctx) return 0; diff --git a/security/smack/smack.h b/security/smack/smack.h index 77abe2e..5df15dd 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 @@ -352,6 +353,11 @@ extern struct list_head smack_onlycap_list; #define SMACK_HASH_SLOTS 16 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; +static inline struct task_smack *smack_cred(const struct cred *cred) +{ + return cred->security; +} + /* * Is the directory transmuting? */ @@ -378,13 +384,16 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp) return tsp->smk_task; } -static inline struct smack_known *smk_of_task_struct(const struct task_struct *t) +static inline struct smack_known *smk_of_task_struct( + const struct task_struct *t) { struct smack_known *skp; + const struct cred *cred; rcu_read_lock(); - skp = smk_of_task(__task_cred(t)->security); + cred = __task_cred(t); rcu_read_unlock(); + skp = smk_of_task(smack_cred(cred)); return skp; } @@ -401,7 +410,7 @@ static inline struct smack_known *smk_of_forked(const struct task_smack *tsp) */ static inline struct smack_known *smk_of_current(void) { - return smk_of_task(current_security()); + return smk_of_task(smack_cred(current_cred())); } /* diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 356e376..204dddb 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -275,7 +275,7 @@ int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known, int smk_curacc(struct smack_known *obj_known, u32 mode, struct smk_audit_info *a) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_tskacc(tsp, obj_known, mode, a); } diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 839150e..57fb7bb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -120,7 +120,7 @@ static int smk_bu_note(char *note, struct smack_known *sskp, static int smk_bu_current(char *note, struct smack_known *oskp, int mode, int rc) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); char acc[SMK_NUM_ACCESS_TYPE + 1]; if (rc <= 0) @@ -141,7 +141,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp, #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_task(struct task_struct *otp, int mode, int rc) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); struct smack_known *smk_task = smk_of_task_struct(otp); char acc[SMK_NUM_ACCESS_TYPE + 1]; @@ -163,7 +163,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc) #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_inode(struct inode *inode, int mode, int rc) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); struct inode_smack *isp = inode->i_security; char acc[SMK_NUM_ACCESS_TYPE + 1]; @@ -193,7 +193,7 @@ static int smk_bu_inode(struct inode *inode, int mode, int rc) #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_file(struct file *file, int mode, int rc) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); struct smack_known *sskp = tsp->smk_task; struct inode *inode = file_inode(file); struct inode_smack *isp = inode->i_security; @@ -223,7 +223,7 @@ static int smk_bu_file(struct file *file, int mode, int rc) static int smk_bu_credfile(const struct cred *cred, struct file *file, int mode, int rc) { - struct task_smack *tsp = cred->security; + struct task_smack *tsp = smack_cred(cred); struct smack_known *sskp = tsp->smk_task; struct inode *inode = file_inode(file); struct inode_smack *isp = inode->i_security; @@ -307,29 +307,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; } /** @@ -431,7 +422,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer, } rcu_read_lock(); - tsp = __task_cred(tracer)->security; + tsp = smack_cred(__task_cred(tracer)); tracer_known = smk_of_task(tsp); if ((mode & PTRACE_MODE_ATTACH) && @@ -498,7 +489,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp) int rc; struct smack_known *skp; - skp = smk_of_task(current_security()); + skp = smk_of_task(smack_cred(current_cred())); rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); return rc; @@ -917,7 +908,7 @@ static int smack_sb_statfs(struct dentry *dentry) static int smack_bprm_set_creds(struct linux_binprm *bprm) { struct inode *inode = file_inode(bprm->file); - struct task_smack *bsp = bprm->cred->security; + struct task_smack *bsp = smack_cred(bprm->cred); struct inode_smack *isp; struct superblock_smack *sbsp; int rc; @@ -966,7 +957,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm) */ static void smack_bprm_committing_creds(struct linux_binprm *bprm) { - struct task_smack *bsp = bprm->cred->security; + struct task_smack *bsp = smack_cred(bprm->cred); if (bsp->smk_task != bsp->smk_forked) current->pdeath_signal = 0; @@ -980,7 +971,7 @@ static void smack_bprm_committing_creds(struct linux_binprm *bprm) */ static int smack_bprm_secureexec(struct linux_binprm *bprm) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); if (tsp->smk_task != tsp->smk_forked) return 1; @@ -1743,7 +1734,7 @@ static int smack_mmap_file(struct file *file, return -EACCES; mkp = isp->smk_mmap; - tsp = current_security(); + tsp = smack_cred(current_cred()); skp = smk_of_current(); rc = 0; @@ -1839,7 +1830,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { struct smack_known *skp; - struct smack_known *tkp = smk_of_task(tsk->cred->security); + struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred)); struct file *file; int rc; struct smk_audit_info ad; @@ -1887,7 +1878,7 @@ static int smack_file_receive(struct file *file) if (S_ISSOCK(inode->i_mode)) { sock = SOCKET_I(inode); ssp = sock->sk->sk_security; - tsp = current_security(); + tsp = smack_cred(current_cred()); /* * If the receiving process can't write to the * passed socket or if the passed socket can't @@ -1929,7 +1920,7 @@ static int smack_file_receive(struct file *file) */ static int smack_file_open(struct file *file, const struct cred *cred) { - struct task_smack *tsp = cred->security; + struct task_smack *tsp = smack_cred(cred); struct inode *inode = file_inode(file); struct smk_audit_info ad; int rc; @@ -1960,14 +1951,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; } @@ -1979,15 +1963,11 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) */ static void smack_cred_free(struct cred *cred) { - struct task_smack *tsp = cred->security; + struct task_smack *tsp = smack_cred(cred); struct smack_rule *rp; 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) { @@ -1995,7 +1975,6 @@ static void smack_cred_free(struct cred *cred) list_del(&rp->list); kfree(rp); } - kfree(tsp); } /** @@ -2009,15 +1988,11 @@ static void smack_cred_free(struct cred *cred) static int smack_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - struct task_smack *old_tsp = old->security; - struct task_smack *new_tsp; + struct task_smack *old_tsp = smack_cred(old); + 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) @@ -2025,10 +2000,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; } /** @@ -2040,15 +2012,14 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old, */ static void smack_cred_transfer(struct cred *new, const struct cred *old) { - struct task_smack *old_tsp = old->security; - struct task_smack *new_tsp = new->security; + struct task_smack *old_tsp = smack_cred(old); + struct task_smack *new_tsp = smack_cred(new); new_tsp->smk_task = old_tsp->smk_task; new_tsp->smk_forked = old_tsp->smk_task; mutex_init(&new_tsp->smk_rules_lock); INIT_LIST_HEAD(&new_tsp->smk_rules); - /* cbs copy rule list */ } @@ -2061,7 +2032,7 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old) */ static int smack_kernel_act_as(struct cred *new, u32 secid) { - struct task_smack *new_tsp = new->security; + struct task_smack *new_tsp = smack_cred(new); new_tsp->smk_task = smack_from_secid(secid); return 0; @@ -2079,7 +2050,7 @@ static int smack_kernel_create_files_as(struct cred *new, struct inode *inode) { struct inode_smack *isp = inode->i_security; - struct task_smack *tsp = new->security; + struct task_smack *tsp = smack_cred(new); tsp->smk_forked = isp->smk_inode; tsp->smk_task = tsp->smk_forked; @@ -3630,10 +3601,10 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value) * * Returns the length of the smack label or an error code */ -static int smack_setprocattr(struct task_struct *p, char *name, - void *value, size_t size) +static int smack_setprocattr(struct task_struct *p, char *name, void *value, + size_t size) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); struct cred *new; struct smack_known *skp; struct smack_known_list_elem *sklep; @@ -3681,7 +3652,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, if (new == NULL) return -ENOMEM; - tsp = new->security; + tsp = smack_cred(new); tsp->smk_task = skp; /* * process can change its label only once @@ -4317,7 +4288,7 @@ static void smack_inet_csk_clone(struct sock *sk, static int smack_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { - struct smack_known *skp = smk_of_task(cred->security); + struct smack_known *skp = smk_of_task(smack_cred(cred)); key->security = skp; return 0; @@ -4348,7 +4319,7 @@ static int smack_key_permission(key_ref_t key_ref, { struct key *keyp; struct smk_audit_info ad; - struct smack_known *tkp = smk_of_task(cred->security); + struct smack_known *tkp = smk_of_task(smack_cred(cred)); int request = 0; int rc; @@ -4601,6 +4572,10 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) return 0; } +struct lsm_blob_sizes smack_blob_sizes = { + .lbs_cred = sizeof(struct task_smack), +}; + static struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), @@ -4777,23 +4752,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"); @@ -4807,20 +4794,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/smack/smackfs.c b/security/smack/smackfs.c index 13743a0..059c91f 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -2203,14 +2203,14 @@ static const struct file_operations smk_logging_ops = { static void *load_self_seq_start(struct seq_file *s, loff_t *pos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_seq_start(s, pos, &tsp->smk_rules); } static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_seq_next(s, v, pos, &tsp->smk_rules); } @@ -2257,7 +2257,7 @@ static int smk_open_load_self(struct inode *inode, struct file *file) static ssize_t smk_write_load_self(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, &tsp->smk_rules_lock, SMK_FIXED24_FMT); @@ -2409,14 +2409,14 @@ static const struct file_operations smk_load2_ops = { static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_seq_start(s, pos, &tsp->smk_rules); } static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_seq_next(s, v, pos, &tsp->smk_rules); } @@ -2462,7 +2462,7 @@ static int smk_open_load_self2(struct inode *inode, struct file *file) static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, &tsp->smk_rules_lock, SMK_LONG_FMT); @@ -2676,14 +2676,14 @@ static const struct file_operations smk_syslog_ops = { static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_seq_start(s, pos, &tsp->smk_relabel); } static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); return smk_seq_next(s, v, pos, &tsp->smk_relabel); } @@ -2731,7 +2731,7 @@ static int smk_open_relabel_self(struct inode *inode, struct file *file) static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct task_smack *tsp = current_security(); + struct task_smack *tsp = smack_cred(current_cred()); char *data; int rc; LIST_HEAD(list_tmp); diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 361e7a2..cbcfccc 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1196,13 +1197,26 @@ static inline void tomoyo_put_group(struct tomoyo_group *group) } /** + * 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. * * Returns pointer to "struct tomoyo_domain_info" for current thread. */ static inline struct tomoyo_domain_info *tomoyo_domain(void) { - return current_cred()->security; + struct tomoyo_domain_info **blob = tomoyo_cred(current_cred()); + + return *blob; } /** @@ -1215,7 +1229,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 838ffa7..0440f44 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -675,6 +675,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; @@ -840,7 +841,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 06ab41b1..9289f2a 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -70,9 +70,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); @@ -233,10 +236,12 @@ 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; + 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 edc52d6..61285fe 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -17,7 +17,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; } @@ -33,8 +35,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; @@ -58,7 +65,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); } @@ -72,6 +81,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. @@ -92,13 +104,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; } @@ -111,8 +124,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. @@ -492,6 +508,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. @@ -537,14 +557,25 @@ 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")) return 0; + + 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; }