From patchwork Tue Aug 4 11:53:29 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: 6937261 Return-Path: X-Original-To: patchwork-linux-nfs@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 AA6B99F38B for ; Tue, 4 Aug 2015 12:01:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 670DB20452 for ; Tue, 4 Aug 2015 12:01:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 4C6F320456 for ; Tue, 4 Aug 2015 12:01:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933637AbbHDMAq (ORCPT ); Tue, 4 Aug 2015 08:00:46 -0400 Received: from mail-wi0-f170.google.com ([209.85.212.170]:33872 "EHLO mail-wi0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S933767AbbHDLzj (ORCPT ); Tue, 4 Aug 2015 07:55:39 -0400 Received: by wibud3 with SMTP id ud3so173569308wib.1; Tue, 04 Aug 2015 04:55:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=JGJiHI1CnkrC/vjIoRWwA7yxTzu8eqDoS763ApnORJU=; b=A1swOVvS/0/DDrSVRYrf+WqK9n3x/UZFG5F7xtWPAMnbyOTB+Re4Jzfv4PFSJDLp+N cLEq+3iomVtUdahyPs4JcV3mAuTmbpPjxWD93kPwY+M/0TDOzDL/csh9EzPzZ2VhakJG UGjs34PNfeRsSS9B8NQpCuL53RHSD9BD28kbD5XBsQ2m09BwFLro0WAkcfVdQQRa6uz0 S1HU4tvE8XvJOdcZ6YFfVLeTS667ZENfc18nzodo410AAksd1jUAQlEweKAoBc+SJxPN Yrh0ANka6K6OTLgSgazKNS9qd1/neGcuBofATwyqeSkC9iLhWOy2s0gcnEhn19LO0vxG tW+Q== X-Received: by 10.180.208.81 with SMTP id mc17mr7608611wic.93.1438689337102; Tue, 04 Aug 2015 04:55:37 -0700 (PDT) Received: from schleppi.home.com (p54980F84.dip0.t-ipconnect.de. [84.152.15.132]) by smtp.gmail.com with ESMTPSA id u7sm2018458wif.3.2015.08.04.04.55.34 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Aug 2015 04:55:36 -0700 (PDT) From: Andreas Gruenbacher X-Google-Original-From: Andreas Gruenbacher To: linux-kernel@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org, linux-nfs@vger.kernel.org, linux-api@vger.kernel.org, linux-cifs@vger.kernel.org, linux-security-module@vger.kernel.org, Andreas Gruenbacher Subject: [RFC v6 31/40] nfsd: Add support for the v4.1 dacl attribute Date: Tue, 4 Aug 2015 13:53:29 +0200 Message-Id: <1438689218-6921-32-git-send-email-agruenba@redhat.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1438689218-6921-1-git-send-email-agruenba@redhat.com> References: <1438689218-6921-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=-4.4 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=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 Richacls support the Automatic Inheritance permission propagation mechanism as specified in NFSv4.1. Over NFS, this requires support for the dacl attribute: compared to the acl attribute, the dacl attribute has an additional flags field which indicates when Automatic Inheritance is in use. The server will only indicate dacl attribute support in protocol version 4.1 and later, on file systems with richacl support. This commit also adds support for the NFSv4.1 NFS4_ACE_WRITE_RETENTION and NFS4_ACE_WRITE_RETENTION_HOLD ACL permissions. Signed-off-by: Andreas Gruenbacher --- fs/nfsd/nfs4proc.c | 2 + fs/nfsd/nfs4xdr.c | 219 ++++++++++++++++++++++++++++++---------------- fs/nfsd/nfsd.h | 6 +- include/linux/nfs4.h | 1 + include/uapi/linux/nfs4.h | 3 +- 5 files changed, 155 insertions(+), 76 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 9f8f0a8..ef9e6cd 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1804,6 +1804,8 @@ static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp, ret += NFS4_FHSIZE + 4; bmap0 &= ~FATTR4_WORD0_FILEHANDLE; } + if (bmap1 & FATTR4_WORD1_DACL) + return svc_max_payload(rqstp); if (bmap2 & FATTR4_WORD2_SECURITY_LABEL) { ret += NFS4_MAXLABELLEN + 12; bmap2 &= ~FATTR4_WORD2_SECURITY_LABEL; diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 8628065..a7da454 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -301,6 +301,68 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) DECODE_TAIL; } +static unsigned int +nfsd4_ace_mask(int minorversion) +{ + return minorversion == 0 ? NFS40_ACE_MASK_ALL : NFS4_ACE_MASK_ALL; +} + +static __be32 +nfsd4_decode_acl_entries(struct nfsd4_compoundargs *argp, struct richacl **acl, + unsigned short flags_mask, unsigned int ace_mask, + int *plen) +{ + struct richace *ace; + u32 dummy32; + char *buf; + int len = 0; + + DECODE_HEAD; + + flags_mask &= RICHACE_VALID_FLAGS & ~RICHACE_SPECIAL_WHO; + + READ_BUF(4); len += 4; + dummy32 = be32_to_cpup(p++); + + if (dummy32 > NFSD4_ACL_MAX) + return nfserr_fbig; + + *acl = svcxdr_alloc_richacl(argp, dummy32); + if (*acl == NULL) + return nfserr_jukebox; + + richacl_for_each_entry(ace, *acl) { + READ_BUF(16); len += 16; + + dummy32 = be32_to_cpup(p++); + if (dummy32 > RICHACE_ACCESS_DENIED_ACE_TYPE) + return nfserr_inval; + ace->e_type = dummy32; + + dummy32 = be32_to_cpup(p++); + if (dummy32 & ~flags_mask) + return nfserr_inval; + ace->e_flags = dummy32; + + dummy32 = be32_to_cpup(p++); + if (dummy32 & ~ace_mask) + return nfserr_inval; + ace->e_mask = dummy32; + + dummy32 = be32_to_cpup(p++); + READ_BUF(dummy32); + len += XDR_QUADLEN(dummy32) << 2; + READMEM(buf, dummy32); + status = nfsd4_decode_ace_who(ace, argp->rqstp, + buf, dummy32); + if (status) + return status; + } + *plen += len; + + DECODE_TAIL; +} + static __be32 nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr, struct richacl **acl, @@ -312,6 +374,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, DECODE_HEAD; iattr->ia_valid = 0; + *acl = NULL; if ((status = nfsd4_decode_bitmap(argp, bmval))) return status; @@ -325,50 +388,18 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, iattr->ia_valid |= ATTR_SIZE; } if (bmval[0] & FATTR4_WORD0_ACL) { - u32 nace; - struct richace *ace; - - READ_BUF(4); len += 4; - nace = be32_to_cpup(p++); - - if (nace > NFSD4_ACL_MAX) - return nfserr_fbig; + if (bmval[1] & FATTR4_WORD1_DACL) + return nfserr_inval; - *acl = svcxdr_alloc_richacl(argp, nace); - if (*acl == NULL) + status = nfsd4_decode_acl_entries(argp, acl, + ~NFS4_ACE_INHERITED_ACE, + nfsd4_ace_mask(argp->minorversion), + &len); + if (status) + return status; + else if (*acl == NULL) return nfserr_jukebox; - - richacl_for_each_entry(ace, *acl) { - READ_BUF(16); len += 16; - - dummy32 = be32_to_cpup(p++); - if (dummy32 > RICHACE_ACCESS_DENIED_ACE_TYPE) - return nfserr_inval; - ace->e_type = dummy32; - - dummy32 = be32_to_cpup(p++); - if (dummy32 & (~RICHACE_VALID_FLAGS | - RICHACE_INHERITED_ACE | - RICHACE_SPECIAL_WHO)) - return nfserr_inval; - ace->e_flags = dummy32; - - dummy32 = be32_to_cpup(p++); - if (dummy32 & ~NFS4_ACE_MASK_ALL) - return nfserr_inval; - ace->e_mask = dummy32; - - dummy32 = be32_to_cpup(p++); - READ_BUF(dummy32); - len += XDR_QUADLEN(dummy32) << 2; - READMEM(buf, dummy32); - status = nfsd4_decode_ace_who(ace, argp->rqstp, - buf, dummy32); - if (status) - return status; - } - } else - *acl = NULL; + } if (bmval[1] & FATTR4_WORD1_MODE) { READ_BUF(4); len += 4; @@ -436,6 +467,22 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, goto xdr_error; } } + if (bmval[1] & FATTR4_WORD1_DACL) { + READ_BUF(4); + len += 4; + dummy32 = be32_to_cpup(p++); + if (dummy32 & (~RICHACL_VALID_FLAGS | RICHACL_MASKED)) + return nfserr_inval; + status = nfsd4_decode_acl_entries(argp, acl, + ~0, + nfsd4_ace_mask(argp->minorversion), + &len); + if (status) + return status; + else if (*acl == NULL) + return nfserr_jukebox; + (*acl)->a_flags = dummy32; + } label->len = 0; #ifdef CONFIG_NFSD_V4_SECURITY_LABEL @@ -2216,6 +2263,42 @@ static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) return err; } +static __be32 nfsd4_encode_acl_entries(struct xdr_stream *xdr, + struct richacl *acl, struct svc_rqst *rqstp, + unsigned short flags_mask, unsigned int ace_mask) +{ + __be32 *p; + + flags_mask &= ~RICHACE_SPECIAL_WHO; + + p = xdr_reserve_space(xdr, 4); + if (!p) + return nfserr_resource; + + if (acl == NULL) { + *p++ = cpu_to_be32(0); + } else { + struct richace *ace; + + *p++ = cpu_to_be32(acl->a_count); + + richacl_for_each_entry(ace, acl) { + __be32 status; + + p = xdr_reserve_space(xdr, 4*3); + if (!p) + return nfserr_resource; + *p++ = cpu_to_be32(ace->e_type); + *p++ = cpu_to_be32(ace->e_flags & flags_mask); + *p++ = cpu_to_be32(ace->e_mask & ace_mask); + status = nfsd4_encode_ace_who(xdr, rqstp, ace); + if (status) + return status; + } + } + return 0; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -2287,15 +2370,16 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, goto out; fhp = tempfh; } - if (bmval0 & FATTR4_WORD0_ACL) { + if ((bmval0 & FATTR4_WORD0_ACL) || (bmval1 & FATTR4_WORD1_DACL)) { acl = nfsd4_get_acl(rqstp, dentry); if (IS_ERR(acl)) { err = PTR_ERR(acl); acl = NULL; } - if (err == -EOPNOTSUPP) + if (err == -EOPNOTSUPP) { bmval0 &= ~FATTR4_WORD0_ACL; - else if (err == -EINVAL) { + bmval1 &= ~FATTR4_WORD1_DACL; + } else if (err == -EINVAL) { status = nfserr_attrnotsupp; goto out; } else if (err != 0) @@ -2353,6 +2437,8 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, if (!IS_ACL(d_inode(dentry))) word0 &= ~FATTR4_WORD0_ACL; + if (!IS_RICHACL(d_inode(dentry))) + word1 &= ~FATTR4_WORD1_DACL; if (!contextsupport) word2 &= ~FATTR4_WORD2_SECURITY_LABEL; if (!word2) { @@ -2466,35 +2552,12 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, *p++ = cpu_to_be32(rdattr_err); } if (bmval0 & FATTR4_WORD0_ACL) { - struct richace *ace; - - if (acl == NULL) { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - - *p++ = cpu_to_be32(0); - goto out_acl; - } - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(acl->a_count); - - richacl_for_each_entry(ace, acl) { - p = xdr_reserve_space(xdr, 4*3); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(ace->e_type); - *p++ = cpu_to_be32(ace->e_flags & - ~(RICHACE_SPECIAL_WHO | RICHACE_INHERITED_ACE)); - *p++ = cpu_to_be32(ace->e_mask & NFS4_ACE_MASK_ALL); - status = nfsd4_encode_ace_who(xdr, rqstp, ace); - if (status) - goto out; - } + status = nfsd4_encode_acl_entries(xdr, acl, rqstp, + ~NFS4_ACE_INHERITED_ACE, + nfsd4_ace_mask(minorversion)); + if (status) + goto out; } -out_acl: if (bmval0 & FATTR4_WORD0_ACLSUPPORT) { p = xdr_reserve_space(xdr, 4); if (!p) @@ -2703,6 +2766,16 @@ out_acl: get_parent_attributes(exp, &stat); p = xdr_encode_hyper(p, stat.ino); } + if (bmval1 & FATTR4_WORD1_DACL) { + p = xdr_reserve_space(xdr, 4); + if (!p) + goto out_resource; + *p++ = cpu_to_be32(acl->a_flags); + status = nfsd4_encode_acl_entries(xdr, acl, rqstp, + ~0, nfsd4_ace_mask(minorversion)); + if (status) + goto out; + } #ifdef CONFIG_NFSD_PNFS if ((bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) || (bmval2 & FATTR4_WORD2_LAYOUT_TYPES)) { diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index cf98052..cb5c3ed 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -339,7 +339,8 @@ void nfsd_lockd_shutdown(void); NFSD4_SUPPORTED_ATTRS_WORD0 #define NFSD4_1_SUPPORTED_ATTRS_WORD1 \ - (NFSD4_SUPPORTED_ATTRS_WORD1 | PNFSD_SUPPORTED_ATTRS_WORD1) + (NFSD4_SUPPORTED_ATTRS_WORD1 | PNFSD_SUPPORTED_ATTRS_WORD1 | \ + FATTR4_WORD1_DACL) #define NFSD4_1_SUPPORTED_ATTRS_WORD2 \ (NFSD4_SUPPORTED_ATTRS_WORD2 | PNFSD_SUPPORTED_ATTRS_WORD2 | \ @@ -386,7 +387,8 @@ static inline u32 nfsd_suppattrs2(u32 minorversion) (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) #define NFSD_WRITEABLE_ATTRS_WORD1 \ (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ - | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) + | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET \ + | FATTR4_WORD1_DACL) #ifdef CONFIG_NFSD_V4_SECURITY_LABEL #define NFSD_WRITEABLE_ATTRS_WORD2 FATTR4_WORD2_SECURITY_LABEL #else diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h index 992ddc4..1bd4aea 100644 --- a/include/linux/nfs4.h +++ b/include/linux/nfs4.h @@ -394,6 +394,7 @@ enum lock_type4 { #define FATTR4_WORD1_TIME_MODIFY (1UL << 21) #define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22) #define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23) +#define FATTR4_WORD1_DACL (1UL << 26) #define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30) #define FATTR4_WORD2_LAYOUT_TYPES (1UL << 0) #define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h index 2119c7c..64e4c6c 100644 --- a/include/uapi/linux/nfs4.h +++ b/include/uapi/linux/nfs4.h @@ -121,7 +121,8 @@ #define NFS4_ACE_GENERIC_READ 0x00120081 #define NFS4_ACE_GENERIC_WRITE 0x00160106 #define NFS4_ACE_GENERIC_EXECUTE 0x001200A0 -#define NFS4_ACE_MASK_ALL 0x001F01FF +#define NFS40_ACE_MASK_ALL 0x001F01FF +#define NFS4_ACE_MASK_ALL 0x001F07FF #define EXCHGID4_FLAG_SUPP_MOVED_REFER 0x00000001 #define EXCHGID4_FLAG_SUPP_MOVED_MIGR 0x00000002