]>
Commit | Line | Data |
---|---|---|
52aa51ba GKH |
1 | From ddeee0b2eec2a51b0712b04de4b39e7bec892a53 Mon Sep 17 00:00:00 2001 |
2 | From: Linus Torvalds <torvalds@linux-foundation.org> | |
3 | Date: Tue, 16 Feb 2010 12:35:07 -0800 | |
4 | Subject: USB: usbfs: properly clean up the as structure on error paths | |
5 | ||
6 | From: Linus Torvalds <torvalds@linux-foundation.org> | |
7 | ||
8 | commit ddeee0b2eec2a51b0712b04de4b39e7bec892a53 upstream. | |
9 | ||
10 | I notice that the processcompl_compat() function seems to be leaking the | |
11 | 'struct async *as' in the error paths. | |
12 | ||
13 | I think that the calling convention is fundamentally buggered. The | |
14 | caller is the one that did the "reap_as()" to get the as thing, the | |
15 | caller should be the one to free it too. | |
16 | ||
17 | Freeing it in the caller also means that it very clearly always gets | |
18 | freed, and avoids the need for any "free in the error case too". | |
19 | ||
20 | From: Linus Torvalds <torvalds@linux-foundation.org> | |
21 | Cc: Alan Stern <stern@rowland.harvard.edu> | |
22 | Cc: Marcus Meissner <meissner@suse.de> | |
23 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
24 | ||
25 | --- | |
26 | drivers/usb/core/devio.c | 40 ++++++++++++++++++++++++++-------------- | |
27 | 1 file changed, 26 insertions(+), 14 deletions(-) | |
28 | ||
29 | --- a/drivers/usb/core/devio.c | |
30 | +++ b/drivers/usb/core/devio.c | |
31 | @@ -1246,14 +1246,11 @@ static int processcompl(struct async *as | |
32 | } | |
33 | } | |
34 | ||
35 | - free_async(as); | |
36 | - | |
37 | if (put_user(addr, (void __user * __user *)arg)) | |
38 | return -EFAULT; | |
39 | return 0; | |
40 | ||
41 | err_out: | |
42 | - free_async(as); | |
43 | return -EFAULT; | |
44 | } | |
45 | ||
46 | @@ -1283,8 +1280,11 @@ static struct async *reap_as(struct dev_ | |
47 | static int proc_reapurb(struct dev_state *ps, void __user *arg) | |
48 | { | |
49 | struct async *as = reap_as(ps); | |
50 | - if (as) | |
51 | - return processcompl(as, (void __user * __user *)arg); | |
52 | + if (as) { | |
53 | + int retval = processcompl(as, (void __user * __user *)arg); | |
54 | + free_async(as); | |
55 | + return retval; | |
56 | + } | |
57 | if (signal_pending(current)) | |
58 | return -EINTR; | |
59 | return -EIO; | |
60 | @@ -1292,11 +1292,16 @@ static int proc_reapurb(struct dev_state | |
61 | ||
62 | static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) | |
63 | { | |
64 | + int retval; | |
65 | struct async *as; | |
66 | ||
67 | - if (!(as = async_getcompleted(ps))) | |
68 | - return -EAGAIN; | |
69 | - return processcompl(as, (void __user * __user *)arg); | |
70 | + as = async_getcompleted(ps); | |
71 | + retval = -EAGAIN; | |
72 | + if (as) { | |
73 | + retval = processcompl(as, (void __user * __user *)arg); | |
74 | + free_async(as); | |
75 | + } | |
76 | + return retval; | |
77 | } | |
78 | ||
79 | #ifdef CONFIG_COMPAT | |
80 | @@ -1369,7 +1374,6 @@ static int processcompl_compat(struct as | |
81 | } | |
82 | } | |
83 | ||
84 | - free_async(as); | |
85 | if (put_user(ptr_to_compat(addr), (u32 __user *)arg)) | |
86 | return -EFAULT; | |
87 | return 0; | |
88 | @@ -1378,8 +1382,11 @@ static int processcompl_compat(struct as | |
89 | static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) | |
90 | { | |
91 | struct async *as = reap_as(ps); | |
92 | - if (as) | |
93 | - return processcompl_compat(as, (void __user * __user *)arg); | |
94 | + if (as) { | |
95 | + int retval = processcompl_compat(as, (void __user * __user *)arg); | |
96 | + free_async(as); | |
97 | + return retval; | |
98 | + } | |
99 | if (signal_pending(current)) | |
100 | return -EINTR; | |
101 | return -EIO; | |
102 | @@ -1387,11 +1394,16 @@ static int proc_reapurb_compat(struct de | |
103 | ||
104 | static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) | |
105 | { | |
106 | + int retval; | |
107 | struct async *as; | |
108 | ||
109 | - if (!(as = async_getcompleted(ps))) | |
110 | - return -EAGAIN; | |
111 | - return processcompl_compat(as, (void __user * __user *)arg); | |
112 | + retval = -EAGAIN; | |
113 | + as = async_getcompleted(ps); | |
114 | + if (as) { | |
115 | + retval = processcompl_compat(as, (void __user * __user *)arg); | |
116 | + free_async(as); | |
117 | + } | |
118 | + return retval; | |
119 | } | |
120 | ||
121 | #endif |