Skip to content

Commit 67a56e9

Browse files
trondmygregkh
authored andcommitted
NFS: Fix memory leaks and corruption in readdir
[ Upstream commit 4b31031 ] nfs_readdir_xdr_to_array() must not exit without having initialised the array, so that the page cache deletion routines can safely call nfs_readdir_clear_array(). Furthermore, we should ensure that if we exit nfs_readdir_filler() with an error, we free up any page contents to prevent a leak if we try to fill the page again. Fixes: 11de3b1 ("NFS: Fix a memory leak in nfs_readdir") Cc: [email protected] # v2.6.37+ Signed-off-by: Trond Myklebust <[email protected]> Reviewed-by: Benjamin Coddington <[email protected]> Signed-off-by: Anna Schumaker <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 9dc9bee commit 67a56e9

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

fs/nfs/dir.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,17 @@ typedef struct {
169169
unsigned int eof:1;
170170
} nfs_readdir_descriptor_t;
171171

172+
static
173+
void nfs_readdir_init_array(struct page *page)
174+
{
175+
struct nfs_cache_array *array;
176+
177+
array = kmap_atomic(page);
178+
memset(array, 0, sizeof(struct nfs_cache_array));
179+
array->eof_index = -1;
180+
kunmap_atomic(array);
181+
}
182+
172183
/*
173184
* The caller is responsible for calling nfs_readdir_release_array(page)
174185
*/
@@ -202,6 +213,7 @@ void nfs_readdir_clear_array(struct page *page)
202213
array = kmap_atomic(page);
203214
for (i = 0; i < array->size; i++)
204215
kfree(array->array[i].string.name);
216+
array->size = 0;
205217
kunmap_atomic(array);
206218
}
207219

@@ -643,6 +655,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
643655
int status = -ENOMEM;
644656
unsigned int array_size = ARRAY_SIZE(pages);
645657

658+
nfs_readdir_init_array(page);
659+
646660
entry.prev_cookie = 0;
647661
entry.cookie = desc->last_cookie;
648662
entry.eof = 0;
@@ -663,8 +677,8 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page,
663677
status = PTR_ERR(array);
664678
goto out_label_free;
665679
}
666-
memset(array, 0, sizeof(struct nfs_cache_array));
667-
array->eof_index = -1;
680+
681+
array = kmap(page);
668682

669683
status = nfs_readdir_alloc_pages(pages, array_size);
670684
if (status < 0)
@@ -719,6 +733,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page)
719733
unlock_page(page);
720734
return 0;
721735
error:
736+
nfs_readdir_clear_array(page);
722737
unlock_page(page);
723738
return ret;
724739
}

0 commit comments

Comments
 (0)