mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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>
This commit is contained in:
parent
872ece86ea
commit
21f498c2f7
1 changed files with 11 additions and 9 deletions
|
@ -3653,11 +3653,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
|
||||||
&& (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
|
&& (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that
|
/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
|
||||||
* it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on
|
* it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
|
||||||
* the stack.
|
* the stack.
|
||||||
*/
|
*/
|
||||||
#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
|
#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
|
||||||
|
|
||||||
static int buf_to_pages_noslab(const void *buf, size_t buflen,
|
static int buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||||
struct page **pages, unsigned int *pgbase)
|
struct page **pages, unsigned int *pgbase)
|
||||||
|
@ -3668,7 +3668,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||||
spages = pages;
|
spages = pages;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
|
len = min_t(size_t, PAGE_SIZE, buflen);
|
||||||
newpage = alloc_page(GFP_KERNEL);
|
newpage = alloc_page(GFP_KERNEL);
|
||||||
|
|
||||||
if (newpage == NULL)
|
if (newpage == NULL)
|
||||||
|
@ -3782,17 +3782,16 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
|
||||||
.rpc_argp = &args,
|
.rpc_argp = &args,
|
||||||
.rpc_resp = &res,
|
.rpc_resp = &res,
|
||||||
};
|
};
|
||||||
int ret = -ENOMEM, npages, i;
|
unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
|
||||||
|
int ret = -ENOMEM, i;
|
||||||
size_t acl_len = 0;
|
size_t acl_len = 0;
|
||||||
|
|
||||||
npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
|
|
||||||
/* As long as we're doing a round trip to the server anyway,
|
/* As long as we're doing a round trip to the server anyway,
|
||||||
* let's be prepared for a page of acl data. */
|
* let's be prepared for a page of acl data. */
|
||||||
if (npages == 0)
|
if (npages == 0)
|
||||||
npages = 1;
|
npages = 1;
|
||||||
|
if (npages > ARRAY_SIZE(pages))
|
||||||
/* Add an extra page to handle the bitmap returned */
|
return -ERANGE;
|
||||||
npages++;
|
|
||||||
|
|
||||||
for (i = 0; i < npages; i++) {
|
for (i = 0; i < npages; i++) {
|
||||||
pages[i] = alloc_page(GFP_KERNEL);
|
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
|
||||||
.rpc_argp = &arg,
|
.rpc_argp = &arg,
|
||||||
.rpc_resp = &res,
|
.rpc_resp = &res,
|
||||||
};
|
};
|
||||||
|
unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
|
||||||
if (!nfs4_server_supports_acls(server))
|
if (!nfs4_server_supports_acls(server))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
if (npages > ARRAY_SIZE(pages))
|
||||||
|
return -ERANGE;
|
||||||
i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
|
i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return i;
|
return i;
|
||||||
|
|
Loading…
Add table
Reference in a new issue