2013-11-04 20:51:23

by Myklebust, Trond

[permalink] [raw]
Subject: [PATCH 1/5] NFSv4.2: Fix a mismatch between Linux labeled NFS and the NFSv4.2 spec

In the spec, the security label attribute id is '80', which means that
it should be bit number 80-64 == 16 in the 3rd word of the bitmap.

Fixes: 4488cc96c581: NFS: Add NFSv4.2 protocol constants
Cc: J. Bruce Fields <[email protected]>
Cc: Steve Dickson <[email protected]>
Cc: [email protected] # 3.11+
Signed-off-by: Trond Myklebust <[email protected]>
---
include/linux/nfs4.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index c56fa8fedce9..bfe6c379a24e 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -395,7 +395,7 @@ enum lock_type4 {
#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30)
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
-#define FATTR4_WORD2_SECURITY_LABEL (1UL << 17)
+#define FATTR4_WORD2_SECURITY_LABEL (1UL << 16)

/* MDS threshold bitmap bits */
#define THRESHOLD_RD (1UL << 0)
--
1.8.3.1



2013-11-04 21:27:12

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH 1/5] NFSv4.2: Fix a mismatch between Linux labeled NFS and the NFSv4.2 spec

On Mon, Nov 04, 2013 at 03:51:08PM -0500, Trond Myklebust wrote:
> In the spec, the security label attribute id is '80', which means that
> it should be bit number 80-64 == 16 in the 3rd word of the bitmap.

And the same error got copied to wireshark.

https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=9383

--b.

2013-11-04 20:51:21

by Myklebust, Trond

[permalink] [raw]
Subject: [PATCH 3/5] NFSv4.2: encode_readdir - only ask for labels when doing readdirplus

Currently, if the server is doing NFSv4.2 and supports labeled NFS, then
our on-the-wire READDIR request ends up asking for the label information,
which is then ignored unless we're doing readdirplus.
This patch ensures that READDIR doesn't ask the server for label information
at all unless the readdir->bitmask contains the FATTR4_WORD2_SECURITY_LABEL
attribute, and the readdir->plus flag is set.

While we're at it, optimise away the 3rd bitmap field if it is zero.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/nfs4xdr.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index f903389d90f1..5be2868c02f1 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -105,12 +105,8 @@ static int nfs4_stat_to_errno(int);
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
/* PI(4 bytes) + LFS(4 bytes) + 1(for null terminator?) + MAXLABELLEN */
#define nfs4_label_maxsz (4 + 4 + 1 + XDR_QUADLEN(NFS4_MAXLABELLEN))
-#define encode_readdir_space 24
-#define encode_readdir_bitmask_sz 3
#else
#define nfs4_label_maxsz 0
-#define encode_readdir_space 20
-#define encode_readdir_bitmask_sz 2
#endif
/* We support only one layout type per file system */
#define decode_mdsthreshold_maxsz (1 + 1 + nfs4_fattr_bitmap_maxsz + 1 + 8)
@@ -1581,6 +1577,8 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
};
uint32_t dircount = readdir->count >> 1;
__be32 *p, verf[2];
+ uint32_t attrlen = 0;
+ unsigned int i;

if (readdir->plus) {
attrs[0] |= FATTR4_WORD0_TYPE|FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE|
@@ -1589,26 +1587,27 @@ static void encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
FATTR4_WORD1_OWNER_GROUP|FATTR4_WORD1_RAWDEV|
FATTR4_WORD1_SPACE_USED|FATTR4_WORD1_TIME_ACCESS|
FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+ attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
dircount >>= 1;
}
/* Use mounted_on_fileid only if the server supports it */
if (!(readdir->bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID))
attrs[0] |= FATTR4_WORD0_FILEID;
+ for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+ attrs[i] &= readdir->bitmask[i];
+ if (attrs[i] != 0)
+ attrlen = i+1;
+ }

encode_op_hdr(xdr, OP_READDIR, decode_readdir_maxsz, hdr);
encode_uint64(xdr, readdir->cookie);
encode_nfs4_verifier(xdr, &readdir->verifier);
- p = reserve_space(xdr, encode_readdir_space);
+ p = reserve_space(xdr, 12 + (attrlen << 2));
*p++ = cpu_to_be32(dircount);
*p++ = cpu_to_be32(readdir->count);
- *p++ = cpu_to_be32(encode_readdir_bitmask_sz);
- *p++ = cpu_to_be32(attrs[0] & readdir->bitmask[0]);
- *p = cpu_to_be32(attrs[1] & readdir->bitmask[1]);
- if (encode_readdir_bitmask_sz > 2) {
- if (hdr->minorversion > 1)
- attrs[2] |= FATTR4_WORD2_SECURITY_LABEL;
- p++, *p++ = cpu_to_be32(attrs[2] & readdir->bitmask[2]);
- }
+ *p++ = cpu_to_be32(attrlen);
+ for (i = 0; i < attrlen; i++)
+ *p++ = cpu_to_be32(attrs[i]);
memcpy(verf, readdir->verifier.data, sizeof(verf));

