From patchwork Thu Nov 5 11:39:38 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Gruenbacher X-Patchwork-Id: 7560361 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 288259F399 for ; Thu, 5 Nov 2015 11:44:27 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 44A6F208A7 for ; Thu, 5 Nov 2015 11:44:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 41DC1208A5 for ; Thu, 5 Nov 2015 11:44:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161711AbbKELmL (ORCPT ); Thu, 5 Nov 2015 06:42:11 -0500 Received: from mx1.redhat.com ([209.132.183.28]:57775 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161701AbbKELmI (ORCPT ); Thu, 5 Nov 2015 06:42:08 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (Postfix) with ESMTPS id EB925130B; Thu, 5 Nov 2015 11:42:07 +0000 (UTC) Received: from nux.redhat.com (vpn1-7-134.ams2.redhat.com [10.36.7.134]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id tA5Bdfbv015870; Thu, 5 Nov 2015 06:42:01 -0500 From: Andreas Gruenbacher To: Alexander Viro , "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 Cc: Andreas Gruenbacher Subject: [PATCH v14 20/22] vfs: Add richacl permission checking Date: Thu, 5 Nov 2015 12:39:38 +0100 Message-Id: <1446723580-3747-21-git-send-email-agruenba@redhat.com> In-Reply-To: <1446723580-3747-1-git-send-email-agruenba@redhat.com> References: <1446723580-3747-1-git-send-email-agruenba@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@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 Hook the richacl permission checking function into the vfs. Signed-off-by: Andreas Gruenbacher --- fs/namei.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- fs/posix_acl.c | 6 +++--- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 2eab19e..3822b5e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include "internal.h" @@ -255,7 +256,40 @@ void putname(struct filename *name) __putname(name); } -static int check_acl(struct inode *inode, int mask) +static int check_richacl(struct inode *inode, int mask) +{ +#ifdef CONFIG_FS_RICHACL + struct richacl *acl; + + if (mask & MAY_NOT_BLOCK) { + acl = get_cached_richacl_rcu(inode); + if (!acl) + goto no_acl; + /* no ->get_richacl() calls in RCU mode... */ + if (acl == ACL_NOT_CACHED) + return -ECHILD; + return richacl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); + } + + acl = get_richacl(inode); + if (IS_ERR(acl)) + return PTR_ERR(acl); + if (acl) { + int error = richacl_permission(inode, acl, mask); + richacl_put(acl); + return error; + } +no_acl: +#endif + if (mask & (MAY_DELETE_SELF | MAY_TAKE_OWNERSHIP | + MAY_CHMOD | MAY_SET_TIMES)) { + /* File permission bits cannot grant this. */ + return -EACCES; + } + return -EAGAIN; +} + +static int check_posix_acl(struct inode *inode, int mask) { #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *acl; @@ -290,11 +324,24 @@ static int acl_permission_check(struct inode *inode, int mask) { unsigned int mode = inode->i_mode; + /* + * With POSIX ACLs, the (mode & S_IRWXU) bits exactly match the owner + * permissions, and we can skip checking posix acls for the owner. + * With richacls, the owner may be granted fewer permissions than the + * mode bits seem to suggest (for example, append but not write), and + * we always need to check the richacl. + */ + + if (IS_RICHACL(inode)) { + int error = check_richacl(inode, mask); + if (error != -EAGAIN) + return error; + } if (likely(uid_eq(current_fsuid(), inode->i_uid))) mode >>= 6; else { if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { - int error = check_acl(inode, mask); + int error = check_posix_acl(inode, mask); if (error != -EAGAIN) return error; } diff --git a/fs/posix_acl.c b/fs/posix_acl.c index b0eb1dc..6dbddb6 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c @@ -100,13 +100,13 @@ struct posix_acl *get_acl(struct inode *inode, int type) { struct posix_acl *acl; + if (!IS_POSIXACL(inode)) + return NULL; + acl = get_cached_acl(inode, type); if (acl != ACL_NOT_CACHED) return acl; - if (!IS_POSIXACL(inode)) - return NULL; - /* * A filesystem can force a ACL callback by just never filling the * ACL cache. But normally you'd fill the cache either at inode