From patchwork Thu Jun 30 13:47:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 9207629 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 9326960752 for ; Thu, 30 Jun 2016 13:49:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8373E2865F for ; Thu, 30 Jun 2016 13:49:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 77DB928673; Thu, 30 Jun 2016 13:49:30 +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=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from oss.sgi.com (oss.sgi.com [192.48.182.195]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3C3812865F for ; Thu, 30 Jun 2016 13:49:29 +0000 (UTC) Received: from oss.sgi.com (localhost [IPv6:::1]) by oss.sgi.com (Postfix) with ESMTP id BC91A7CBE; Thu, 30 Jun 2016 08:49:10 -0500 (CDT) X-Original-To: xfs@oss.sgi.com Delivered-To: xfs@oss.sgi.com Received: from relay.sgi.com (relay1.corp.sgi.com [137.38.102.111]) by oss.sgi.com (Postfix) with ESMTP id 0FC807CA4 for ; Thu, 30 Jun 2016 08:49:09 -0500 (CDT) Received: from cuda.sgi.com (cuda2.sgi.com [192.48.176.25]) by relay1.corp.sgi.com (Postfix) with ESMTP id C83298F8064 for ; Thu, 30 Jun 2016 06:49:08 -0700 (PDT) X-ASG-Debug-ID: 1467294547-04cbb027373b63a0001-NocioJ Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by cuda.sgi.com with ESMTP id 6wPc5Mg4B9aCd1M5 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Thu, 30 Jun 2016 06:49:07 -0700 (PDT) X-Barracuda-Envelope-From: agruenba@redhat.com X-Barracuda-Effective-Source-IP: mx1.redhat.com[209.132.183.28] X-Barracuda-Apparent-Source-IP: 209.132.183.28 X-ASG-Whitelist: Client Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EB6E7C0467C8; Thu, 30 Jun 2016 13:49:06 +0000 (UTC) Received: from nux.redhat.com (vpn1-5-124.ams2.redhat.com [10.36.5.124]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u5UDlDsq005273; Thu, 30 Jun 2016 09:49:00 -0400 From: Andreas Gruenbacher To: Alexander Viro Subject: [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode Date: Thu, 30 Jun 2016 15:47:06 +0200 X-ASG-Orig-Subj: [PATCH v23 15/22] richacl: Check if an acl is equivalent to a file mode Message-Id: <1467294433-3222-16-git-send-email-agruenba@redhat.com> In-Reply-To: <1467294433-3222-1-git-send-email-agruenba@redhat.com> References: <1467294433-3222-1-git-send-email-agruenba@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 30 Jun 2016 13:49:07 +0000 (UTC) X-Barracuda-Connect: mx1.redhat.com[209.132.183.28] X-Barracuda-Start-Time: 1467294547 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://192.48.176.25:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 4352 X-Virus-Scanned: by bsmtpd at sgi.com X-Barracuda-BRTS-Status: 1 Cc: "J. Bruce Fields" , linux-nfs@vger.kernel.org, Theodore Ts'o , Andreas Gruenbacher , linux-cifs@vger.kernel.org, linux-api@vger.kernel.org, Trond Myklebust , linux-kernel@vger.kernel.org, xfs@oss.sgi.com, Christoph Hellwig , Andreas Dilger , linux-fsdevel@vger.kernel.org, Jeff Layton , linux-ext4@vger.kernel.org, Anna Schumaker X-BeenThere: xfs@oss.sgi.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: XFS Filesystem from SGI List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: xfs-bounces@oss.sgi.com Sender: xfs-bounces@oss.sgi.com X-Virus-Scanned: ClamAV using ClamSMTP ACLs are considered equivalent to file modes if they only consist of owner@, group@, and everyone@ entries, the owner@ permissions do not depend on whether the owner is a member in the owning group, and no inheritance flags are set. This test is used to avoid storing richacls if the acl can be computed from the file permission bits. Signed-off-by: Andreas Gruenbacher Reviewed-by: J. Bruce Fields Reviewed-by: Jeff Layton --- fs/richacl.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/richacl.h | 1 + 2 files changed, 105 insertions(+) diff --git a/fs/richacl.c b/fs/richacl.c index ba110a6..e8a383b 100644 --- a/fs/richacl.c +++ b/fs/richacl.c @@ -618,3 +618,107 @@ richacl_chmod(struct inode *inode, umode_t mode) return retval; } EXPORT_SYMBOL(richacl_chmod); + +/** + * richacl_equiv_mode - compute the mode equivalent of @acl + * + * An acl is considered equivalent to a file mode if it only consists of + * owner@, group@, and everyone@ entries and the owner@ permissions do not + * depend on whether the owner is a member in the owning group. + */ +int +richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p) +{ + umode_t mode = *mode_p; + + /* + * The RICHACE_DELETE_CHILD flag is meaningless for non-directories, so + * we ignore it. + */ + unsigned int x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD; + struct { + unsigned int allowed; + unsigned int defined; /* allowed or denied */ + } owner = { + .defined = RICHACE_POSIX_ALWAYS_ALLOWED | + RICHACE_POSIX_OWNER_ALLOWED | x, + }, group = { + .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x, + }, everyone = { + .defined = RICHACE_POSIX_ALWAYS_ALLOWED | x, + }; + const struct richace *ace; + + if (acl->a_flags & ~(RICHACL_WRITE_THROUGH | RICHACL_MASKED)) + return -1; + + richacl_for_each_entry(ace, acl) { + if (ace->e_flags & ~RICHACE_SPECIAL_WHO) + return -1; + + if (richace_is_owner(ace) || richace_is_everyone(ace)) { + x = ace->e_mask & ~owner.defined; + if (richace_is_allow(ace)) { + unsigned int group_denied = + group.defined & ~group.allowed; + + if (x & group_denied) + return -1; + owner.allowed |= x; + } else /* if (richace_is_deny(ace)) */ { + if (x & group.allowed) + return -1; + } + owner.defined |= x; + + if (richace_is_everyone(ace)) { + x = ace->e_mask; + if (richace_is_allow(ace)) { + group.allowed |= + x & ~group.defined; + everyone.allowed |= + x & ~everyone.defined; + } + group.defined |= x; + everyone.defined |= x; + } + } else if (richace_is_group(ace)) { + x = ace->e_mask & ~group.defined; + if (richace_is_allow(ace)) + group.allowed |= x; + group.defined |= x; + } else + return -1; + } + + if (group.allowed & ~owner.defined) + return -1; + + if (acl->a_flags & RICHACL_MASKED) { + if (acl->a_flags & RICHACL_WRITE_THROUGH) { + owner.allowed = acl->a_owner_mask; + everyone.allowed = acl->a_other_mask; + } else { + owner.allowed &= acl->a_owner_mask; + everyone.allowed &= acl->a_other_mask; + } + group.allowed &= acl->a_group_mask; + } + + mode = (mode & ~S_IRWXUGO) | + (richacl_mask_to_mode(owner.allowed) << 6) | + (richacl_mask_to_mode(group.allowed) << 3) | + richacl_mask_to_mode(everyone.allowed); + + /* Mask flags we can ignore */ + x = S_ISDIR(mode) ? 0 : RICHACE_DELETE_CHILD; + + if (((richacl_mode_to_mask(mode >> 6) ^ owner.allowed) & ~x) || + ((richacl_mode_to_mask(mode >> 3) ^ group.allowed) & ~x) || + ((richacl_mode_to_mask(mode) ^ everyone.allowed) & ~x)) + return -1; + + *mode_p = mode; + return 0; +} +EXPORT_SYMBOL_GPL(richacl_equiv_mode); diff --git a/include/linux/richacl.h b/include/linux/richacl.h index db82fab..9212edb 100644 --- a/include/linux/richacl.h +++ b/include/linux/richacl.h @@ -191,5 +191,6 @@ extern unsigned int richacl_want_to_mask(unsigned int); extern void richacl_compute_max_masks(struct richacl *); extern int richacl_permission(struct inode *, const struct richacl *, int); extern int richacl_chmod(struct inode *, umode_t); +extern int richacl_equiv_mode(const struct richacl *, umode_t *); #endif /* __RICHACL_H */