dprintk("%s: cookie = %llu, verifier = %08x:%08x, bitmap = %08x:%08x:%08x\n",
--
1.8.3.1


2013-11-04 21:00:54

by Myklebust, Trond

[permalink] [raw]
Subject: Re: [PATCH 2/5] NFS: __nfs_revalidate_inode() - use the nfs4_label to update file security info


On Nov 4, 2013, at 15:51, Trond Myklebust <[email protected]> wrote:

> Currently, we just discard the nfs4_label information, instead of using it
> to update the file LSM security info.
>
> Signed-off-by: Trond Myklebust <[email protected]>

I forgot to add a "Reported-by: Jeff Layton <[email protected]>?. Fixed now...

> ---
> fs/nfs/inode.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> index 471ba59c42f9..09d4df5f588a 100644
> --- a/fs/nfs/inode.c
> +++ b/fs/nfs/inode.c
> @@ -920,6 +920,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
> goto err_out;
> }
>
> + nfs_setsecurity(inode, fattr, label);
> if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
> nfs_zap_acl_cache(inode);
>
> --
> 1.8.3.1
>

--
Trond Myklebust
Linux NFS client maintainer

NetApp
[email protected]
http://www.netapp.com


2013-11-04 20:51:22

by Myklebust, Trond

[permalink] [raw]
Subject: [PATCH 4/5] NFSv4: Sanity check the server reply in _nfs4_server_capabilities

We don't want to be setting capabilities and/or requesting attributes
that are not appropriate for the NFSv4 minor version.

- Ensure that we clear the NFS_CAP_SECURITY_LABEL capability when appropriate
- Ensure that we limit the attribute bitmasks to the mounted_on_fileid
attribute and less for NFSv4.0
- Ensure that we limit the attribute bitmasks to suppattr_exclcreat and
less for NFSv4.1
- Ensure that we limit it to change_sec_label or less for NFSv4.2

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/nfs4proc.c | 25 ++++++++++++++++++++-----
include/linux/nfs4.h | 2 ++
2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 7e28b5c77cbc..ed2a0e6b9aed 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2706,6 +2706,10 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
nfs4_close_state(ctx->state, ctx->mode);
}

+#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
+#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
+#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_CHANGE_SECURITY_LABEL - 1UL)
+
static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{
struct nfs4_server_caps_arg args = {
@@ -2721,12 +2725,25 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f

status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
if (status == 0) {
+ /* Sanity check the server answers */
+ switch (server->nfs_client->cl_minorversion) {
+ case 0:
+ res.attr_bitmask[1] &= FATTR4_WORD1_NFS40_MASK;
+ res.attr_bitmask[2] = 0;
+ break;
+ case 1:
+ res.attr_bitmask[2] &= FATTR4_WORD2_NFS41_MASK;
+ break;
+ case 2:
+ res.attr_bitmask[2] &= FATTR4_WORD2_NFS42_MASK;
+ }
memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS|
NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|
NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
- NFS_CAP_CTIME|NFS_CAP_MTIME);
+ NFS_CAP_CTIME|NFS_CAP_MTIME|
+ NFS_CAP_SECURITY_LABEL);
if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
server->caps |= NFS_CAP_ACLS;
if (res.has_links != 0)
@@ -2755,14 +2772,12 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
#endif
memcpy(server->attr_bitmask_nl, res.attr_bitmask,
sizeof(server->attr_bitmask));
+ server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;

- if (server->caps & NFS_CAP_SECURITY_LABEL) {
- server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
- res.attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
- }
memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
+ server->cache_consistency_bitmask[2] = 0;
server->acl_bitmask = res.acl_bitmask;
server->fh_expire_type = res.fh_expire_type;
}
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index bfe6c379a24e..c6f41b616965 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -396,6 +396,8 @@ enum lock_type4 {
#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1)
#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4)
#define FATTR4_WORD2_SECURITY_LABEL (1UL << 16)
+#define FATTR4_WORD2_CHANGE_SECURITY_LABEL \
+ (1UL << 17)

/* MDS threshold bitmap bits */
#define THRESHOLD_RD (1UL << 0)
--
1.8.3.1


2013-11-04 20:51:24

by Myklebust, Trond

[permalink] [raw]
Subject: [PATCH 5/5] NFSv4.2: Remove redundant checks in nfs_setsecurity+nfs4_label_init_security

We already check for nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)
in nfs4_label_alloc()
We check the minor version in _nfs4_server_capabilities before setting
NFS_CAP_SECURITY_LABEL.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/inode.c | 6 ------
fs/nfs/nfs4proc.c | 3 ---
2 files changed, 9 deletions(-)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 09d4df5f588a..4ae41a26844f 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -274,12 +274,6 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr,
if (label == NULL)
return;

