diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-08-24 10:59:25 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-09-04 14:52:43 -0400 |
commit | 21f498c2f73bd6150d82931f09965826dca0b5f2 (patch) | |
tree | 40885b9d8d338c4f1890f384ad2894f465163e91 /fs/nfs | |
parent | 872ece86ea5c367aa92f44689c2d01a1c767aeb3 (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.c | 20 |
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 | ||
3662 | static int buf_to_pages_noslab(const void *buf, size_t buflen, | 3662 | static 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; |