diff options
author | J. Bruce Fields <bfields@redhat.com> | 2011-12-22 20:22:49 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2012-01-05 15:35:55 -0500 |
commit | 61c8504c428edcebf23b97775a129c5b393a302b (patch) | |
tree | 471b18af06d51a17e2ef224d7f2da9384939ee21 /net/sunrpc | |
parent | b8548894bde94ccee836e210274ff401225e9733 (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.c | 3 |
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 | ||
168 | fail_free: | 168 | fail_free: |
169 | kfree(m->to_pool); | 169 | kfree(m->to_pool); |
170 | m->to_pool = NULL; | ||
170 | fail: | 171 | fail: |
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 | ||