]> Pileus Git - ~andy/linux/blobdiff - fs/nfs/nfs4proc.c
NFSv4: Sanity check the server reply in _nfs4_server_capabilities
[~andy/linux] / fs / nfs / nfs4proc.c
index 7e28b5c77cbc832e642dc02efc99187d1b1a77a2..ed2a0e6b9aed35ed2003d2547cb665e4049378ba 100644 (file)
@@ -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;
        }