OSDN Git Service

NFSv4 fix acl retrieval over krb5i/krb5p mounts
authorOlga Kornievskaia <kolga@netapp.com>
Thu, 2 Jan 2020 22:09:54 +0000 (17:09 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 15 Jan 2020 15:54:33 +0000 (10:54 -0500)
For the krb5i and krb5p mount, it was problematic to truncate the
received ACL to the provided buffer because an integrity check
could not be preformed.

Instead, provide enough pages to accommodate the largest buffer
bounded by the largest RPC receive buffer size.

Note: I don't think it's possible for the ACL to be truncated now.
Thus NFS4_ACL_TRUNC flag and related code could be possibly
removed but since I'm unsure, I'm leaving it.

v2: needs +1 page.

Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/nfs4proc.c

index 294d27b..22175b8 100644 (file)
@@ -5601,10 +5601,9 @@ out:
  */
 static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
 {
-       struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
+       struct page **pages;
        struct nfs_getaclargs args = {
                .fh = NFS_FH(inode),
-               .acl_pages = pages,
                .acl_len = buflen,
        };
        struct nfs_getaclres res = {
@@ -5615,11 +5614,19 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
+       unsigned int npages;
        int ret = -ENOMEM, i;
+       struct nfs_server *server = NFS_SERVER(inode);
 
-       if (npages > ARRAY_SIZE(pages))
-               return -ERANGE;
+       if (buflen == 0)
+               buflen = server->rsize;
+
+       npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
+       pages = kmalloc_array(npages, sizeof(struct page *), GFP_NOFS);
+       if (!pages)
+               return -ENOMEM;
+
+       args.acl_pages = pages;
 
        for (i = 0; i < npages; i++) {
                pages[i] = alloc_page(GFP_KERNEL);
@@ -5665,6 +5672,7 @@ out_free:
                        __free_page(pages[i]);
        if (res.acl_scratch)
                __free_page(res.acl_scratch);
+       kfree(pages);
        return ret;
 }