Commit eb9f37053db5ea11101825d97442cf88754a48d1
Committed by
David S. Miller
1 parent
93dccc5916
Revert "sctp: optimize the sctp_sysctl_net_register"
This revert commit efb842c45("sctp: optimize the sctp_sysctl_net_register"), Since it doesn't kmemdup a sysctl_table for init_net, so the init_net->sctp.sysctl_header->ctl_table_arg points to sctp_net_table which is a static array pointer. So when doing sctp_sysctl_net_unregister, it will free sctp_net_table, then we will get a NULL pointer dereference like that: [ 262.948220] BUG: unable to handle kernel NULL pointer dereference at 000000000000006c [ 262.948232] IP: [<ffffffff81144b70>] kfree+0x80/0x420 [ 262.948260] PGD db80a067 PUD dae12067 PMD 0 [ 262.948268] Oops: 0000 [#1] SMP [ 262.948273] Modules linked in: sctp(-) crc32c_generic libcrc32c ... [ 262.948338] task: ffff8800db830190 ti: ffff8800dad00000 task.ti: ffff8800dad00000 [ 262.948344] RIP: 0010:[<ffffffff81144b70>] [<ffffffff81144b70>] kfree+0x80/0x420 [ 262.948353] RSP: 0018:ffff8800dad01d88 EFLAGS: 00010046 [ 262.948358] RAX: 0100000000000000 RBX: ffffffffa0227940 RCX: ffffea0000707888 [ 262.948363] RDX: ffffea0000707888 RSI: 0000000000000001 RDI: ffffffffa0227940 [ 262.948369] RBP: ffff8800dad01de8 R08: 0000000000000000 R09: ffff8800d9e983a9 [ 262.948374] R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffa0227940 [ 262.948380] R13: ffffffff8187cfc0 R14: 0000000000000000 R15: ffffffff8187da10 [ 262.948386] FS: 00007fa2a2658700(0000) GS:ffff880112800000(0000) knlGS:0000000000000000 [ 262.948394] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 262.948400] CR2: 000000000000006c CR3: 00000000cddc0000 CR4: 00000000000006e0 [ 262.948410] Stack: [ 262.948413] ffff8800dad01da8 0000000000000286 0000000020227940 ffffffffa0227940 [ 262.948422] ffff8800dad01dd8 ffffffff811b7fa1 ffffffffa0227940 ffffffffa0227940 [ 262.948431] ffffffff8187d960 ffffffff8187cfc0 ffffffff8187d960 ffffffff8187da10 [ 262.948440] Call Trace: [ 262.948457] [<ffffffff811b7fa1>] ? unregister_sysctl_table+0x51/0xa0 [ 262.948476] [<ffffffffa020d1a1>] sctp_sysctl_net_unregister+0x21/0x30 [sctp] [ 262.948490] [<ffffffffa020ef6d>] sctp_net_exit+0x12d/0x150 [sctp] [ 262.948512] [<ffffffff81394f49>] ops_exit_list+0x39/0x60 [ 262.948522] [<ffffffff813951ed>] unregister_pernet_operations+0x3d/0x70 [ 262.948530] [<ffffffff81395292>] unregister_pernet_subsys+0x22/0x40 [ 262.948544] [<ffffffffa020efcc>] sctp_exit+0x3c/0x12d [sctp] [ 262.948562] [<ffffffff810c5e04>] SyS_delete_module+0x194/0x210 [ 262.948577] [<ffffffff81240fde>] ? trace_hardirqs_on_thunk+0x3a/0x3f [ 262.948587] [<ffffffff815217a2>] system_call_fastpath+0x16/0x1b With this revert, it won't occur the Oops. Signed-off-by: Wang Weidong <wangweidong1@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 7 additions and 10 deletions Inline Diff
net/sctp/sysctl.c
1 | /* SCTP kernel implementation | 1 | /* SCTP kernel implementation |
2 | * (C) Copyright IBM Corp. 2002, 2004 | 2 | * (C) Copyright IBM Corp. 2002, 2004 |
3 | * Copyright (c) 2002 Intel Corp. | 3 | * Copyright (c) 2002 Intel Corp. |
4 | * | 4 | * |
5 | * This file is part of the SCTP kernel implementation | 5 | * This file is part of the SCTP kernel implementation |
6 | * | 6 | * |
7 | * Sysctl related interfaces for SCTP. | 7 | * Sysctl related interfaces for SCTP. |
8 | * | 8 | * |
9 | * This SCTP implementation is free software; | 9 | * This SCTP implementation is free software; |
10 | * you can redistribute it and/or modify it under the terms of | 10 | * you can redistribute it and/or modify it under the terms of |
11 | * the GNU General Public License as published by | 11 | * the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2, or (at your option) | 12 | * the Free Software Foundation; either version 2, or (at your option) |
13 | * any later version. | 13 | * any later version. |
14 | * | 14 | * |
15 | * This SCTP implementation is distributed in the hope that it | 15 | * This SCTP implementation is distributed in the hope that it |
16 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | 16 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
17 | * ************************ | 17 | * ************************ |
18 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 18 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
19 | * See the GNU General Public License for more details. | 19 | * See the GNU General Public License for more details. |
20 | * | 20 | * |
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with GNU CC; see the file COPYING. If not, see | 22 | * along with GNU CC; see the file COPYING. If not, see |
23 | * <http://www.gnu.org/licenses/>. | 23 | * <http://www.gnu.org/licenses/>. |
24 | * | 24 | * |
25 | * Please send any bug reports or fixes you make to the | 25 | * Please send any bug reports or fixes you make to the |
26 | * email address(es): | 26 | * email address(es): |
27 | * lksctp developers <linux-sctp@vger.kernel.org> | 27 | * lksctp developers <linux-sctp@vger.kernel.org> |
28 | * | 28 | * |
29 | * Written or modified by: | 29 | * Written or modified by: |
30 | * Mingqin Liu <liuming@us.ibm.com> | 30 | * Mingqin Liu <liuming@us.ibm.com> |
31 | * Jon Grimm <jgrimm@us.ibm.com> | 31 | * Jon Grimm <jgrimm@us.ibm.com> |
32 | * Ardelle Fan <ardelle.fan@intel.com> | 32 | * Ardelle Fan <ardelle.fan@intel.com> |
33 | * Ryan Layer <rmlayer@us.ibm.com> | 33 | * Ryan Layer <rmlayer@us.ibm.com> |
34 | * Sridhar Samudrala <sri@us.ibm.com> | 34 | * Sridhar Samudrala <sri@us.ibm.com> |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <net/sctp/structs.h> | 37 | #include <net/sctp/structs.h> |
38 | #include <net/sctp/sctp.h> | 38 | #include <net/sctp/sctp.h> |
39 | #include <linux/sysctl.h> | 39 | #include <linux/sysctl.h> |
40 | 40 | ||
41 | static int zero = 0; | 41 | static int zero = 0; |
42 | static int one = 1; | 42 | static int one = 1; |
43 | static int timer_max = 86400000; /* ms in one day */ | 43 | static int timer_max = 86400000; /* ms in one day */ |
44 | static int int_max = INT_MAX; | 44 | static int int_max = INT_MAX; |
45 | static int sack_timer_min = 1; | 45 | static int sack_timer_min = 1; |
46 | static int sack_timer_max = 500; | 46 | static int sack_timer_max = 500; |
47 | static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ | 47 | static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ |
48 | static int rwnd_scale_max = 16; | 48 | static int rwnd_scale_max = 16; |
49 | static unsigned long max_autoclose_min = 0; | 49 | static unsigned long max_autoclose_min = 0; |
50 | static unsigned long max_autoclose_max = | 50 | static unsigned long max_autoclose_max = |
51 | (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) | 51 | (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) |
52 | ? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ; | 52 | ? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ; |
53 | 53 | ||
54 | extern long sysctl_sctp_mem[3]; | 54 | extern long sysctl_sctp_mem[3]; |
55 | extern int sysctl_sctp_rmem[3]; | 55 | extern int sysctl_sctp_rmem[3]; |
56 | extern int sysctl_sctp_wmem[3]; | 56 | extern int sysctl_sctp_wmem[3]; |
57 | 57 | ||
58 | static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write, | 58 | static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write, |
59 | void __user *buffer, size_t *lenp, | 59 | void __user *buffer, size_t *lenp, |
60 | loff_t *ppos); | 60 | loff_t *ppos); |
61 | static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, | 61 | static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, |
62 | void __user *buffer, size_t *lenp, | 62 | void __user *buffer, size_t *lenp, |
63 | loff_t *ppos); | 63 | loff_t *ppos); |
64 | static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, | 64 | static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, |
65 | void __user *buffer, size_t *lenp, | 65 | void __user *buffer, size_t *lenp, |
66 | loff_t *ppos); | 66 | loff_t *ppos); |
67 | static int proc_sctp_do_auth(struct ctl_table *ctl, int write, | 67 | static int proc_sctp_do_auth(struct ctl_table *ctl, int write, |
68 | void __user *buffer, size_t *lenp, | 68 | void __user *buffer, size_t *lenp, |
69 | loff_t *ppos); | 69 | loff_t *ppos); |
70 | 70 | ||
71 | static struct ctl_table sctp_table[] = { | 71 | static struct ctl_table sctp_table[] = { |
72 | { | 72 | { |
73 | .procname = "sctp_mem", | 73 | .procname = "sctp_mem", |
74 | .data = &sysctl_sctp_mem, | 74 | .data = &sysctl_sctp_mem, |
75 | .maxlen = sizeof(sysctl_sctp_mem), | 75 | .maxlen = sizeof(sysctl_sctp_mem), |
76 | .mode = 0644, | 76 | .mode = 0644, |
77 | .proc_handler = proc_doulongvec_minmax | 77 | .proc_handler = proc_doulongvec_minmax |
78 | }, | 78 | }, |
79 | { | 79 | { |
80 | .procname = "sctp_rmem", | 80 | .procname = "sctp_rmem", |
81 | .data = &sysctl_sctp_rmem, | 81 | .data = &sysctl_sctp_rmem, |
82 | .maxlen = sizeof(sysctl_sctp_rmem), | 82 | .maxlen = sizeof(sysctl_sctp_rmem), |
83 | .mode = 0644, | 83 | .mode = 0644, |
84 | .proc_handler = proc_dointvec, | 84 | .proc_handler = proc_dointvec, |
85 | }, | 85 | }, |
86 | { | 86 | { |
87 | .procname = "sctp_wmem", | 87 | .procname = "sctp_wmem", |
88 | .data = &sysctl_sctp_wmem, | 88 | .data = &sysctl_sctp_wmem, |
89 | .maxlen = sizeof(sysctl_sctp_wmem), | 89 | .maxlen = sizeof(sysctl_sctp_wmem), |
90 | .mode = 0644, | 90 | .mode = 0644, |
91 | .proc_handler = proc_dointvec, | 91 | .proc_handler = proc_dointvec, |
92 | }, | 92 | }, |
93 | 93 | ||
94 | { /* sentinel */ } | 94 | { /* sentinel */ } |
95 | }; | 95 | }; |
96 | 96 | ||
97 | static struct ctl_table sctp_net_table[] = { | 97 | static struct ctl_table sctp_net_table[] = { |
98 | { | 98 | { |
99 | .procname = "rto_initial", | 99 | .procname = "rto_initial", |
100 | .data = &init_net.sctp.rto_initial, | 100 | .data = &init_net.sctp.rto_initial, |
101 | .maxlen = sizeof(unsigned int), | 101 | .maxlen = sizeof(unsigned int), |
102 | .mode = 0644, | 102 | .mode = 0644, |
103 | .proc_handler = proc_dointvec_minmax, | 103 | .proc_handler = proc_dointvec_minmax, |
104 | .extra1 = &one, | 104 | .extra1 = &one, |
105 | .extra2 = &timer_max | 105 | .extra2 = &timer_max |
106 | }, | 106 | }, |
107 | { | 107 | { |
108 | .procname = "rto_min", | 108 | .procname = "rto_min", |
109 | .data = &init_net.sctp.rto_min, | 109 | .data = &init_net.sctp.rto_min, |
110 | .maxlen = sizeof(unsigned int), | 110 | .maxlen = sizeof(unsigned int), |
111 | .mode = 0644, | 111 | .mode = 0644, |
112 | .proc_handler = proc_sctp_do_rto_min, | 112 | .proc_handler = proc_sctp_do_rto_min, |
113 | .extra1 = &one, | 113 | .extra1 = &one, |
114 | .extra2 = &init_net.sctp.rto_max | 114 | .extra2 = &init_net.sctp.rto_max |
115 | }, | 115 | }, |
116 | { | 116 | { |
117 | .procname = "rto_max", | 117 | .procname = "rto_max", |
118 | .data = &init_net.sctp.rto_max, | 118 | .data = &init_net.sctp.rto_max, |
119 | .maxlen = sizeof(unsigned int), | 119 | .maxlen = sizeof(unsigned int), |
120 | .mode = 0644, | 120 | .mode = 0644, |
121 | .proc_handler = proc_sctp_do_rto_max, | 121 | .proc_handler = proc_sctp_do_rto_max, |
122 | .extra1 = &init_net.sctp.rto_min, | 122 | .extra1 = &init_net.sctp.rto_min, |
123 | .extra2 = &timer_max | 123 | .extra2 = &timer_max |
124 | }, | 124 | }, |
125 | { | 125 | { |
126 | .procname = "rto_alpha_exp_divisor", | 126 | .procname = "rto_alpha_exp_divisor", |
127 | .data = &init_net.sctp.rto_alpha, | 127 | .data = &init_net.sctp.rto_alpha, |
128 | .maxlen = sizeof(int), | 128 | .maxlen = sizeof(int), |
129 | .mode = 0444, | 129 | .mode = 0444, |
130 | .proc_handler = proc_dointvec, | 130 | .proc_handler = proc_dointvec, |
131 | }, | 131 | }, |
132 | { | 132 | { |
133 | .procname = "rto_beta_exp_divisor", | 133 | .procname = "rto_beta_exp_divisor", |
134 | .data = &init_net.sctp.rto_beta, | 134 | .data = &init_net.sctp.rto_beta, |
135 | .maxlen = sizeof(int), | 135 | .maxlen = sizeof(int), |
136 | .mode = 0444, | 136 | .mode = 0444, |
137 | .proc_handler = proc_dointvec, | 137 | .proc_handler = proc_dointvec, |
138 | }, | 138 | }, |
139 | { | 139 | { |
140 | .procname = "max_burst", | 140 | .procname = "max_burst", |
141 | .data = &init_net.sctp.max_burst, | 141 | .data = &init_net.sctp.max_burst, |
142 | .maxlen = sizeof(int), | 142 | .maxlen = sizeof(int), |
143 | .mode = 0644, | 143 | .mode = 0644, |
144 | .proc_handler = proc_dointvec_minmax, | 144 | .proc_handler = proc_dointvec_minmax, |
145 | .extra1 = &zero, | 145 | .extra1 = &zero, |
146 | .extra2 = &int_max | 146 | .extra2 = &int_max |
147 | }, | 147 | }, |
148 | { | 148 | { |
149 | .procname = "cookie_preserve_enable", | 149 | .procname = "cookie_preserve_enable", |
150 | .data = &init_net.sctp.cookie_preserve_enable, | 150 | .data = &init_net.sctp.cookie_preserve_enable, |
151 | .maxlen = sizeof(int), | 151 | .maxlen = sizeof(int), |
152 | .mode = 0644, | 152 | .mode = 0644, |
153 | .proc_handler = proc_dointvec, | 153 | .proc_handler = proc_dointvec, |
154 | }, | 154 | }, |
155 | { | 155 | { |
156 | .procname = "cookie_hmac_alg", | 156 | .procname = "cookie_hmac_alg", |
157 | .data = &init_net.sctp.sctp_hmac_alg, | 157 | .data = &init_net.sctp.sctp_hmac_alg, |
158 | .maxlen = 8, | 158 | .maxlen = 8, |
159 | .mode = 0644, | 159 | .mode = 0644, |
160 | .proc_handler = proc_sctp_do_hmac_alg, | 160 | .proc_handler = proc_sctp_do_hmac_alg, |
161 | }, | 161 | }, |
162 | { | 162 | { |
163 | .procname = "valid_cookie_life", | 163 | .procname = "valid_cookie_life", |
164 | .data = &init_net.sctp.valid_cookie_life, | 164 | .data = &init_net.sctp.valid_cookie_life, |
165 | .maxlen = sizeof(unsigned int), | 165 | .maxlen = sizeof(unsigned int), |
166 | .mode = 0644, | 166 | .mode = 0644, |
167 | .proc_handler = proc_dointvec_minmax, | 167 | .proc_handler = proc_dointvec_minmax, |
168 | .extra1 = &one, | 168 | .extra1 = &one, |
169 | .extra2 = &timer_max | 169 | .extra2 = &timer_max |
170 | }, | 170 | }, |
171 | { | 171 | { |
172 | .procname = "sack_timeout", | 172 | .procname = "sack_timeout", |
173 | .data = &init_net.sctp.sack_timeout, | 173 | .data = &init_net.sctp.sack_timeout, |
174 | .maxlen = sizeof(int), | 174 | .maxlen = sizeof(int), |
175 | .mode = 0644, | 175 | .mode = 0644, |
176 | .proc_handler = proc_dointvec_minmax, | 176 | .proc_handler = proc_dointvec_minmax, |
177 | .extra1 = &sack_timer_min, | 177 | .extra1 = &sack_timer_min, |
178 | .extra2 = &sack_timer_max, | 178 | .extra2 = &sack_timer_max, |
179 | }, | 179 | }, |
180 | { | 180 | { |
181 | .procname = "hb_interval", | 181 | .procname = "hb_interval", |
182 | .data = &init_net.sctp.hb_interval, | 182 | .data = &init_net.sctp.hb_interval, |
183 | .maxlen = sizeof(unsigned int), | 183 | .maxlen = sizeof(unsigned int), |
184 | .mode = 0644, | 184 | .mode = 0644, |
185 | .proc_handler = proc_dointvec_minmax, | 185 | .proc_handler = proc_dointvec_minmax, |
186 | .extra1 = &one, | 186 | .extra1 = &one, |
187 | .extra2 = &timer_max | 187 | .extra2 = &timer_max |
188 | }, | 188 | }, |
189 | { | 189 | { |
190 | .procname = "association_max_retrans", | 190 | .procname = "association_max_retrans", |
191 | .data = &init_net.sctp.max_retrans_association, | 191 | .data = &init_net.sctp.max_retrans_association, |
192 | .maxlen = sizeof(int), | 192 | .maxlen = sizeof(int), |
193 | .mode = 0644, | 193 | .mode = 0644, |
194 | .proc_handler = proc_dointvec_minmax, | 194 | .proc_handler = proc_dointvec_minmax, |
195 | .extra1 = &one, | 195 | .extra1 = &one, |
196 | .extra2 = &int_max | 196 | .extra2 = &int_max |
197 | }, | 197 | }, |
198 | { | 198 | { |
199 | .procname = "path_max_retrans", | 199 | .procname = "path_max_retrans", |
200 | .data = &init_net.sctp.max_retrans_path, | 200 | .data = &init_net.sctp.max_retrans_path, |
201 | .maxlen = sizeof(int), | 201 | .maxlen = sizeof(int), |
202 | .mode = 0644, | 202 | .mode = 0644, |
203 | .proc_handler = proc_dointvec_minmax, | 203 | .proc_handler = proc_dointvec_minmax, |
204 | .extra1 = &one, | 204 | .extra1 = &one, |
205 | .extra2 = &int_max | 205 | .extra2 = &int_max |
206 | }, | 206 | }, |
207 | { | 207 | { |
208 | .procname = "max_init_retransmits", | 208 | .procname = "max_init_retransmits", |
209 | .data = &init_net.sctp.max_retrans_init, | 209 | .data = &init_net.sctp.max_retrans_init, |
210 | .maxlen = sizeof(int), | 210 | .maxlen = sizeof(int), |
211 | .mode = 0644, | 211 | .mode = 0644, |
212 | .proc_handler = proc_dointvec_minmax, | 212 | .proc_handler = proc_dointvec_minmax, |
213 | .extra1 = &one, | 213 | .extra1 = &one, |
214 | .extra2 = &int_max | 214 | .extra2 = &int_max |
215 | }, | 215 | }, |
216 | { | 216 | { |
217 | .procname = "pf_retrans", | 217 | .procname = "pf_retrans", |
218 | .data = &init_net.sctp.pf_retrans, | 218 | .data = &init_net.sctp.pf_retrans, |
219 | .maxlen = sizeof(int), | 219 | .maxlen = sizeof(int), |
220 | .mode = 0644, | 220 | .mode = 0644, |
221 | .proc_handler = proc_dointvec_minmax, | 221 | .proc_handler = proc_dointvec_minmax, |
222 | .extra1 = &zero, | 222 | .extra1 = &zero, |
223 | .extra2 = &int_max | 223 | .extra2 = &int_max |
224 | }, | 224 | }, |
225 | { | 225 | { |
226 | .procname = "sndbuf_policy", | 226 | .procname = "sndbuf_policy", |
227 | .data = &init_net.sctp.sndbuf_policy, | 227 | .data = &init_net.sctp.sndbuf_policy, |
228 | .maxlen = sizeof(int), | 228 | .maxlen = sizeof(int), |
229 | .mode = 0644, | 229 | .mode = 0644, |
230 | .proc_handler = proc_dointvec, | 230 | .proc_handler = proc_dointvec, |
231 | }, | 231 | }, |
232 | { | 232 | { |
233 | .procname = "rcvbuf_policy", | 233 | .procname = "rcvbuf_policy", |
234 | .data = &init_net.sctp.rcvbuf_policy, | 234 | .data = &init_net.sctp.rcvbuf_policy, |
235 | .maxlen = sizeof(int), | 235 | .maxlen = sizeof(int), |
236 | .mode = 0644, | 236 | .mode = 0644, |
237 | .proc_handler = proc_dointvec, | 237 | .proc_handler = proc_dointvec, |
238 | }, | 238 | }, |
239 | { | 239 | { |
240 | .procname = "default_auto_asconf", | 240 | .procname = "default_auto_asconf", |
241 | .data = &init_net.sctp.default_auto_asconf, | 241 | .data = &init_net.sctp.default_auto_asconf, |
242 | .maxlen = sizeof(int), | 242 | .maxlen = sizeof(int), |
243 | .mode = 0644, | 243 | .mode = 0644, |
244 | .proc_handler = proc_dointvec, | 244 | .proc_handler = proc_dointvec, |
245 | }, | 245 | }, |
246 | { | 246 | { |
247 | .procname = "addip_enable", | 247 | .procname = "addip_enable", |
248 | .data = &init_net.sctp.addip_enable, | 248 | .data = &init_net.sctp.addip_enable, |
249 | .maxlen = sizeof(int), | 249 | .maxlen = sizeof(int), |
250 | .mode = 0644, | 250 | .mode = 0644, |
251 | .proc_handler = proc_dointvec, | 251 | .proc_handler = proc_dointvec, |
252 | }, | 252 | }, |
253 | { | 253 | { |
254 | .procname = "addip_noauth_enable", | 254 | .procname = "addip_noauth_enable", |
255 | .data = &init_net.sctp.addip_noauth, | 255 | .data = &init_net.sctp.addip_noauth, |
256 | .maxlen = sizeof(int), | 256 | .maxlen = sizeof(int), |
257 | .mode = 0644, | 257 | .mode = 0644, |
258 | .proc_handler = proc_dointvec, | 258 | .proc_handler = proc_dointvec, |
259 | }, | 259 | }, |
260 | { | 260 | { |
261 | .procname = "prsctp_enable", | 261 | .procname = "prsctp_enable", |
262 | .data = &init_net.sctp.prsctp_enable, | 262 | .data = &init_net.sctp.prsctp_enable, |
263 | .maxlen = sizeof(int), | 263 | .maxlen = sizeof(int), |
264 | .mode = 0644, | 264 | .mode = 0644, |
265 | .proc_handler = proc_dointvec, | 265 | .proc_handler = proc_dointvec, |
266 | }, | 266 | }, |
267 | { | 267 | { |
268 | .procname = "auth_enable", | 268 | .procname = "auth_enable", |
269 | .data = &init_net.sctp.auth_enable, | 269 | .data = &init_net.sctp.auth_enable, |
270 | .maxlen = sizeof(int), | 270 | .maxlen = sizeof(int), |
271 | .mode = 0644, | 271 | .mode = 0644, |
272 | .proc_handler = proc_sctp_do_auth, | 272 | .proc_handler = proc_sctp_do_auth, |
273 | }, | 273 | }, |
274 | { | 274 | { |
275 | .procname = "addr_scope_policy", | 275 | .procname = "addr_scope_policy", |
276 | .data = &init_net.sctp.scope_policy, | 276 | .data = &init_net.sctp.scope_policy, |
277 | .maxlen = sizeof(int), | 277 | .maxlen = sizeof(int), |
278 | .mode = 0644, | 278 | .mode = 0644, |
279 | .proc_handler = proc_dointvec_minmax, | 279 | .proc_handler = proc_dointvec_minmax, |
280 | .extra1 = &zero, | 280 | .extra1 = &zero, |
281 | .extra2 = &addr_scope_max, | 281 | .extra2 = &addr_scope_max, |
282 | }, | 282 | }, |
283 | { | 283 | { |
284 | .procname = "rwnd_update_shift", | 284 | .procname = "rwnd_update_shift", |
285 | .data = &init_net.sctp.rwnd_upd_shift, | 285 | .data = &init_net.sctp.rwnd_upd_shift, |
286 | .maxlen = sizeof(int), | 286 | .maxlen = sizeof(int), |
287 | .mode = 0644, | 287 | .mode = 0644, |
288 | .proc_handler = &proc_dointvec_minmax, | 288 | .proc_handler = &proc_dointvec_minmax, |
289 | .extra1 = &one, | 289 | .extra1 = &one, |
290 | .extra2 = &rwnd_scale_max, | 290 | .extra2 = &rwnd_scale_max, |
291 | }, | 291 | }, |
292 | { | 292 | { |
293 | .procname = "max_autoclose", | 293 | .procname = "max_autoclose", |
294 | .data = &init_net.sctp.max_autoclose, | 294 | .data = &init_net.sctp.max_autoclose, |
295 | .maxlen = sizeof(unsigned long), | 295 | .maxlen = sizeof(unsigned long), |
296 | .mode = 0644, | 296 | .mode = 0644, |
297 | .proc_handler = &proc_doulongvec_minmax, | 297 | .proc_handler = &proc_doulongvec_minmax, |
298 | .extra1 = &max_autoclose_min, | 298 | .extra1 = &max_autoclose_min, |
299 | .extra2 = &max_autoclose_max, | 299 | .extra2 = &max_autoclose_max, |
300 | }, | 300 | }, |
301 | 301 | ||
302 | { /* sentinel */ } | 302 | { /* sentinel */ } |
303 | }; | 303 | }; |
304 | 304 | ||
305 | static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write, | 305 | static int proc_sctp_do_hmac_alg(struct ctl_table *ctl, int write, |
306 | void __user *buffer, size_t *lenp, | 306 | void __user *buffer, size_t *lenp, |
307 | loff_t *ppos) | 307 | loff_t *ppos) |
308 | { | 308 | { |
309 | struct net *net = current->nsproxy->net_ns; | 309 | struct net *net = current->nsproxy->net_ns; |
310 | char tmp[8]; | 310 | char tmp[8]; |
311 | struct ctl_table tbl; | 311 | struct ctl_table tbl; |
312 | int ret; | 312 | int ret; |
313 | int changed = 0; | 313 | int changed = 0; |
314 | char *none = "none"; | 314 | char *none = "none"; |
315 | 315 | ||
316 | memset(&tbl, 0, sizeof(struct ctl_table)); | 316 | memset(&tbl, 0, sizeof(struct ctl_table)); |
317 | 317 | ||
318 | if (write) { | 318 | if (write) { |
319 | tbl.data = tmp; | 319 | tbl.data = tmp; |
320 | tbl.maxlen = 8; | 320 | tbl.maxlen = 8; |
321 | } else { | 321 | } else { |
322 | tbl.data = net->sctp.sctp_hmac_alg ? : none; | 322 | tbl.data = net->sctp.sctp_hmac_alg ? : none; |
323 | tbl.maxlen = strlen(tbl.data); | 323 | tbl.maxlen = strlen(tbl.data); |
324 | } | 324 | } |
325 | ret = proc_dostring(&tbl, write, buffer, lenp, ppos); | 325 | ret = proc_dostring(&tbl, write, buffer, lenp, ppos); |
326 | 326 | ||
327 | if (write) { | 327 | if (write) { |
328 | #ifdef CONFIG_CRYPTO_MD5 | 328 | #ifdef CONFIG_CRYPTO_MD5 |
329 | if (!strncmp(tmp, "md5", 3)) { | 329 | if (!strncmp(tmp, "md5", 3)) { |
330 | net->sctp.sctp_hmac_alg = "md5"; | 330 | net->sctp.sctp_hmac_alg = "md5"; |
331 | changed = 1; | 331 | changed = 1; |
332 | } | 332 | } |
333 | #endif | 333 | #endif |
334 | #ifdef CONFIG_CRYPTO_SHA1 | 334 | #ifdef CONFIG_CRYPTO_SHA1 |
335 | if (!strncmp(tmp, "sha1", 4)) { | 335 | if (!strncmp(tmp, "sha1", 4)) { |
336 | net->sctp.sctp_hmac_alg = "sha1"; | 336 | net->sctp.sctp_hmac_alg = "sha1"; |
337 | changed = 1; | 337 | changed = 1; |
338 | } | 338 | } |
339 | #endif | 339 | #endif |
340 | if (!strncmp(tmp, "none", 4)) { | 340 | if (!strncmp(tmp, "none", 4)) { |
341 | net->sctp.sctp_hmac_alg = NULL; | 341 | net->sctp.sctp_hmac_alg = NULL; |
342 | changed = 1; | 342 | changed = 1; |
343 | } | 343 | } |
344 | 344 | ||
345 | if (!changed) | 345 | if (!changed) |
346 | ret = -EINVAL; | 346 | ret = -EINVAL; |
347 | } | 347 | } |
348 | 348 | ||
349 | return ret; | 349 | return ret; |
350 | } | 350 | } |
351 | 351 | ||
352 | static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, | 352 | static int proc_sctp_do_rto_min(struct ctl_table *ctl, int write, |
353 | void __user *buffer, size_t *lenp, | 353 | void __user *buffer, size_t *lenp, |
354 | loff_t *ppos) | 354 | loff_t *ppos) |
355 | { | 355 | { |
356 | struct net *net = current->nsproxy->net_ns; | 356 | struct net *net = current->nsproxy->net_ns; |
357 | int new_value; | 357 | int new_value; |
358 | struct ctl_table tbl; | 358 | struct ctl_table tbl; |
359 | unsigned int min = *(unsigned int *) ctl->extra1; | 359 | unsigned int min = *(unsigned int *) ctl->extra1; |
360 | unsigned int max = *(unsigned int *) ctl->extra2; | 360 | unsigned int max = *(unsigned int *) ctl->extra2; |
361 | int ret; | 361 | int ret; |
362 | 362 | ||
363 | memset(&tbl, 0, sizeof(struct ctl_table)); | 363 | memset(&tbl, 0, sizeof(struct ctl_table)); |
364 | tbl.maxlen = sizeof(unsigned int); | 364 | tbl.maxlen = sizeof(unsigned int); |
365 | 365 | ||
366 | if (write) | 366 | if (write) |
367 | tbl.data = &new_value; | 367 | tbl.data = &new_value; |
368 | else | 368 | else |
369 | tbl.data = &net->sctp.rto_min; | 369 | tbl.data = &net->sctp.rto_min; |
370 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); | 370 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); |
371 | if (write) { | 371 | if (write) { |
372 | if (ret || new_value > max || new_value < min) | 372 | if (ret || new_value > max || new_value < min) |
373 | return -EINVAL; | 373 | return -EINVAL; |
374 | net->sctp.rto_min = new_value; | 374 | net->sctp.rto_min = new_value; |
375 | } | 375 | } |
376 | return ret; | 376 | return ret; |
377 | } | 377 | } |
378 | 378 | ||
379 | static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, | 379 | static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, |
380 | void __user *buffer, size_t *lenp, | 380 | void __user *buffer, size_t *lenp, |
381 | loff_t *ppos) | 381 | loff_t *ppos) |
382 | { | 382 | { |
383 | struct net *net = current->nsproxy->net_ns; | 383 | struct net *net = current->nsproxy->net_ns; |
384 | int new_value; | 384 | int new_value; |
385 | struct ctl_table tbl; | 385 | struct ctl_table tbl; |
386 | unsigned int min = *(unsigned int *) ctl->extra1; | 386 | unsigned int min = *(unsigned int *) ctl->extra1; |
387 | unsigned int max = *(unsigned int *) ctl->extra2; | 387 | unsigned int max = *(unsigned int *) ctl->extra2; |
388 | int ret; | 388 | int ret; |
389 | 389 | ||
390 | memset(&tbl, 0, sizeof(struct ctl_table)); | 390 | memset(&tbl, 0, sizeof(struct ctl_table)); |
391 | tbl.maxlen = sizeof(unsigned int); | 391 | tbl.maxlen = sizeof(unsigned int); |
392 | 392 | ||
393 | if (write) | 393 | if (write) |
394 | tbl.data = &new_value; | 394 | tbl.data = &new_value; |
395 | else | 395 | else |
396 | tbl.data = &net->sctp.rto_max; | 396 | tbl.data = &net->sctp.rto_max; |
397 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); | 397 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); |
398 | if (write) { | 398 | if (write) { |
399 | if (ret || new_value > max || new_value < min) | 399 | if (ret || new_value > max || new_value < min) |
400 | return -EINVAL; | 400 | return -EINVAL; |
401 | net->sctp.rto_max = new_value; | 401 | net->sctp.rto_max = new_value; |
402 | } | 402 | } |
403 | return ret; | 403 | return ret; |
404 | } | 404 | } |
405 | 405 | ||
406 | static int proc_sctp_do_auth(struct ctl_table *ctl, int write, | 406 | static int proc_sctp_do_auth(struct ctl_table *ctl, int write, |
407 | void __user *buffer, size_t *lenp, | 407 | void __user *buffer, size_t *lenp, |
408 | loff_t *ppos) | 408 | loff_t *ppos) |
409 | { | 409 | { |
410 | struct net *net = current->nsproxy->net_ns; | 410 | struct net *net = current->nsproxy->net_ns; |
411 | struct ctl_table tbl; | 411 | struct ctl_table tbl; |
412 | int new_value, ret; | 412 | int new_value, ret; |
413 | 413 | ||
414 | memset(&tbl, 0, sizeof(struct ctl_table)); | 414 | memset(&tbl, 0, sizeof(struct ctl_table)); |
415 | tbl.maxlen = sizeof(unsigned int); | 415 | tbl.maxlen = sizeof(unsigned int); |
416 | 416 | ||
417 | if (write) | 417 | if (write) |
418 | tbl.data = &new_value; | 418 | tbl.data = &new_value; |
419 | else | 419 | else |
420 | tbl.data = &net->sctp.auth_enable; | 420 | tbl.data = &net->sctp.auth_enable; |
421 | 421 | ||
422 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); | 422 | ret = proc_dointvec(&tbl, write, buffer, lenp, ppos); |
423 | 423 | ||
424 | if (write) { | 424 | if (write) { |
425 | struct sock *sk = net->sctp.ctl_sock; | 425 | struct sock *sk = net->sctp.ctl_sock; |
426 | 426 | ||
427 | net->sctp.auth_enable = new_value; | 427 | net->sctp.auth_enable = new_value; |
428 | /* Update the value in the control socket */ | 428 | /* Update the value in the control socket */ |
429 | lock_sock(sk); | 429 | lock_sock(sk); |
430 | sctp_sk(sk)->ep->auth_enable = new_value; | 430 | sctp_sk(sk)->ep->auth_enable = new_value; |
431 | release_sock(sk); | 431 | release_sock(sk); |
432 | } | 432 | } |
433 | 433 | ||
434 | return ret; | 434 | return ret; |
435 | } | 435 | } |
436 | 436 | ||
437 | int sctp_sysctl_net_register(struct net *net) | 437 | int sctp_sysctl_net_register(struct net *net) |
438 | { | 438 | { |
439 | struct ctl_table *table = sctp_net_table; | 439 | struct ctl_table *table; |
440 | int i; | ||
440 | 441 | ||
441 | if (!net_eq(net, &init_net)) { | 442 | table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL); |
442 | int i; | 443 | if (!table) |
444 | return -ENOMEM; | ||
443 | 445 | ||
444 | table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL); | 446 | for (i = 0; table[i].data; i++) |
445 | if (!table) | 447 | table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp; |
446 | return -ENOMEM; | ||
447 | |||
448 | for (i = 0; table[i].data; i++) | ||
449 | table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp; | ||
450 | } | ||
451 | 448 | ||
452 | net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table); | 449 | net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table); |
453 | return 0; | 450 | return 0; |
454 | } | 451 | } |
455 | 452 | ||
456 | void sctp_sysctl_net_unregister(struct net *net) | 453 | void sctp_sysctl_net_unregister(struct net *net) |
457 | { | 454 | { |
458 | struct ctl_table *table; | 455 | struct ctl_table *table; |
459 | 456 | ||
460 | table = net->sctp.sysctl_header->ctl_table_arg; | 457 | table = net->sctp.sysctl_header->ctl_table_arg; |
461 | unregister_net_sysctl_table(net->sctp.sysctl_header); | 458 | unregister_net_sysctl_table(net->sctp.sysctl_header); |
462 | kfree(table); | 459 | kfree(table); |
463 | } | 460 | } |
464 | 461 | ||
465 | static struct ctl_table_header *sctp_sysctl_header; | 462 | static struct ctl_table_header *sctp_sysctl_header; |
466 | 463 | ||
467 | /* Sysctl registration. */ | 464 | /* Sysctl registration. */ |
468 | void sctp_sysctl_register(void) | 465 | void sctp_sysctl_register(void) |
469 | { | 466 | { |
470 | sctp_sysctl_header = register_net_sysctl(&init_net, "net/sctp", sctp_table); | 467 | sctp_sysctl_header = register_net_sysctl(&init_net, "net/sctp", sctp_table); |
471 | } | 468 | } |
472 | 469 | ||
473 | /* Sysctl deregistration. */ | 470 | /* Sysctl deregistration. */ |
474 | void sctp_sysctl_unregister(void) | 471 | void sctp_sysctl_unregister(void) |
475 | { | 472 | { |
476 | unregister_net_sysctl_table(sctp_sysctl_header); | 473 | unregister_net_sysctl_table(sctp_sysctl_header); |