From patchwork Wed Jun 24 21:57:02 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Andreas_Gr=C3=BCnbacher?= X-Patchwork-Id: 6670741 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 0FA65C05AC for ; Wed, 24 Jun 2015 22:04:32 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0FDE120547 for ; Wed, 24 Jun 2015 22:04:31 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 163EA2056E for ; Wed, 24 Jun 2015 22:04:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932117AbbFXWE1 (ORCPT ); Wed, 24 Jun 2015 18:04:27 -0400 Received: from mail-wi0-f180.google.com ([209.85.212.180]:34079 "EHLO mail-wi0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752235AbbFXV5x (ORCPT ); Wed, 24 Jun 2015 17:57:53 -0400 Received: by wicnd19 with SMTP id nd19so1112531wic.1; Wed, 24 Jun 2015 14:57:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:subject:date:message-id:in-reply-to:references; bh=cLpWrIgjg2mFCzkxXuLkRdX7brlaifzgVkDCh2w/5qk=; b=l+MQV30vA3CWTqQ3AA9UntTfRLhHWKQXRNvpVWuYaSOXSwshEPnF4sreKVpQnQDKis IX/PSKj3x2xR8ZTZMNUd8RF2cqYuY4bBZ7puE6rhoSXQfQ0oKhPQWDcPMlAQd4B0czmP eO9d5RvCYqhTFrjXfVPo1dWMl0E5Y6dc3rsSbFEFWB2Lpsh4ftLhuieo0MMMKzJuRzvm R4RU163+t89T+S1zqhhjK7Dc66JOcWs+guh9J3/CDvtBGcb87EgFYxTX9HEdf/T8+1aK JoCkzw1wkUBxTgpS+n9+6fItokwPT9AS0EYSf8PGCjyXqGzxm+ObKDsOr5bal+oVLzQG q+Og== X-Received: by 10.181.29.201 with SMTP id jy9mr8707781wid.84.1435183070494; Wed, 24 Jun 2015 14:57:50 -0700 (PDT) Received: from nuc.home.com (80-110-112-232.cgn.dynamic.surfer.at. [80.110.112.232]) by mx.google.com with ESMTPSA id lu5sm42559880wjb.9.2015.06.24.14.57.48 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 24 Jun 2015 14:57:49 -0700 (PDT) From: Andreas Gruenbacher X-Google-Original-From: Andreas Gruenbacher To: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-api@vger.kernel.org, samba-technical@lists.samba.org, linux-security-module@vger.kernel.org Subject: [RFC v4 13/31] richacl: Check if an acl is equivalent to a file mode Date: Wed, 24 Jun 2015 23:57:02 +0200 Message-Id: <1435183040-22726-14-git-send-email-agruenba@redhat.com> X-Mailer: git-send-email 2.4.2 In-Reply-To: <1435183040-22726-1-git-send-email-agruenba@redhat.com> References: <1435183040-22726-1-git-send-email-agruenba@redhat.com> Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org X-Spam-Status: No, score=-5.7 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SUSPICIOUS_RECIPS, T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=ham 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 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 --- fs/richacl_base.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/richacl.h | 1 + 2 files changed, 96 insertions(+) diff --git a/fs/richacl_base.c b/fs/richacl_base.c index 5da092b..1ef3bf3 100644 --- a/fs/richacl_base.c +++ b/fs/richacl_base.c @@ -365,3 +365,98 @@ richacl_chmod(struct richacl *acl, mode_t mode) return clone; } EXPORT_SYMBOL_GPL(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, mode_t *mode_p) +{ + mode_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_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) { + owner.allowed = acl->a_owner_mask; + group.allowed &= acl->a_group_mask; + everyone.allowed = acl->a_other_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 1b66cd5..2357d6b 100644 --- a/include/linux/richacl.h +++ b/include/linux/richacl.h @@ -307,6 +307,7 @@ extern unsigned int richacl_mode_to_mask(mode_t); extern unsigned int richacl_want_to_mask(unsigned int); extern void richacl_compute_max_masks(struct richacl *, kuid_t); extern struct richacl *richacl_chmod(struct richacl *, mode_t); +extern int richacl_equiv_mode(const struct richacl *, mode_t *); /* richacl_inode.c */ extern int richacl_permission(struct inode *, const struct richacl *, int);