From patchwork Thu Jun 30 13:47:07 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 9207631 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 0D44F60752 for ; Thu, 30 Jun 2016 13:49:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F255D28679 for ; Thu, 30 Jun 2016 13:49:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E66D52867D; Thu, 30 Jun 2016 13:49:37 +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 67CB628679 for ; Thu, 30 Jun 2016 13:49:37 +0000 (UTC) Received: from oss.sgi.com (localhost [IPv6:::1]) by oss.sgi.com (Postfix) with ESMTP id A6C5B7CCF; Thu, 30 Jun 2016 08:49:18 -0500 (CDT) X-Original-To: xfs@oss.sgi.com Delivered-To: xfs@oss.sgi.com Received: from relay.sgi.com (relay3.corp.sgi.com [198.149.34.15]) by oss.sgi.com (Postfix) with ESMTP id 4B62C7CA4 for ; Thu, 30 Jun 2016 08:49:16 -0500 (CDT) Received: from cuda.sgi.com (cuda1.sgi.com [192.48.157.11]) by relay3.corp.sgi.com (Postfix) with ESMTP id D9633AC008 for ; Thu, 30 Jun 2016 06:49:15 -0700 (PDT) X-ASG-Debug-ID: 1467294554-04bdf074b62387a0001-NocioJ Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by cuda.sgi.com with ESMTP id geSX7xTzVvzuMCpo (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Thu, 30 Jun 2016 06:49:14 -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 DDDA1C05B1E7; Thu, 30 Jun 2016 13:49:13 +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 u5UDlDsr005273; Thu, 30 Jun 2016 09:49:07 -0400 From: Andreas Gruenbacher To: Alexander Viro Subject: [PATCH v23 16/22] richacl: Create-time inheritance Date: Thu, 30 Jun 2016 15:47:07 +0200 X-ASG-Orig-Subj: [PATCH v23 16/22] richacl: Create-time inheritance Message-Id: <1467294433-3222-17-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.32]); Thu, 30 Jun 2016 13:49:14 +0000 (UTC) X-Barracuda-Connect: mx1.redhat.com[209.132.183.28] X-Barracuda-Start-Time: 1467294554 X-Barracuda-Encrypted: ECDHE-RSA-AES256-GCM-SHA384 X-Barracuda-URL: https://192.48.157.11:443/cgi-mod/mark.cgi X-Barracuda-Scan-Msg-Size: 5758 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 When a new file is created, it can inherit an acl from its parent directory; this is similar to how default acls work in POSIX ACLs. As with POSIX ACLs, if a file inherits an acl from its parent directory, the intersection between the create mode and the permissions granted by the inherited acl determines the file masks and file permission bits, and the umask is ignored. Signed-off-by: Andreas Gruenbacher Reviewed-by: Jeff Layton --- fs/richacl.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/richacl.h | 2 + 2 files changed, 153 insertions(+) diff --git a/fs/richacl.c b/fs/richacl.c index e8a383b..29eaf89 100644 --- a/fs/richacl.c +++ b/fs/richacl.c @@ -722,3 +722,154 @@ richacl_equiv_mode(const struct richacl *acl, umode_t *mode_p) return 0; } EXPORT_SYMBOL_GPL(richacl_equiv_mode); + +static inline bool +ace_inherits_to_directory(const struct richace *ace) +{ + if (ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE) + return true; + if ((ace->e_flags & RICHACE_FILE_INHERIT_ACE) && + !(ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE)) + return true; + return false; +} + +/** + * richacl_inherit - compute the inherited acl of a new file + * @dir_acl: acl of the containing directory + * @isdir: inherit by a directory or non-directory? + * + * A directory can have acl entries which files and/or directories created + * inside the directory will inherit. This function computes the acl for such + * a new file. If there is no inheritable acl, it will return %NULL. + */ +struct richacl * +richacl_inherit(const struct richacl *dir_acl, int isdir) +{ + const struct richace *dir_ace; + struct richacl *acl = NULL; + struct richace *ace; + int count = 0; + + if (isdir) { + richacl_for_each_entry(dir_ace, dir_acl) { + if (!ace_inherits_to_directory(dir_ace)) + continue; + count++; + } + if (!count) + return NULL; + acl = richacl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + ace = acl->a_entries; + richacl_for_each_entry(dir_ace, dir_acl) { + if (!ace_inherits_to_directory(dir_ace)) + continue; + richace_copy(ace, dir_ace); + if (dir_ace->e_flags & RICHACE_NO_PROPAGATE_INHERIT_ACE) + ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS; + else if (dir_ace->e_flags & RICHACE_DIRECTORY_INHERIT_ACE) + ace->e_flags &= ~RICHACE_INHERIT_ONLY_ACE; + else + ace->e_flags |= RICHACE_INHERIT_ONLY_ACE; + ace++; + } + } else { + richacl_for_each_entry(dir_ace, dir_acl) { + if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE)) + continue; + count++; + } + if (!count) + return NULL; + acl = richacl_alloc(count, GFP_KERNEL); + if (!acl) + return ERR_PTR(-ENOMEM); + ace = acl->a_entries; + richacl_for_each_entry(dir_ace, dir_acl) { + if (!(dir_ace->e_flags & RICHACE_FILE_INHERIT_ACE)) + continue; + richace_copy(ace, dir_ace); + ace->e_flags &= ~RICHACE_INHERITANCE_FLAGS; + /* + * RICHACE_DELETE_CHILD is meaningless for + * non-directories, so clear it. + */ + ace->e_mask &= ~RICHACE_DELETE_CHILD; + ace++; + } + } + + return acl; +} + +/* + * richacl_inherit_inode - compute inherited acl and file mode + * @dir_acl: acl of the containing directory + * @mode_p: mode of the new inode + * + * The file permission bits in @mode_p must be set to the create mode by the + * caller. + * + * If there is an inheritable acl, the maximum permissions that the acl grants + * are computed and the file masks of the new acl are set accordingly. + */ +static struct richacl * +richacl_inherit_inode(const struct richacl *dir_acl, umode_t *mode_p) +{ + struct richacl *acl; + umode_t mode = *mode_p; + + acl = richacl_inherit(dir_acl, S_ISDIR(mode)); + if (acl) { + if (richacl_equiv_mode(acl, &mode) == 0) { + *mode_p &= mode; + richacl_put(acl); + acl = NULL; + } else { + richacl_compute_max_masks(acl); + /* + * Ensure that the acl will not grant any permissions + * beyond the create mode. + */ + acl->a_flags |= RICHACL_MASKED; + acl->a_owner_mask &= + richacl_mode_to_mask(mode >> 6); + acl->a_group_mask &= + richacl_mode_to_mask(mode >> 3); + acl->a_other_mask &= + richacl_mode_to_mask(mode); + } + } else + *mode_p &= ~current_umask(); + + return acl; +} + +/** + * richacl_create - filesystem create helper + * @mode_p: mode of the new inode + * @dir: containing directory + * + * Compute the inherited acl for a new inode. If there is no acl to inherit, + * apply the umask. Use when creating a new inode on a richacl enabled file + * system. + */ +struct richacl *richacl_create(umode_t *mode_p, struct inode *dir) +{ + struct richacl *dir_acl, *acl = NULL; + + if (S_ISLNK(*mode_p)) + return NULL; + dir_acl = get_richacl(dir); + if (dir_acl) { + if (IS_ERR(dir_acl)) + return dir_acl; + acl = richacl_inherit_inode(dir_acl, mode_p); + richacl_put(dir_acl); + } else + *mode_p &= ~current_umask(); + return acl; +} +EXPORT_SYMBOL_GPL(richacl_create); diff --git a/include/linux/richacl.h b/include/linux/richacl.h index 9212edb..7aca1a3 100644 --- a/include/linux/richacl.h +++ b/include/linux/richacl.h @@ -192,5 +192,7 @@ 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 *); +extern struct richacl *richacl_inherit(const struct richacl *, int); +extern struct richacl *richacl_create(umode_t *, struct inode *); #endif /* __RICHACL_H */