]>
Commit | Line | Data |
---|---|---|
5e3c2993 GKH |
1 | From 61c8504c428edcebf23b97775a129c5b393a302b Mon Sep 17 00:00:00 2001 |
2 | From: "J. Bruce Fields" <bfields@redhat.com> | |
3 | Date: Thu, 22 Dec 2011 18:22:49 -0700 | |
4 | Subject: svcrpc: fix double-free on shutdown of nfsd after changing pool mode | |
5 | ||
6 | From: "J. Bruce Fields" <bfields@redhat.com> | |
7 | ||
8 | commit 61c8504c428edcebf23b97775a129c5b393a302b upstream. | |
9 | ||
10 | The pool_to and to_pool fields of the global svc_pool_map are freed on | |
11 | shutdown, but are initialized in nfsd startup only in the | |
12 | SVC_POOL_PERCPU and SVC_POOL_PERNODE cases. | |
13 | ||
14 | They *are* initialized to zero on kernel startup. So as long as you use | |
15 | only SVC_POOL_GLOBAL (the default), this will never be a problem. | |
16 | ||
17 | You're also OK if you only ever use SVC_POOL_PERCPU or SVC_POOL_PERNODE. | |
18 | ||
19 | However, the following sequence events leads to a double-free: | |
20 | ||
21 | 1. set SVC_POOL_PERCPU or SVC_POOL_PERNODE | |
22 | 2. start nfsd: both fields are initialized. | |
23 | 3. shutdown nfsd: both fields are freed. | |
24 | 4. set SVC_POOL_GLOBAL | |
25 | 5. start nfsd: the fields are left untouched. | |
26 | 6. shutdown nfsd: now we try to free them again. | |
27 | ||
28 | Step 4 is actually unnecessary, since (for some bizarre reason), nfsd | |
29 | automatically resets the pool mode to SVC_POOL_GLOBAL on shutdown. | |
30 | ||
31 | Signed-off-by: J. Bruce Fields <bfields@redhat.com> | |
32 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
33 | ||
34 | --- | |
35 | net/sunrpc/svc.c | 3 +++ | |
36 | 1 file changed, 3 insertions(+) | |
37 | ||
38 | --- a/net/sunrpc/svc.c | |
39 | +++ b/net/sunrpc/svc.c | |
40 | @@ -167,6 +167,7 @@ svc_pool_map_alloc_arrays(struct svc_poo | |
41 | ||
42 | fail_free: | |
43 | kfree(m->to_pool); | |
44 | + m->to_pool = NULL; | |
45 | fail: | |
46 | return -ENOMEM; | |
47 | } | |
48 | @@ -287,7 +288,9 @@ svc_pool_map_put(void) | |
49 | if (!--m->count) { | |
50 | m->mode = SVC_POOL_DEFAULT; | |
51 | kfree(m->to_pool); | |
52 | + m->to_pool = NULL; | |
53 | kfree(m->pool_to); | |
54 | + m->pool_to = NULL; | |
55 | m->npools = 0; | |
56 | } | |
57 |