aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-12-22 20:22:49 -0500
committerJ. Bruce Fields <bfields@redhat.com>2012-01-05 15:35:55 -0500
commit61c8504c428edcebf23b97775a129c5b393a302b (patch)
tree471b18af06d51a17e2ef224d7f2da9384939ee21 /net/sunrpc
parentb8548894bde94ccee836e210274ff401225e9733 (diff)
svcrpc: fix double-free on shutdown of nfsd after changing pool mode
The pool_to and to_pool fields of the global svc_pool_map are freed on shutdown, but are initialized in nfsd startup only in the SVC_POOL_PERCPU and SVC_POOL_PERNODE cases. They *are* initialized to zero on kernel startup. So as long as you use only SVC_POOL_GLOBAL (the default), this will never be a problem. You're also OK if you only ever use SVC_POOL_PERCPU or SVC_POOL_PERNODE. However, the following sequence events leads to a double-free: 1. set SVC_POOL_PERCPU or SVC_POOL_PERNODE 2. start nfsd: both fields are initialized. 3. shutdown nfsd: both fields are freed. 4. set SVC_POOL_GLOBAL 5. start nfsd: the fields are left untouched. 6. shutdown nfsd: now we try to free them again. Step 4 is actually unnecessary, since (for some bizarre reason), nfsd automatically resets the pool mode to SVC_POOL_GLOBAL on shutdown. Cc: stable@kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/svc.c3
1 files changed, 3 insertions, 0 deletions
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index e9632bb66535..1dd5fd014559 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -167,6 +167,7 @@ svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
167 167
168fail_free: 168fail_free:
169 kfree(m->to_pool); 169 kfree(m->to_pool);
170 m->to_pool = NULL;
170fail: 171fail:
171 return -ENOMEM; 172 return -ENOMEM;
172} 173}
@@ -287,7 +288,9 @@ svc_pool_map_put(void)
287 if (!--m->count) { 288 if (!--m->count) {
288 m->mode = SVC_POOL_DEFAULT; 289 m->mode = SVC_POOL_DEFAULT;
289 kfree(m->to_pool); 290 kfree(m->to_pool);
291 m->to_pool = NULL;
290 kfree(m->pool_to); 292 kfree(m->pool_to);
293 m->pool_to = NULL;
291 m->npools = 0; 294 m->npools = 0;
292 } 295 }
293 296