From patchwork Thu Jan 26 02:07:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Casey Schaufler X-Patchwork-Id: 9538307 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 0FF8D604A7 for ; Thu, 26 Jan 2017 02:07:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D9F4927C0C for ; Thu, 26 Jan 2017 02:07:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CED8727F85; Thu, 26 Jan 2017 02:07:32 +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.3 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM, 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 DFB1027F07 for ; Thu, 26 Jan 2017 02:07:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752478AbdAZCHb (ORCPT ); Wed, 25 Jan 2017 21:07:31 -0500 Received: from nm27-vm3.bullet.mail.ne1.yahoo.com ([98.138.91.157]:55980 "EHLO nm27-vm3.bullet.mail.ne1.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752299AbdAZCHa (ORCPT ); Wed, 25 Jan 2017 21:07:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1485396449; bh=pzIbtTbSWwE3kCYlamVNwAkJ8vPhzl63i4Ff0+6Zphc=; h=Subject:To:References:Cc:From:Date:In-Reply-To:From:Subject; b=qt5tc7cPDJS2k6fNPkTSWwQqm1ca0KHie09HL1D0VMqkIgZL2wb0CZrSebn5WUp2R0ZuXv+yru0/bEoRC1xMbZc+rcFr/FLlDSYKYeUEKVpg1OCR7wILI13kBMjpOT7W2P8aZRXVpPzblCbeTNQQI+684HSrqAJVVnLi0qiO35punDlalcBX2z5EJ1P4Jyb/9yW2wzMQ2o+KoKObWaPPhqNZ7Tax3bmcroANJ6Yf/6KTKg9qVh8fWMzpewcr2WB4Fm0u1T/sgtmF7jCOAw12b5SSZU0LuD27mi01ygrw89+L08JduTRFcc2IOy334McxzvG2+p7KvYYrmQE80fufpA== Received: from [98.138.100.113] by nm27.bullet.mail.ne1.yahoo.com with NNFMP; 26 Jan 2017 02:07:29 -0000 Received: from [98.138.84.45] by tm104.bullet.mail.ne1.yahoo.com with NNFMP; 26 Jan 2017 02:07:29 -0000 Received: from [127.0.0.1] by smtp113.mail.ne1.yahoo.com with NNFMP; 26 Jan 2017 02:07:29 -0000 X-Yahoo-Newman-Id: 612871.29437.bm@smtp113.mail.ne1.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: 5hc9S1YVM1l481bVZGHp8ajYne5erOEj4xRjK6J6dB4TTyD u_ymoi4l7pZB2LP9VGNdGgSpB0LyIqU17XhLznXfjj284Fz_bh6nEIwOhf9m BhbCyhS0Xyjrf4uktN92AzxeDCq1fRQcblw1iu1s_EEPElVMLD0c8Mauj3Qn 4XXSXQJq8wM5RJZWFiyJeSxNTF6KmHHUWrl2erp_j8Ze_JpKUsT6d2eeq4nE rXF3t3fnGCC0WLdzUbl9CXTtseFHligxlTNjETA6R39YegF4IYPTdBJkBXH6 cy2remloNheZLXohkalnxaZ2RxaljhnL2YHgGhtSQj30HiCcYJFAdhGVkZMR aFoRy_s.kuR3KJRCgvHkgKHisiefiEXx8oaNGk3xqj_7xlm7jJKUDft1a_HM gmkVzcvnpbsNguEBc8NkuFIBcSVMAgL96oTiQ8B0i70aKJUbdJqPvD5Ehb8f OGg9mEhBB8JY_pLhTLBaX283hPGkrUNUYpud5aUt7wCl_fLD9tRFNtUBAi6p 1LVCr99aHysCWB_If3Le_MpzBJb_z5Jl_c7ca2RCiVrgcl0ufkhk0SFHMEus .UT3iqmldqT8D X-Yahoo-SMTP: OIJXglSswBDfgLtXluJ6wiAYv6_cnw-- Subject: [PATCH RFC 4/9] LSM: Manage file security blobs To: LSM References: Cc: James Morris , John Johansen , Tetsuo Handa , Paul Moore , Stephen Smalley , Kees Cook From: Casey Schaufler Message-ID: <3d820eac-0b6c-5f24-4c1e-f2c80a609747@schaufler-ca.com> Date: Wed, 25 Jan 2017 18:07:28 -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 4/9] LSM: Manage file security blobs Move the management of file security blobs from the individual security modules to the security infrastructure. The security modules using file blobs have been updated accordingly. Modules are required to identify the space they need at module initialization. In some cases a module no longer needs to supply a blob managment hook, in which case the hook has been removed. Signed-off-by: Casey Schaufler --- include/linux/lsm_hooks.h | 1 + security/apparmor/include/context.h | 6 ++++++ security/apparmor/lsm.c | 26 ++++------------------- security/security.c | 32 +++++++++++++++++++++++++++++ security/selinux/hooks.c | 41 +++++++++---------------------------- security/selinux/include/objsec.h | 5 +++++ security/smack/smack.h | 5 +++++ security/smack/smack_lsm.c | 26 ++++++++--------------- 8 files changed, 72 insertions(+), 70 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index f26a5b4..c1807a2 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1884,6 +1884,7 @@ struct security_hook_list { */ struct lsm_blob_sizes { int lbs_cred; + int lbs_file; }; /* diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 07fb7a1..c140aad 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -24,6 +24,7 @@ #define cred_cxt(X) apparmor_cred(X) #define current_cxt() cred_cxt(current_cred()) +#define file_cxt(X) apparmor_file(X) /* struct aa_file_cxt - the AppArmor context the file was opened in * @perms: the permission the file was opened with @@ -91,6 +92,11 @@ static inline struct aa_task_cxt *apparmor_cred(const struct cred *cred) return cred->security; } +static inline struct aa_file_cxt *apparmor_file(const struct file *file) +{ + return file->f_security; +} + /** * aa_cred_profile - obtain cred's profiles * @cred: cred to obtain profiles from (NOT NULL) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8e25455..ed8f1e4 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -321,7 +321,7 @@ static int apparmor_inode_getattr(const struct path *path) static int apparmor_file_open(struct file *file, const struct cred *cred) { - struct aa_file_cxt *fcxt = file->f_security; + struct aa_file_cxt *fcxt = file_cxt(file); struct aa_profile *profile; int error = 0; @@ -352,26 +352,9 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) return error; } -static int apparmor_file_alloc_security(struct file *file) -{ - /* freed by apparmor_file_free_security */ - file->f_security = aa_alloc_file_context(GFP_KERNEL); - if (!file->f_security) - return -ENOMEM; - return 0; - -} - -static void apparmor_file_free_security(struct file *file) -{ - struct aa_file_cxt *cxt = file->f_security; - - aa_free_file_context(cxt); -} - static int common_file_perm(int op, struct file *file, u32 mask) { - struct aa_file_cxt *fcxt = file->f_security; + struct aa_file_cxt *fcxt = file_cxt(file); struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred); int error = 0; @@ -417,7 +400,7 @@ static int common_mmap(int op, struct file *file, unsigned long prot, { int mask = 0; - if (!file || !file->f_security) + if (!file || file_cxt(file) == NULL) return 0; if (prot & PROT_READ) @@ -565,6 +548,7 @@ static int apparmor_task_setrlimit(struct task_struct *task, struct lsm_blob_sizes apparmor_blob_sizes = { .lbs_cred = sizeof(struct aa_task_cxt), + .lbs_file = sizeof(struct aa_file_cxt), }; static struct security_hook_list apparmor_hooks[] = { @@ -587,8 +571,6 @@ static struct security_hook_list apparmor_hooks[] = { LSM_HOOK_INIT(file_open, apparmor_file_open), LSM_HOOK_INIT(file_permission, apparmor_file_permission), - LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security), - LSM_HOOK_INIT(file_free_security, apparmor_file_free_security), LSM_HOOK_INIT(mmap_file, apparmor_mmap_file), LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect), LSM_HOOK_INIT(file_lock, apparmor_file_lock), diff --git a/security/security.c b/security/security.c index 144d467..0aee0f4 100644 --- a/security/security.c +++ b/security/security.c @@ -80,6 +80,7 @@ int __init security_init(void) #ifdef CONFIG_SECURITY_LSM_DEBUG pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred); + pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file); #endif return 0; @@ -197,6 +198,30 @@ static void __init lsm_set_size(int *need, int *lbs) void __init security_add_blobs(struct lsm_blob_sizes *needed) { lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred); + lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file); +} + +/** + * 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. + */ +int lsm_file_alloc(struct file *file) +{ +#ifdef CONFIG_SECURITY_LSM_DEBUG + if (file->f_security) + pr_info("%s: Inbound file blob is not NULL.\n", __func__); +#endif + if (blob_sizes.lbs_file == 0) + return 0; + + file->f_security = kzalloc(blob_sizes.lbs_file, GFP_KERNEL); + if (file->f_security == NULL) + return -ENOMEM; + return 0; } /* @@ -884,12 +909,19 @@ int security_file_permission(struct file *file, int mask) int security_file_alloc(struct file *file) { + int rc = lsm_file_alloc(file); + + if (rc) + return rc; return call_int_hook(file_alloc_security, 0, file); } void security_file_free(struct file *file) { call_void_hook(file_free_security, file); + + kfree(file->f_security); + file->f_security = NULL; } int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 17f1f7b..546956a 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -126,7 +126,6 @@ int selinux_enabled = 1; #endif 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 @@ -356,27 +355,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 = file->f_security; - 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; @@ -1783,7 +1770,7 @@ static int file_has_perm(const struct cred *cred, struct file *file, u32 av) { - struct file_security_struct *fsec = file->f_security; + struct file_security_struct *fsec = selinux_file(file); struct inode *inode = file_inode(file); struct common_audit_data ad; u32 sid = cred_sid(cred); @@ -2111,7 +2098,7 @@ static int selinux_binder_transfer_file(struct task_struct *from, struct file *file) { u32 sid = task_sid(to); - struct file_security_struct *fsec = file->f_security; + struct file_security_struct *fsec = selinux_file(file); struct dentry *dentry = file->f_path.dentry; struct inode_security_struct *isec; struct common_audit_data ad; @@ -3380,7 +3367,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask) static int selinux_file_permission(struct file *file, int mask) { struct inode *inode = file_inode(file); - struct file_security_struct *fsec = file->f_security; + struct file_security_struct *fsec = selinux_file(file); struct inode_security_struct *isec; u32 sid = current_sid(); @@ -3402,11 +3389,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. @@ -3415,7 +3397,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, u32 requested, u16 cmd) { struct common_audit_data ad; - struct file_security_struct *fsec = file->f_security; + struct file_security_struct *fsec = selinux_file(file); struct inode *inode = file_inode(file); struct inode_security_struct *isec; struct lsm_ioctlop_audit ioctl; @@ -3644,7 +3626,7 @@ static void selinux_file_set_fowner(struct file *file) { struct file_security_struct *fsec; - fsec = file->f_security; + fsec = selinux_file(file); fsec->fown_sid = current_sid(); } @@ -3659,7 +3641,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, /* struct fown_struct is never outside the context of a struct file */ file = container_of(fown, struct file, f_owner); - fsec = file->f_security; + fsec = selinux_file(file); if (!signum) perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ @@ -3682,7 +3664,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred) struct file_security_struct *fsec; struct inode_security_struct *isec; - fsec = file->f_security; + fsec = selinux_file(file); isec = inode_security(file_inode(file)); /* * Save inode label and policy sequence number @@ -3812,7 +3794,7 @@ static int selinux_kernel_module_from_file(struct file *file) ad.type = LSM_AUDIT_DATA_FILE; ad.u.file = file; - fsec = file->f_security; + fsec = selinux_file(file); if (sid != fsec->sid) { rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); if (rc) @@ -6069,6 +6051,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) struct lsm_blob_sizes selinux_blob_sizes = { .lbs_cred = sizeof(struct task_security_struct), + .lbs_file = sizeof(struct file_security_struct), }; static struct security_hook_list selinux_hooks[] = { @@ -6140,7 +6123,6 @@ static struct security_hook_list selinux_hooks[] = { 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), @@ -6315,9 +6297,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(); security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index e968b32..d02c1f8 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -140,4 +140,9 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred) return cred->security; } +static inline struct file_security_struct *selinux_file(const struct file *file) +{ + return file->f_security; +} + #endif /* _SELINUX_OBJSEC_H_ */ diff --git a/security/smack/smack.h b/security/smack/smack.h index 5df15dd..bb0d24b 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -358,6 +358,11 @@ static inline struct task_smack *smack_cred(const struct cred *cred) return cred->security; } +static inline struct smack_known **smack_file(const struct file *file) +{ + return file->f_security; +} + /* * Is the directory transmuting? */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 57fb7bb..d0b48de 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1582,25 +1582,13 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid) */ static int smack_file_alloc_security(struct file *file) { - struct smack_known *skp = smk_of_current(); + struct smack_known **blob = smack_file(file); - file->f_security = skp; + *blob = smk_of_current(); 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 * @cmd: what to do @@ -1812,7 +1800,9 @@ static int smack_mmap_file(struct file *file, */ static void smack_file_set_fowner(struct file *file) { - file->f_security = smk_of_current(); + struct smack_known **blob = smack_file(file); + + *blob = smk_of_current(); } /** @@ -1829,6 +1819,7 @@ static void smack_file_set_fowner(struct file *file) static int smack_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { + struct smack_known **blob; struct smack_known *skp; struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred)); struct file *file; @@ -1841,7 +1832,8 @@ static int smack_file_send_sigiotask(struct task_struct *tsk, file = container_of(fown, struct file, f_owner); /* we don't log here as rc can be overriden */ - skp = file->f_security; + blob = smack_file(file); + skp = *blob; rc = smk_access(skp, tkp, MAY_DELIVER, NULL); rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc); if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE)) @@ -4574,6 +4566,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) struct lsm_blob_sizes smack_blob_sizes = { .lbs_cred = sizeof(struct task_smack), + .lbs_file = sizeof(struct smack_known *), }; static struct security_hook_list smack_hooks[] = { @@ -4613,7 +4606,6 @@ static struct security_hook_list smack_hooks[] = { 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),