From patchwork Tue May 31 11:50:53 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 9144527 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 5DD2660757 for ; Tue, 31 May 2016 11:54:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4F441272D8 for ; Tue, 31 May 2016 11:54:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 43E5127B89; Tue, 31 May 2016 11:54:29 +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.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable 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 55935272D8 for ; Tue, 31 May 2016 11:54:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754455AbcEaLxc (ORCPT ); Tue, 31 May 2016 07:53:32 -0400 Received: from mx1.redhat.com ([209.132.183.28]:38757 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754410AbcEaLx1 (ORCPT ); Tue, 31 May 2016 07:53:27 -0400 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (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 7B64D3B70B; Tue, 31 May 2016 11:53:26 +0000 (UTC) Received: from nux.redhat.com (vpn1-6-182.ams2.redhat.com [10.36.6.182]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u4VBota3031703; Tue, 31 May 2016 07:53:20 -0400 From: Andreas Gruenbacher To: Alexander Viro Cc: "Aneesh Kumar K.V" , Christoph Hellwig , "Theodore Ts'o" , Andreas Dilger , "J. Bruce Fields" , Jeff Layton , Trond Myklebust , Anna Schumaker , Dave Chinner , linux-ext4@vger.kernel.org, xfs@oss.sgi.com, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-cifs@vger.kernel.org, linux-api@vger.kernel.org, Andreas Gruenbacher Subject: [PATCH v22 21/22] ext4: Add richacl support Date: Tue, 31 May 2016 13:50:53 +0200 Message-Id: <1464695454-18557-22-git-send-email-agruenba@redhat.com> In-Reply-To: <1464695454-18557-1-git-send-email-agruenba@redhat.com> References: <1464695454-18557-1-git-send-email-agruenba@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Tue, 31 May 2016 11:53:26 +0000 (UTC) Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: "Aneesh Kumar K.V" Support the richacl permission model in ext4. The richacls are stored in "system.richacl" xattrs. Richacls need to be enabled by tune2fs or at file system create time. Signed-off-by: Aneesh Kumar K.V Signed-off-by: Andreas Gruenbacher Reviewed-by: Andreas Dilger --- fs/ext4/Kconfig | 11 +++++ fs/ext4/Makefile | 1 + fs/ext4/file.c | 3 ++ fs/ext4/ialloc.c | 11 ++++- fs/ext4/inode.c | 5 +- fs/ext4/namei.c | 5 ++ fs/ext4/richacl.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/ext4/richacl.h | 40 ++++++++++++++++ fs/ext4/xattr.c | 7 +++ include/linux/acl.h | 15 ++++++ 10 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 fs/ext4/richacl.c create mode 100644 fs/ext4/richacl.h create mode 100644 include/linux/acl.h diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index b46e9fc..4e21c18 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -22,6 +22,17 @@ config EXT3_FS_POSIX_ACL This config option is here only for backward compatibility. ext3 filesystem is now handled by the ext4 driver. +config EXT4_FS_RICHACL + bool "Ext4 Rich Access Control Lists" + depends on EXT4_FS + select FS_RICHACL + help + Richacls are an implementation of NFSv4 ACLs, extended by file masks + to cleanly integrate into the POSIX file permission model. To learn + more about them, see http://www.bestbits.at/richacl/. + + If you don't know what Richacls are, say N. + config EXT3_FS_SECURITY bool "Ext3 Security Labels" depends on EXT3_FS diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index f52cf54..1fb7f11 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -14,3 +14,4 @@ ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o ext4-$(CONFIG_EXT4_FS_ENCRYPTION) += crypto_policy.o crypto.o \ crypto_key.o crypto_fname.o +ext4-$(CONFIG_EXT4_FS_RICHACL) += richacl.o diff --git a/fs/ext4/file.c b/fs/ext4/file.c index df44c87..6e7b4b9 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -30,6 +30,7 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" +#include "richacl.h" /* * Called when an inode is released. Note that this is different @@ -717,6 +718,8 @@ const struct inode_operations ext4_file_inode_operations = { .removexattr = generic_removexattr, .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, + .get_richacl = ext4_get_richacl, + .set_richacl = ext4_set_richacl, .fiemap = ext4_fiemap, }; diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 3da4cf8..5bd382a 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -27,6 +27,7 @@ #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" +#include "richacl.h" #include @@ -729,6 +730,14 @@ out: return ret; } +static inline int +ext4_new_acl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + if (IS_RICHACL(dir)) + return ext4_init_richacl(handle, inode, dir); + return ext4_init_acl(handle, inode, dir); +} + /* * There are two policies for allocating an inode. If the new inode is * a directory, then a forward search is made for a block group with both @@ -1093,7 +1102,7 @@ got: if (err) goto fail_drop; - err = ext4_init_acl(handle, inode, dir); + err = ext4_new_acl(handle, inode, dir); if (err) goto fail_free_drop; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index f7140ca..7b8d96f 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -37,10 +37,10 @@ #include #include #include +#include #include "ext4_jbd2.h" #include "xattr.h" -#include "acl.h" #include "truncate.h" #include @@ -5183,8 +5183,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) ext4_orphan_del(NULL, inode); if (!rc && (ia_valid & ATTR_MODE)) - rc = posix_acl_chmod(inode, inode->i_mode); - + rc = acl_chmod(inode); err_out: ext4_std_error(inode->i_sb, error); if (!error) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index ec4c399..09e36b7 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -38,6 +38,7 @@ #include "xattr.h" #include "acl.h" +#include "richacl.h" #include /* @@ -3893,6 +3894,8 @@ const struct inode_operations ext4_dir_inode_operations = { .removexattr = generic_removexattr, .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, + .get_richacl = ext4_get_richacl, + .set_richacl = ext4_set_richacl, .fiemap = ext4_fiemap, }; @@ -3904,4 +3907,6 @@ const struct inode_operations ext4_special_inode_operations = { .removexattr = generic_removexattr, .get_acl = ext4_get_acl, .set_acl = ext4_set_acl, + .get_richacl = ext4_get_richacl, + .set_richacl = ext4_set_richacl, }; diff --git a/fs/ext4/richacl.c b/fs/ext4/richacl.c new file mode 100644 index 0000000..0c316ff --- /dev/null +++ b/fs/ext4/richacl.c @@ -0,0 +1,134 @@ +/* + * Copyright IBM Corporation, 2010 + * Copyright (C) 2015 Red Hat, Inc. + * Author: Aneesh Kumar K.V , + * Andreas Gruenbacher + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#include +#include +#include + +#include "ext4.h" +#include "ext4_jbd2.h" +#include "xattr.h" +#include "acl.h" +#include "richacl.h" + +struct richacl * +ext4_get_richacl(struct inode *inode) +{ + const int name_index = EXT4_XATTR_INDEX_RICHACL; + void *value = NULL; + struct richacl *acl = NULL; + int retval; + + retval = ext4_xattr_get(inode, name_index, "", NULL, 0); + if (retval > 0) { + value = kmalloc(retval, GFP_NOFS); + if (!value) + return ERR_PTR(-ENOMEM); + retval = ext4_xattr_get(inode, name_index, "", value, retval); + } + if (retval > 0) + acl = richacl_from_xattr(&init_user_ns, value, retval, -EIO); + else if (retval != -ENODATA && retval != -ENOSYS) + acl = ERR_PTR(retval); + kfree(value); + + return acl; +} + +static int +__ext4_remove_richacl(handle_t *handle, struct inode *inode) +{ + const int name_index = EXT4_XATTR_INDEX_RICHACL; + int retval; + + retval = ext4_xattr_set_handle(handle, inode, name_index, "", + NULL, 0, 0); + if (!retval) + set_cached_richacl(inode, NULL); + return retval; +} + +static int +__ext4_set_richacl(handle_t *handle, struct inode *inode, struct richacl *acl) +{ + const int name_index = EXT4_XATTR_INDEX_RICHACL; + umode_t mode = inode->i_mode; + int retval, size; + void *value; + + if (richacl_equiv_mode(acl, &mode) == 0) { + inode->i_ctime = ext4_current_time(inode); + inode->i_mode = mode; + ext4_mark_inode_dirty(handle, inode); + return __ext4_remove_richacl(handle, inode); + } + + mode &= ~S_IRWXUGO; + mode |= richacl_masks_to_mode(acl); + + size = richacl_xattr_size(acl); + value = kmalloc(size, GFP_NOFS); + if (!value) + return -ENOMEM; + richacl_to_xattr(&init_user_ns, acl, value, size); + inode->i_mode = mode; + retval = ext4_xattr_set_handle(handle, inode, name_index, "", + value, size, 0); + kfree(value); + if (retval) + return retval; + + set_cached_richacl(inode, acl); + + return 0; +} + +int +ext4_set_richacl(struct inode *inode, struct richacl *acl) +{ + handle_t *handle; + int retval, retries = 0; + +retry: + handle = ext4_journal_start(inode, EXT4_HT_XATTR, + ext4_jbd2_credits_xattr(inode)); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + if (acl) + retval = __ext4_set_richacl(handle, inode, acl); + else + retval = __ext4_remove_richacl(handle, inode); + + ext4_journal_stop(handle); + if (retval == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) + goto retry; + return retval; +} + +int +ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + struct richacl *acl = richacl_create(&inode->i_mode, dir); + int error; + + error = PTR_ERR(acl); + if (!IS_ERR_OR_NULL(acl)) { + error = __ext4_set_richacl(handle, inode, acl); + richacl_put(acl); + } + return error; +} diff --git a/fs/ext4/richacl.h b/fs/ext4/richacl.h new file mode 100644 index 0000000..6fe9a92 --- /dev/null +++ b/fs/ext4/richacl.h @@ -0,0 +1,40 @@ +/* + * Copyright IBM Corporation, 2010 + * Copyright (C) 2015 Red Hat, Inc. + * Author Aneesh Kumar K.V + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __FS_EXT4_RICHACL_H +#define __FS_EXT4_RICHACL_H + +#include + +#ifdef CONFIG_EXT4_FS_RICHACL + +extern struct richacl *ext4_get_richacl(struct inode *); +extern int ext4_set_richacl(struct inode *, struct richacl *); + +extern int ext4_init_richacl(handle_t *, struct inode *, struct inode *); + +#else /* CONFIG_EXT4_FS_RICHACL */ + +#define ext4_get_richacl NULL +#define ext4_set_richacl NULL + +static inline int +ext4_init_richacl(handle_t *handle, struct inode *inode, struct inode *dir) +{ + return 0; +} + +#endif /* CONFIG_EXT4_FS_RICHACL */ +#endif /* __FS_EXT4_RICHACL_H */ diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index e79bd32..e5ca483 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -55,6 +55,7 @@ #include #include #include +#include #include "ext4_jbd2.h" #include "ext4.h" #include "xattr.h" @@ -97,6 +98,9 @@ static const struct xattr_handler *ext4_xattr_handler_map[] = { #ifdef CONFIG_EXT4_FS_SECURITY [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, #endif +#ifdef CONFIG_EXT4_FS_RICHACL + [EXT4_XATTR_INDEX_RICHACL] = &richacl_xattr_handler, +#endif }; const struct xattr_handler *ext4_xattr_handlers[] = { @@ -109,6 +113,9 @@ const struct xattr_handler *ext4_xattr_handlers[] = { #ifdef CONFIG_EXT4_FS_SECURITY &ext4_xattr_security_handler, #endif +#ifdef CONFIG_EXT4_FS_RICHACL + &richacl_xattr_handler, +#endif NULL }; diff --git a/include/linux/acl.h b/include/linux/acl.h new file mode 100644 index 0000000..3c3b5ce --- /dev/null +++ b/include/linux/acl.h @@ -0,0 +1,15 @@ +#ifndef __LINUX_ACL_H +#define __LINUX_ACL_H + +#include +#include + +static inline int +acl_chmod(struct inode *inode) +{ + if (IS_RICHACL(inode)) + return richacl_chmod(inode, inode->i_mode); + return posix_acl_chmod(inode, inode->i_mode); +} + +#endif