aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-08-24 10:59:25 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-04 14:52:43 -0400
commit21f498c2f73bd6150d82931f09965826dca0b5f2 (patch)
tree40885b9d8d338c4f1890f384ad2894f465163e91 /fs/nfs
parent872ece86ea5c367aa92f44689c2d01a1c767aeb3 (diff)
NFSv4: Fix range checking in __nfs4_get_acl_uncached and __nfs4_proc_set_acl
Ensure that the user supplied buffer size doesn't cause us to overflow the 'pages' array. Also fix up some confusion between the use of PAGE_SIZE and PAGE_CACHE_SIZE when calculating buffer sizes. We're not using the page cache for anything here. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 86b4c7361036..6b94f2d52532 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3653,11 +3653,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
3653 && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL); 3653 && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
3654} 3654}
3655 3655
3656/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that 3656/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
3657 * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on 3657 * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
3658 * the stack. 3658 * the stack.
3659 */ 3659 */
3660#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT) 3660#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
3661 3661
3662static int buf_to_pages_noslab(const void *buf, size_t buflen, 3662static int buf_to_pages_noslab(const void *buf, size_t buflen,
3663 struct page **pages, unsigned int *pgbase) 3663 struct page **pages, unsigned int *pgbase)
@@ -3668,7 +3668,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen,
3668 spages = pages; 3668 spages = pages;
3669 3669
3670 do { 3670 do {
3671 len = min_t(size_t, PAGE_CACHE_SIZE, buflen); 3671 len = min_t(size_t, PAGE_SIZE, buflen);
3672 newpage = alloc_page(GFP_KERNEL); 3672 newpage = alloc_page(GFP_KERNEL);
3673 3673
3674 if (newpage == NULL) 3674 if (newpage == NULL)
@@ -3782,17 +3782,16 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
3782 .rpc_argp = &args, 3782 .rpc_argp = &args,
3783 .rpc_resp = &res, 3783 .rpc_resp = &res,
3784 }; 3784 };
3785 int ret = -ENOMEM, npages, i; 3785 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
3786 int ret = -ENOMEM, i;
3786 size_t acl_len = 0; 3787 size_t acl_len = 0;
3787 3788
3788 npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
3789 /* As long as we're doing a round trip to the server anyway, 3789 /* As long as we're doing a round trip to the server anyway,
3790 * let's be prepared for a page of acl data. */ 3790 * let's be prepared for a page of acl data. */
3791 if (npages == 0) 3791 if (npages == 0)
3792 npages = 1; 3792 npages = 1;
3793 3793 if (npages > ARRAY_SIZE(pages))
3794 /* Add an extra page to handle the bitmap returned */ 3794 return -ERANGE;
3795 npages++;
3796 3795
3797 for (i = 0; i < npages; i++) { 3796 for (i = 0; i < npages; i++) {
3798 pages[i] = alloc_page(GFP_KERNEL); 3797 pages[i] = alloc_page(GFP_KERNEL);
@@ -3891,10 +3890,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
3891 .rpc_argp = &arg, 3890 .rpc_argp = &arg,
3892 .rpc_resp = &res, 3891 .rpc_resp = &res,
3893 }; 3892 };
3893 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
3894 int ret, i; 3894 int ret, i;
3895 3895
3896 if (!nfs4_server_supports_acls(server)) 3896 if (!nfs4_server_supports_acls(server))
3897 return -EOPNOTSUPP; 3897 return -EOPNOTSUPP;
3898 if (npages > ARRAY_SIZE(pages))
3899 return -ERANGE;
3898 i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase); 3900 i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
3899 if (i < 0) 3901 if (i < 0)
3900 return i; 3902 return i;