diff options
author | Krzysztof Mazur <krzysiek@podlesie.net> | 2012-11-06 17:16:59 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-11-27 19:37:04 -0500 |
commit | e41faed9cde1acce657f75a0b19a1787e9850d3f (patch) | |
tree | 92354ef7b85f7684d247a9e8ebb402c5f0d86ed5 /net | |
parent | 3b1a914595f3f9beb9e38ff3ddc7bdafa092ba22 (diff) |
pppoatm: fix module_put() race
The pppoatm used module_put() during unassignment from vcc with
hope that we have BKL. This assumption is no longer true.
Now owner field in atmvcc is used to move this module_put()
to vcc_destroy_socket().
Signed-off-by: Krzysztof Mazur <krzysiek@podlesie.net>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/atm/pppoatm.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index f27a07a3c546..b23c6723e87c 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c | |||
@@ -60,6 +60,7 @@ struct pppoatm_vcc { | |||
60 | struct atm_vcc *atmvcc; /* VCC descriptor */ | 60 | struct atm_vcc *atmvcc; /* VCC descriptor */ |
61 | void (*old_push)(struct atm_vcc *, struct sk_buff *); | 61 | void (*old_push)(struct atm_vcc *, struct sk_buff *); |
62 | void (*old_pop)(struct atm_vcc *, struct sk_buff *); | 62 | void (*old_pop)(struct atm_vcc *, struct sk_buff *); |
63 | struct module *old_owner; | ||
63 | /* keep old push/pop for detaching */ | 64 | /* keep old push/pop for detaching */ |
64 | enum pppoatm_encaps encaps; | 65 | enum pppoatm_encaps encaps; |
65 | atomic_t inflight; | 66 | atomic_t inflight; |
@@ -155,8 +156,6 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc) | |||
155 | ppp_unregister_channel(&pvcc->chan); | 156 | ppp_unregister_channel(&pvcc->chan); |
156 | atmvcc->user_back = NULL; | 157 | atmvcc->user_back = NULL; |
157 | kfree(pvcc); | 158 | kfree(pvcc); |
158 | /* Gee, I hope we have the big kernel lock here... */ | ||
159 | module_put(THIS_MODULE); | ||
160 | } | 159 | } |
161 | 160 | ||
162 | /* Called when an AAL5 PDU comes in */ | 161 | /* Called when an AAL5 PDU comes in */ |
@@ -165,9 +164,13 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) | |||
165 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); | 164 | struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); |
166 | pr_debug("\n"); | 165 | pr_debug("\n"); |
167 | if (skb == NULL) { /* VCC was closed */ | 166 | if (skb == NULL) { /* VCC was closed */ |
167 | struct module *module; | ||
168 | |||
168 | pr_debug("removing ATMPPP VCC %p\n", pvcc); | 169 | pr_debug("removing ATMPPP VCC %p\n", pvcc); |
170 | module = pvcc->old_owner; | ||
169 | pppoatm_unassign_vcc(atmvcc); | 171 | pppoatm_unassign_vcc(atmvcc); |
170 | atmvcc->push(atmvcc, NULL); /* Pass along bad news */ | 172 | atmvcc->push(atmvcc, NULL); /* Pass along bad news */ |
173 | module_put(module); | ||
171 | return; | 174 | return; |
172 | } | 175 | } |
173 | atm_return(atmvcc, skb->truesize); | 176 | atm_return(atmvcc, skb->truesize); |
@@ -362,6 +365,7 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) | |||
362 | atomic_set(&pvcc->inflight, NONE_INFLIGHT); | 365 | atomic_set(&pvcc->inflight, NONE_INFLIGHT); |
363 | pvcc->old_push = atmvcc->push; | 366 | pvcc->old_push = atmvcc->push; |
364 | pvcc->old_pop = atmvcc->pop; | 367 | pvcc->old_pop = atmvcc->pop; |
368 | pvcc->old_owner = atmvcc->owner; | ||
365 | pvcc->encaps = (enum pppoatm_encaps) be.encaps; | 369 | pvcc->encaps = (enum pppoatm_encaps) be.encaps; |
366 | pvcc->chan.private = pvcc; | 370 | pvcc->chan.private = pvcc; |
367 | pvcc->chan.ops = &pppoatm_ops; | 371 | pvcc->chan.ops = &pppoatm_ops; |
@@ -378,6 +382,7 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg) | |||
378 | atmvcc->push = pppoatm_push; | 382 | atmvcc->push = pppoatm_push; |
379 | atmvcc->pop = pppoatm_pop; | 383 | atmvcc->pop = pppoatm_pop; |
380 | __module_get(THIS_MODULE); | 384 | __module_get(THIS_MODULE); |
385 | atmvcc->owner = THIS_MODULE; | ||
381 | 386 | ||
382 | /* re-process everything received between connection setup and | 387 | /* re-process everything received between connection setup and |
383 | backend setup */ | 388 | backend setup */ |