From patchwork Thu Mar 8 01:52:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Casey Schaufler X-Patchwork-Id: 10265805 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 2D06D602C8 for ; Thu, 8 Mar 2018 01:52:59 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D175290AB for ; Thu, 8 Mar 2018 01:52:59 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1197E2910E; Thu, 8 Mar 2018 01:52: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=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 087E9290AB for ; Thu, 8 Mar 2018 01:52:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934612AbeCHBw5 (ORCPT ); Wed, 7 Mar 2018 20:52:57 -0500 Received: from sonic313-18.consmr.mail.ne1.yahoo.com ([66.163.185.41]:35959 "EHLO sonic313-18.consmr.mail.ne1.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933351AbeCHBw4 (ORCPT ); Wed, 7 Mar 2018 20:52:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1520473976; bh=UtfzPVuvAnIOBxh+zMyaLckdwSu0DiFALqMiO/9ZNSs=; h=Subject:To:Cc:References:From:Date:In-Reply-To:From:Subject; b=Jzo8yBs1unj1bo1FYFdyelJYW71ps/zxN/de42ouobBTuaSPiq5KzJ8+O1Xa2xONxr+R24/a5ktSarpwWxCJzMiGdvsxPipEM5E6KT0tHidAyOVeGRHtrb0oUqOQ9IIiUXs0yuLBPV3geD53HSHHxFKRG1H98ZPcvTqKZ9VvNdL7OI2gy4eEvGQ7mfswR8eH1vQJQgUzMVfS6joetypwFxjiabxv/fLsbzCbBTpbwwhOk9kozV/jTEvuAtgiLBWf7vSSFz2EVz9fvyf1V90+9S6H0FoU1i2NGUxZ9QdZPw0EWJ/i1oanbHHQXuvUkK2U/bHohjr7Crpm/ap8PMqXTA== X-YMail-OSG: pk_U6aUVM1neyHDpOwW61m5movlMwb4piMpjGe9J.jFQWuSOf0f_VJ.Y9v1jQIO mbax2G1wOxps_8svbkmubdsS6o1IayrDngUW.wv02EjJ21K.p8x1zq1nC5rX3vqjT5agcRJUwhfM 9rDuUI8OTZX5yIHo1hu5ZDIvmwBYH2kETcMige82z_j2Q0sckmMYl9q1ohjiTfsqrnUBe8wDmg8v qPsBIQ2fIc7dMmwqwQUTPQV1LfcV.k1YNJkk7Pj7C.VkefaPApM4_5SHzwtSaAKha8DbhMd3NmaR w_jrh9uFji3RUZXQxoyvotoCg8i_XdHZgTH2Gi8sRQk3_UPvks5in.QJZDZIo3hQsaa6_ohmADOT XnkfHOoNod1HAYkVU8rHiPg3WYXdEO5MzlLD8h7MytrPyLJPS.iHp8Koa03q_jHz9IMgSu7wrzoQ LYcfJaQyLnxB.wOINb5dgV0xdUTXr4LLVyc2MAPhlSX4JvbhLK9ohup1CP0nHZiIDImNgU3dpdis n8QEMYd7.g4CiHPvvOs0RMt.JFkGMY.7GD023_ab2mBjTa67fCLO9INhsapsSgfkN Received: from sonic.gate.mail.ne1.yahoo.com by sonic313.consmr.mail.ne1.yahoo.com with HTTP; Thu, 8 Mar 2018 01:52:56 +0000 Received: from smtp226.mail.ne1.yahoo.com (EHLO [192.168.0.104]) ([10.218.253.215]) by smtp403.mail.ne1.yahoo.com (JAMES SMTP Server ) with ESMTPA ID f8306414dd1ccdafa28dfd4e6f8032b9; Thu, 08 Mar 2018 01:52:55 +0000 (UTC) Subject: [PATCH 3/8] LSM: Manage file security blobs To: LSM , James Morris Cc: John Johansen , Tetsuo Handa , Paul Moore , Kees Cook , Stephen Smalley , SE Linux , SMACK-announce@lists.01.org, Casey Schaufler References: From: Casey Schaufler Message-ID: <25eaf580-7fee-c11a-eb26-afed825111f9@schaufler-ca.com> Date: Wed, 7 Mar 2018 17:52:53 -0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.6.0 MIME-Version: 1.0 In-Reply-To: Content-Language: en-US Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH 3/8] 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 management 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 | 5 ++++ security/apparmor/include/file.h | 2 +- security/apparmor/lsm.c | 19 ++++++------- security/security.c | 54 ++++++++++++++++++++++++++++++++++--- security/selinux/hooks.c | 41 +++++++--------------------- security/selinux/include/objsec.h | 5 ++++ security/smack/smack.h | 5 ++++ security/smack/smack_lsm.c | 26 +++++++----------- 9 files changed, 97 insertions(+), 61 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index bb36a9ead1fe..417a8946201a 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1974,6 +1974,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 301ab3a0dd04..c6e106a533e8 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -87,6 +87,11 @@ static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred) return aa_get_newest_label(aa_cred_raw_label(cred)); } +static inline struct aa_file_ctx *apparmor_file(const struct file *file) +{ + return file->f_security; +} + /** * __aa_task_raw_label - retrieve another task's label * @task: task to query (NOT NULL) diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 4c2c8ac8842f..b9efe6bc226b 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -32,7 +32,7 @@ struct path; AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \ AA_EXEC_MMAP | AA_MAY_LINK) -#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security) +#define file_ctx(X) apparmor_file(X) /* struct aa_file_ctx - the AppArmor context the file was opened in * @lock: lock to update the ctx diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 6058ce595037..03c7cbce4853 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -401,21 +401,21 @@ static int apparmor_file_open(struct file *file, const struct cred *cred) static int apparmor_file_alloc_security(struct file *file) { - int error = 0; - - /* freed by apparmor_file_free_security */ + struct aa_file_ctx *ctx = file_ctx(file); struct aa_label *label = begin_current_label_crit_section(); - file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL); - if (!file_ctx(file)) - error = -ENOMEM; - end_current_label_crit_section(label); - return error; + spin_lock_init(&ctx->lock); + rcu_assign_pointer(ctx->label, aa_get_label(label)); + end_current_label_crit_section(label); + return 0; } static void apparmor_file_free_security(struct file *file) { - aa_free_file_ctx(file_ctx(file)); + struct aa_file_ctx *ctx = file_ctx(file); + + if (ctx) + aa_put_label(rcu_access_pointer(ctx->label)); } static int common_file_perm(const char *op, struct file *file, u32 mask) @@ -722,6 +722,7 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, struct lsm_blob_sizes apparmor_blob_sizes = { .lbs_cred = sizeof(struct aa_task_ctx), + .lbs_file = sizeof(struct aa_file_ctx), }; static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { diff --git a/security/security.c b/security/security.c index c471019e2a7e..90d09d8542d4 100644 --- a/security/security.c +++ b/security/security.c @@ -38,6 +38,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init; static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); +static struct kmem_cache *lsm_file_cache; + char *lsm_names; static struct lsm_blob_sizes blob_sizes; @@ -83,6 +85,13 @@ int __init security_init(void) */ do_security_initcalls(); + /* + * Create any kmem_caches needed for blobs + */ + if (blob_sizes.lbs_file) + lsm_file_cache = kmem_cache_create("lsm_file_cache", + blob_sizes.lbs_file, 0, + SLAB_PANIC, NULL); /* * The second call to a module specific init function * adds hooks to the hook lists and does any other early @@ -92,6 +101,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; @@ -266,6 +276,28 @@ 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) +{ + if (!lsm_file_cache) { + file->f_security = NULL; + return 0; + } + + file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL); + if (file->f_security == NULL) + return -ENOMEM; + return 0; } /* @@ -951,12 +983,28 @@ int security_file_permission(struct file *file, int mask) int security_file_alloc(struct file *file) { - return call_int_hook(file_alloc_security, 0, file); + int rc = lsm_file_alloc(file); + + if (rc) + return rc; + rc = call_int_hook(file_alloc_security, 0, file); + if (unlikely(rc)) + security_file_free(file); + return rc; } void security_file_free(struct file *file) { + void *blob; + + if (!lsm_file_cache) + return; + call_void_hook(file_free_security, file); + + blob = file->f_security; + file->f_security = NULL; + kmem_cache_free(lsm_file_cache, blob); } int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -1074,7 +1122,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) return rc; rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); - if (rc) + if (unlikely(rc)) security_cred_free(cred); return rc; } @@ -1095,7 +1143,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) return rc; rc = call_int_hook(cred_prepare, 0, new, old, gfp); - if (rc) + if (unlikely(rc)) security_cred_free(new); return rc; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index aee16f5b6e1e..ed01d18d0924 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -130,7 +130,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 @@ -360,27 +359,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; @@ -1828,7 +1815,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); @@ -2154,7 +2141,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; @@ -3429,7 +3416,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(); @@ -3451,11 +3438,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. @@ -3464,7 +3446,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; @@ -3710,7 +3692,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(); } @@ -3725,7 +3707,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 */ @@ -3748,7 +3730,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 @@ -3878,7 +3860,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) @@ -6359,6 +6341,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) 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[] __lsm_ro_after_init = { @@ -6429,7 +6412,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), - LSM_HOOK_INIT(file_free_security, selinux_file_free_security), LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), LSM_HOOK_INIT(mmap_file, selinux_mmap_file), LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr), @@ -6620,9 +6602,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 e57010b2ea1f..8117051eef41 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -165,4 +165,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 0c6dce446825..043525a52e94 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -362,6 +362,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 a992c0a04795..1bffbab2e765 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1570,24 +1570,12 @@ 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 @@ -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)) @@ -4655,6 +4647,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, 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[] __lsm_ro_after_init = { @@ -4692,7 +4685,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), - LSM_HOOK_INIT(file_free_security, smack_file_free_security), LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), LSM_HOOK_INIT(file_lock, smack_file_lock), LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),