- if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL) == 0)
- return;
-
- if (NFS_SERVER(inode)->nfs_client->cl_minorversion < 2)
- return;
-
if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) {
error = security_inode_notifysecctx(inode, label->label,
label->len);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ed2a0e6b9aed..5ab33c0792df 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -105,9 +105,6 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0)
return NULL;

- if (NFS_SERVER(dir)->nfs_client->cl_minorversion < 2)
- return NULL;
-
err = security_dentry_init_security(dentry, sattr->ia_mode,
&dentry->d_name, (void **)&label->label, &label->len);
if (err == 0)
--
1.8.3.1


2013-11-04 21:24:22

by Jeff Layton

[permalink] [raw]
Subject: Re: [PATCH 2/5] NFS: __nfs_revalidate_inode() - use the nfs4_label to update file security info

On Mon, 4 Nov 2013 21:00:46 +0000
"Myklebust, Trond" <[email protected]> wrote:

>
> On Nov 4, 2013, at 15:51, Trond Myklebust <[email protected]> wrote:
>
> > Currently, we just discard the nfs4_label information, instead of using it
> > to update the file LSM security info.
> >
> > Signed-off-by: Trond Myklebust <[email protected]>
>
> I forgot to add a "Reported-by: Jeff Layton <[email protected]>?. Fixed now...
>
> > ---
> > fs/nfs/inode.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
> > index 471ba59c42f9..09d4df5f588a 100644
> > --- a/fs/nfs/inode.c
> > +++ b/fs/nfs/inode.c
> > @@ -920,6 +920,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
> > goto err_out;
> > }
> >
> > + nfs_setsecurity(inode, fattr, label);
> > if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
> > nfs_zap_acl_cache(inode);
> >
> > --
> > 1.8.3.1
> >
>

No worries -- looks fine.

Out of curiousity, is there a reason to call nfs_setsecurity prior to
zapping the ACL cache? The patch I had proposed did it afterward, but I
didn't think it mattered much either way...

Thanks,
--
Jeff Layton <[email protected]>

2013-11-04 20:51:20

by Myklebust, Trond

[permalink] [raw]
Subject: [PATCH 2/5] NFS: __nfs_revalidate_inode() - use the nfs4_label to update file security info

Currently, we just discard the nfs4_label information, instead of using it
to update the file LSM security info.

Signed-off-by: Trond Myklebust <[email protected]>
---
fs/nfs/inode.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 471ba59c42f9..09d4df5f588a 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -920,6 +920,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
goto err_out;
}

+ nfs_setsecurity(inode, fattr, label);
if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
nfs_zap_acl_cache(inode);

--
1.8.3.1


2013-11-04 21:39:01

by Myklebust, Trond

[permalink] [raw]
Subject: Re: [PATCH 2/5] NFS: __nfs_revalidate_inode() - use the nfs4_label to update file security info


On Nov 4, 2013, at 16:24, Jeff Layton <[email protected]> wrote:

> On Mon, 4 Nov 2013 21:00:46 +0000
> "Myklebust, Trond" <[email protected]> wrote:
>
>>
>> On Nov 4, 2013, at 15:51, Trond Myklebust <[email protected]> wrote:
>>
>>> Currently, we just discard the nfs4_label information, instead of using it
>>> to update the file LSM security info.
>>>
>>> Signed-off-by: Trond Myklebust <[email protected]>
>>
>> I forgot to add a "Reported-by: Jeff Layton <[email protected]>?. Fixed now...
>>
>>> ---
>>> fs/nfs/inode.c | 1 +
>>> 1 file changed, 1 insertion(+)
>>>
>>> diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
>>> index 471ba59c42f9..09d4df5f588a 100644
>>> --- a/fs/nfs/inode.c
>>> +++ b/fs/nfs/inode.c
>>> @@ -920,6 +920,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
>>> goto err_out;
>>> }
>>>
>>> + nfs_setsecurity(inode, fattr, label);
>>> if (nfsi->cache_validity & NFS_INO_INVALID_ACL)
>>> nfs_zap_acl_cache(inode);
>>>
>>> --
>>> 1.8.3.1
>>>
>>
>
> No worries -- looks fine.
>
> Out of curiousity, is there a reason to call nfs_setsecurity prior to
> zapping the ACL cache? The patch I had proposed did it afterward, but I
> didn't think it mattered much either way...

It shouldn?t make a huge difference, no; either way, there be plenty races here?

Trond