| From 61c8504c428edcebf23b97775a129c5b393a302b Mon Sep 17 00:00:00 2001 |
| From: "J. Bruce Fields" <bfields@redhat.com> |
| Date: Thu, 22 Dec 2011 18:22:49 -0700 |
| Subject: svcrpc: fix double-free on shutdown of nfsd after changing pool mode |
| |
| From: "J. Bruce Fields" <bfields@redhat.com> |
| |
| commit 61c8504c428edcebf23b97775a129c5b393a302b upstream. |
| |
| 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. |
| |
| Signed-off-by: J. Bruce Fields <bfields@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/sunrpc/svc.c | 3 +++ |
| 1 file changed, 3 insertions(+) |
| |
| --- a/net/sunrpc/svc.c |
| +++ b/net/sunrpc/svc.c |
| @@ -166,6 +166,7 @@ svc_pool_map_alloc_arrays(struct svc_poo |
| |
| fail_free: |
| kfree(m->to_pool); |
| + m->to_pool = NULL; |
| fail: |
| return -ENOMEM; |
| } |
| @@ -286,7 +287,9 @@ svc_pool_map_put(void) |
| if (!--m->count) { |
| m->mode = SVC_POOL_DEFAULT; |
| kfree(m->to_pool); |
| + m->to_pool = NULL; |
| kfree(m->pool_to); |
| + m->pool_to = NULL; |
| m->npools = 0; |
| } |
| |