From patchwork Thu Aug 20 18:19:57 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Andreas_Gr=C3=BCnbacher?= X-Patchwork-Id: 7046501 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id BC0869F358 for ; Thu, 20 Aug 2015 18:25:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 95C18205C1 for ; Thu, 20 Aug 2015 18:25:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 63EF02044C for ; Thu, 20 Aug 2015 18:25:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751509AbbHTSZA (ORCPT ); Thu, 20 Aug 2015 14:25:00 -0400 Received: from mail-wi0-f177.google.com ([209.85.212.177]:34282 "EHLO mail-wi0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751304AbbHTSZA (ORCPT ); Thu, 20 Aug 2015 14:25:00 -0400 Received: by wicne3 with SMTP id ne3so533132wic.1; Thu, 20 Aug 2015 11:24:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Qwtgpj/u6dKrn+oqdtdRCuqXlBvqQUV3y46mu/Ex5pc=; b=TOuXsk4BEGXus0w4lGTLKQp9804V3TyOFOgb8qFhIqHf/fTxnKWamUdL6+4qCGTb2k kzisa85rlyF1upNIVYnCT+rvXM0sfLpyTOWrNvvEDHwyJS7R68fy18sTKlhSG1YrtT8M XOpwL6N3uW85WsvCpGs01hrk6MWBy4+B7B8ruRhjOoYjVkAZtXgfvmV2OqqVFEEO+q7z wSzqHkImsPVF3LTPepM8PSSJ58xj+GduiE/IlIybEmpi0POajLdT6iRJQx6tQnRPui7e xGWkhe/5Ee32LmkgDF5SOBeincykF5qt6RptUCMyxdXJNOhCTusltQ5GRDkc/hn0Sl7T Aocg== X-Received: by 10.194.58.236 with SMTP id u12mr8935250wjq.36.1440095098663; Thu, 20 Aug 2015 11:24:58 -0700 (PDT) Received: from nuc.home.com (p549817FE.dip0.t-ipconnect.de. [84.152.23.254]) by smtp.gmail.com with ESMTPSA id ma4sm6598334wjb.38.2015.08.20.11.24.54 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 20 Aug 2015 11:24:58 -0700 (PDT) From: Andreas Gruenbacher X-Google-Original-From: Andreas Gruenbacher To: Alexander Viro , Christoph Hellwig , Eric Paris , "Aneesh Kumar K.V" , linux-fsdevel@vger.kernel.org, David Quigley , "J. Bruce Fields" Cc: linux-security-module@vger.kernel.org, cluster-devel@redhat.com Subject: [RFC 10/11] selinux: Allow to invalidate an inode's security label Date: Thu, 20 Aug 2015 20:19:57 +0200 Message-Id: <1440094798-1411-11-git-send-email-agruenba@redhat.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1440094798-1411-1-git-send-email-agruenba@redhat.com> References: <1440094798-1411-1-git-send-email-agruenba@redhat.com> Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add the LSM and SELinux infrastructure for invalidating inode->i_security and for re-initializing it from inode_has_perm when necessary. In inode_has_perm, we don't have access to a dentry, so file systems must implement iop->igetxattr in order to be able to invalidate security labels. Alternatively, we could add an inode operation called by inode_has_perm to revalidate the security label of the inode on each call, but inode_has_perm is called so frequently that the overhead seems excessive. Signed-off-by: Andreas Gruenbacher --- include/linux/lsm_hooks.h | 6 +++++ include/linux/security.h | 5 +++++ security/selinux/hooks.c | 47 ++++++++++++++++++++++++++++++--------- security/selinux/include/objsec.h | 3 ++- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9429f05..9fe99d6 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1261,6 +1261,10 @@ * audit_rule_init. * @rule contains the allocated rule * + * @inode_invalidate_secctx: + * Notify the security module that it must revalidate the security context + * of an inode before the next access. + * * @inode_notifysecctx: * Notify the security module of what the security context of an inode * should be. Initializes the incore security context managed by the @@ -1516,6 +1520,7 @@ union security_list_options { int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid); void (*release_secctx)(char *secdata, u32 seclen); + void (*inode_invalidate_secctx)(struct inode *inode); int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen); int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen); int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen); @@ -1757,6 +1762,7 @@ struct security_hook_heads { struct list_head secid_to_secctx; struct list_head secctx_to_secid; struct list_head release_secctx; + struct list_head inode_invalidate_secctx; struct list_head inode_notifysecctx; struct list_head inode_setsecctx; struct list_head inode_getsecctx; diff --git a/include/linux/security.h b/include/linux/security.h index 79d85dd..f50587d 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -353,6 +353,7 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); void security_release_secctx(char *secdata, u32 seclen); +int security_inode_invalidate_secctx(struct inode *inode); int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); @@ -1093,6 +1094,10 @@ static inline void security_release_secctx(char *secdata, u32 seclen) { } +static inline void security_inode_invalidate_secctx(struct inode *inode) +{ +} + static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { return -EOPNOTSUPP; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 564079c..e80fcda 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -430,7 +430,7 @@ static int sb_finish_set_opts(struct super_block *sb) rc = -EOPNOTSUPP; goto out; } - rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); + rc = selinux_getxattr(root_inode, root, NULL, 0); if (rc < 0 && rc != -ENODATA) { if (rc == -EOPNOTSUPP) printk(KERN_WARNING "SELinux: (dev %s, type " @@ -1270,6 +1270,19 @@ static int selinux_genfs_get_sid(struct dentry *dentry, return rc; } +static int selinux_getxattr(struct inode *inode, struct dentry *dentry, + char *context, unsigned int len) +{ + if (dentry) + return inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, + context, len); + else if (inode && inode->i_op->igetxattr) + return inode->i_op->igetxattr(inode, XATTR_NAME_SELINUX, + context, len); + else + return -EOPNOTSUPP; +} + /* The inode's security attributes must be initialized before first use. */ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) { @@ -1282,11 +1295,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent unsigned len = 0; int rc = 0; - if (isec->initialized) + if (isec->initialized == 1) goto out; mutex_lock(&isec->lock); - if (isec->initialized) + if (isec->initialized == 1) goto out_unlock; sbsec = inode->i_sb->s_security; @@ -1319,7 +1332,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent /* Called from selinux_complete_init, try to find a dentry. */ dentry = d_find_alias(inode); } - if (!dentry) { + if (!dentry && !inode->i_op->igetxattr) { /* * this is can be hit on boot when a file is accessed * before the policy is loaded. When we load policy we @@ -1340,14 +1353,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent goto out_unlock; } context[len] = '\0'; - rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, - context, len); + rc = selinux_getxattr(inode, dentry, context, len); if (rc == -ERANGE) { kfree(context); /* Need a larger buffer. Query for the right size. */ - rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, - NULL, 0); + rc = selinux_getxattr(inode, dentry, NULL, 0); if (rc < 0) { dput(dentry); goto out_unlock; @@ -1360,9 +1371,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent goto out_unlock; } context[len] = '\0'; - rc = inode->i_op->getxattr(dentry, - XATTR_NAME_SELINUX, - context, len); + rc = selinux_getxattr(inode, dentry, context, len); } dput(dentry); if (rc < 0) { @@ -1614,6 +1623,12 @@ static int inode_has_perm(const struct cred *cred, sid = cred_sid(cred); isec = inode->i_security; + if (isec->initialized == 2) { + inode_doinit(inode); + if (isec->initialized == 2) + return -EACCES; + } + return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); } @@ -5715,6 +5730,15 @@ static void selinux_release_secctx(char *secdata, u32 seclen) kfree(secdata); } +static void selinux_inode_invalidate_secctx(struct inode *inode) +{ + struct inode_security_struct *isec = inode->i_security; + + mutex_lock(&isec->lock); + isec->initialized = 2; + mutex_unlock(&isec->lock); +} + /* * called with inode->i_mutex locked */ @@ -5946,6 +5970,7 @@ static struct security_hook_list selinux_hooks[] = { LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx), LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid), LSM_HOOK_INIT(release_secctx, selinux_release_secctx), + LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx), LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx), LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx), LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx), diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 81fa718..5b13732 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -46,7 +46,8 @@ struct inode_security_struct { u32 task_sid; /* SID of creating task */ u32 sid; /* SID of this object */ u16 sclass; /* security class of this object */ - unsigned char initialized; /* initialization flag */ + unsigned char initialized; /* 0: not initialized, 1: initialized, + 2: needs revalidation */ struct mutex lock; };