diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-04-10 09:26:35 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-01 01:17:07 -0400 |
commit | 8d5658c949e6d89edc579a1f112aeee3bc232a8e (patch) | |
tree | f206d3f6809eeb0ca23c1999cf79aa294968b113 /fs/nfs/read.c | |
parent | c63c7b051395368573779c8309aa5c990dcf2f96 (diff) |
NFS: Fix a buffer overflow in the allocation of struct nfs_read/writedata
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 19 |
1 files changed, 9 insertions, 10 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index f0016062340d..9a55807b2a70 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -27,8 +27,8 @@ | |||
27 | 27 | ||
28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 28 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
29 | 29 | ||
30 | static int nfs_pagein_multi(struct inode *, struct list_head *, size_t, int); | 30 | static int nfs_pagein_multi(struct inode *, struct list_head *, unsigned int, size_t, int); |
31 | static int nfs_pagein_one(struct inode *, struct list_head *, size_t, int); | 31 | static int nfs_pagein_one(struct inode *, struct list_head *, unsigned int, size_t, int); |
32 | static const struct rpc_call_ops nfs_read_partial_ops; | 32 | static const struct rpc_call_ops nfs_read_partial_ops; |
33 | static const struct rpc_call_ops nfs_read_full_ops; | 33 | static const struct rpc_call_ops nfs_read_full_ops; |
34 | 34 | ||
@@ -37,9 +37,8 @@ static mempool_t *nfs_rdata_mempool; | |||
37 | 37 | ||
38 | #define MIN_POOL_READ (32) | 38 | #define MIN_POOL_READ (32) |
39 | 39 | ||
40 | struct nfs_read_data *nfs_readdata_alloc(size_t len) | 40 | struct nfs_read_data *nfs_readdata_alloc(unsigned int pagecount) |
41 | { | 41 | { |
42 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
43 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); | 42 | struct nfs_read_data *p = mempool_alloc(nfs_rdata_mempool, GFP_NOFS); |
44 | 43 | ||
45 | if (p) { | 44 | if (p) { |
@@ -135,9 +134,9 @@ static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, | |||
135 | 134 | ||
136 | nfs_list_add_request(new, &one_request); | 135 | nfs_list_add_request(new, &one_request); |
137 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) | 136 | if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) |
138 | nfs_pagein_multi(inode, &one_request, len, 0); | 137 | nfs_pagein_multi(inode, &one_request, 1, len, 0); |
139 | else | 138 | else |
140 | nfs_pagein_one(inode, &one_request, len, 0); | 139 | nfs_pagein_one(inode, &one_request, 1, len, 0); |
141 | return 0; | 140 | return 0; |
142 | } | 141 | } |
143 | 142 | ||
@@ -234,7 +233,7 @@ static void nfs_execute_read(struct nfs_read_data *data) | |||
234 | * won't see the new data until our attribute cache is updated. This is more | 233 | * won't see the new data until our attribute cache is updated. This is more |
235 | * or less conventional NFS client behavior. | 234 | * or less conventional NFS client behavior. |
236 | */ | 235 | */ |
237 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, size_t count, int flags) | 236 | static int nfs_pagein_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
238 | { | 237 | { |
239 | struct nfs_page *req = nfs_list_entry(head->next); | 238 | struct nfs_page *req = nfs_list_entry(head->next); |
240 | struct page *page = req->wb_page; | 239 | struct page *page = req->wb_page; |
@@ -250,7 +249,7 @@ static int nfs_pagein_multi(struct inode *inode, struct list_head *head, size_t | |||
250 | do { | 249 | do { |
251 | size_t len = min(nbytes,rsize); | 250 | size_t len = min(nbytes,rsize); |
252 | 251 | ||
253 | data = nfs_readdata_alloc(len); | 252 | data = nfs_readdata_alloc(1); |
254 | if (!data) | 253 | if (!data) |
255 | goto out_bad; | 254 | goto out_bad; |
256 | INIT_LIST_HEAD(&data->pages); | 255 | INIT_LIST_HEAD(&data->pages); |
@@ -291,13 +290,13 @@ out_bad: | |||
291 | return -ENOMEM; | 290 | return -ENOMEM; |
292 | } | 291 | } |
293 | 292 | ||
294 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, size_t count, int flags) | 293 | static int nfs_pagein_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int flags) |
295 | { | 294 | { |
296 | struct nfs_page *req; | 295 | struct nfs_page *req; |
297 | struct page **pages; | 296 | struct page **pages; |
298 | struct nfs_read_data *data; | 297 | struct nfs_read_data *data; |
299 | 298 | ||
300 | data = nfs_readdata_alloc(count); | 299 | data = nfs_readdata_alloc(npages); |
301 | if (!data) | 300 | if (!data) |
302 | goto out_bad; | 301 | goto out_bad; |
303 | 302 | ||