From patchwork Mon Oct 5 19:36:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 7331211 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 918F1BEEA4 for ; Mon, 5 Oct 2015 20:06:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 99B1C20615 for ; Mon, 5 Oct 2015 20:06:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8235D20603 for ; Mon, 5 Oct 2015 20:06:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752610AbbJETin (ORCPT ); Mon, 5 Oct 2015 15:38:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:36196 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751300AbbJETil (ORCPT ); Mon, 5 Oct 2015 15:38:41 -0400 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (Postfix) with ESMTPS id 8151EC0B2B42; Mon, 5 Oct 2015 19:38:41 +0000 (UTC) Received: from nux.home.com (vpn1-7-226.ams2.redhat.com [10.36.7.226]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t95JbDHU018133; Mon, 5 Oct 2015 15:38:36 -0400 From: Andreas Gruenbacher To: Alexander Viro , "Theodore Ts'o" , Andreas Dilger , "J. Bruce Fields" , Jeff Layton , Trond Myklebust , Anna Schumaker , linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-api@vger.kernel.org Subject: [PATCH v9 15/43] richacl: Create-time inheritance Date: Mon, 5 Oct 2015 21:36:42 +0200 Message-Id: <1444073830-21854-16-git-send-email-agruenba@redhat.com> In-Reply-To: <1444073830-21854-1-git-send-email-agruenba@redhat.com> References: <1444073830-21854-1-git-send-email-agruenba@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.26 Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable 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 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 (draft) 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: J. Bruce Fields --- fs/richacl_base.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ fs/richacl_inode.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/richacl.h | 2 ++ 3 files changed, 144 insertions(+) diff --git a/fs/richacl_base.c b/fs/richacl_base.c index 8832ba6..a1c675c 100644 --- a/fs/richacl_base.c +++ b/fs/richacl_base.c @@ -484,3 +484,71 @@ richacl_equiv_mode(const struct richacl *acl, mode_t *mode_p) return 0; } EXPORT_SYMBOL_GPL(richacl_equiv_mode); + +/** + * 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 (!richace_is_inheritable(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 (!richace_is_inheritable(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; + 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; +} diff --git a/fs/richacl_inode.c b/fs/richacl_inode.c index e3cf9dd..d58307a 100644 --- a/fs/richacl_inode.c +++ b/fs/richacl_inode.c @@ -252,3 +252,77 @@ richacl_chmod(struct inode *inode, mode_t mode) return retval; } EXPORT_SYMBOL(richacl_chmod); + +/* + * richacl_inherit_inode - compute inherited acl and file mode + * @dir_acl: acl of the containing directory + * @inode: inode of the new file (create mode in i_mode) + * + * The file permission bits in inode->i_mode must be set to the create mode by + * the caller. + * + * If there is an inheritable acl, the maximum permissions that the acl grants + * will be computed and permissions not granted by the acl will be removed from + * inode->i_mode. If there is no inheritable acl, the umask will be applied + * instead. + */ +static struct richacl * +richacl_inherit_inode(const struct richacl *dir_acl, struct inode *inode) +{ + struct richacl *acl; + mode_t mask; + + acl = richacl_inherit(dir_acl, S_ISDIR(inode->i_mode)); + if (acl) { + mask = inode->i_mode; + if (richacl_equiv_mode(acl, &mask) == 0) { + 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(inode->i_mode >> 6); + acl->a_group_mask &= + richacl_mode_to_mask(inode->i_mode >> 3); + acl->a_other_mask &= + richacl_mode_to_mask(inode->i_mode); + mask = ~S_IRWXUGO | richacl_masks_to_mode(acl); + } + } else + mask = ~current_umask(); + + inode->i_mode &= mask; + return acl; +} + +/** + * richacl_create - filesystem create helper + * @inode: inode being created + * @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(struct inode *inode, struct inode *dir) +{ + struct richacl *dir_acl, *acl = NULL; + + if (S_ISLNK(inode->i_mode)) + return NULL; + dir_acl = get_richacl(dir); + if (dir_acl) { + if (IS_ERR(dir_acl)) + return dir_acl; + acl = richacl_inherit_inode(dir_acl, inode); + richacl_put(dir_acl); + } else + inode->i_mode &= ~current_umask(); + return acl; +} +EXPORT_SYMBOL_GPL(richacl_create); diff --git a/include/linux/richacl.h b/include/linux/richacl.h index c715f82..36a4e0a 100644 --- a/include/linux/richacl.h +++ b/include/linux/richacl.h @@ -305,9 +305,11 @@ extern unsigned int richacl_want_to_mask(unsigned int); extern void richacl_compute_max_masks(struct richacl *); extern struct richacl *__richacl_chmod(struct richacl *, mode_t); extern int richacl_equiv_mode(const struct richacl *, mode_t *); +extern struct richacl *richacl_inherit(const struct richacl *, int); /* richacl_inode.c */ extern int richacl_permission(struct inode *, const struct richacl *, int); extern int richacl_chmod(struct inode *, mode_t); +extern struct richacl *richacl_create(struct inode *, struct inode *); #endif /* __RICHACL_H */