Commit b14878ccb7fac0242db82720b784ab62c467c0dc

Authored by Vlad Yasevich
Committed by David S. Miller
1 parent 5a292f7bc6

net: sctp: cache auth_enable per endpoint

Currently, it is possible to create an SCTP socket, then switch
auth_enable via sysctl setting to 1 and crash the system on connect:

Oops[#1]:
CPU: 0 PID: 0 Comm: swapper Not tainted 3.14.1-mipsgit-20140415 #1
task: ffffffff8056ce80 ti: ffffffff8055c000 task.ti: ffffffff8055c000
[...]
Call Trace:
[<ffffffff8043c4e8>] sctp_auth_asoc_set_default_hmac+0x68/0x80
[<ffffffff8042b300>] sctp_process_init+0x5e0/0x8a4
[<ffffffff8042188c>] sctp_sf_do_5_1B_init+0x234/0x34c
[<ffffffff804228c8>] sctp_do_sm+0xb4/0x1e8
[<ffffffff80425a08>] sctp_endpoint_bh_rcv+0x1c4/0x214
[<ffffffff8043af68>] sctp_rcv+0x588/0x630
[<ffffffff8043e8e8>] sctp6_rcv+0x10/0x24
[<ffffffff803acb50>] ip6_input+0x2c0/0x440
[<ffffffff8030fc00>] __netif_receive_skb_core+0x4a8/0x564
[<ffffffff80310650>] process_backlog+0xb4/0x18c
[<ffffffff80313cbc>] net_rx_action+0x12c/0x210
[<ffffffff80034254>] __do_softirq+0x17c/0x2ac
[<ffffffff800345e0>] irq_exit+0x54/0xb0
[<ffffffff800075a4>] ret_from_irq+0x0/0x4
[<ffffffff800090ec>] rm7k_wait_irqoff+0x24/0x48
[<ffffffff8005e388>] cpu_startup_entry+0xc0/0x148
[<ffffffff805a88b0>] start_kernel+0x37c/0x398
Code: dd0900b8  000330f8  0126302d <dcc60000> 50c0fff1  0047182a  a48306a0
03e00008  00000000
---[ end trace b530b0551467f2fd ]---
Kernel panic - not syncing: Fatal exception in interrupt

What happens while auth_enable=0 in that case is, that
ep->auth_hmacs is initialized to NULL in sctp_auth_init_hmacs()
when endpoint is being created.

After that point, if an admin switches over to auth_enable=1,
the machine can crash due to NULL pointer dereference during
reception of an INIT chunk. When we enter sctp_process_init()
via sctp_sf_do_5_1B_init() in order to respond to an INIT chunk,
the INIT verification succeeds and while we walk and process
all INIT params via sctp_process_param() we find that
net->sctp.auth_enable is set, therefore do not fall through,
but invoke sctp_auth_asoc_set_default_hmac() instead, and thus,
dereference what we have set to NULL during endpoint
initialization phase.

The fix is to make auth_enable immutable by caching its value
during endpoint initialization, so that its original value is
being carried along until destruction. The bug seems to originate
from the very first days.

Fix in joint work with Daniel Borkmann.

Reported-by: Joshua Kinard <kumba@gentoo.org>
Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Tested-by: Joshua Kinard <kumba@gentoo.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 7 changed files with 92 additions and 60 deletions Side-by-side Diff

include/net/sctp/structs.h
... ... @@ -1241,6 +1241,7 @@
1241 1241 /* SCTP-AUTH: endpoint shared keys */
1242 1242 struct list_head endpoint_shared_keys;
1243 1243 __u16 active_key_id;
  1244 + __u8 auth_enable;
1244 1245 };
1245 1246  
1246 1247 /* Recover the outter endpoint structure. */
... ... @@ -1269,7 +1270,8 @@
1269 1270 int sctp_has_association(struct net *net, const union sctp_addr *laddr,
1270 1271 const union sctp_addr *paddr);
1271 1272  
1272   -int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
  1273 +int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
  1274 + const struct sctp_association *asoc,
1273 1275 sctp_cid_t, sctp_init_chunk_t *peer_init,
1274 1276 struct sctp_chunk *chunk, struct sctp_chunk **err_chunk);
1275 1277 int sctp_process_init(struct sctp_association *, struct sctp_chunk *chunk,
... ... @@ -386,14 +386,13 @@
386 386 */
387 387 int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
388 388 {
389   - struct net *net = sock_net(asoc->base.sk);
390 389 struct sctp_auth_bytes *secret;
391 390 struct sctp_shared_key *ep_key;
392 391  
393 392 /* If we don't support AUTH, or peer is not capable
394 393 * we don't need to do anything.
395 394 */
396   - if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
  395 + if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
397 396 return 0;
398 397  
399 398 /* If the key_id is non-zero and we couldn't find an
400 399  
401 400  
... ... @@ -440,16 +439,16 @@
440 439 */
441 440 int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
442 441 {
443   - struct net *net = sock_net(ep->base.sk);
444 442 struct crypto_hash *tfm = NULL;
445 443 __u16 id;
446 444  
447   - /* if the transforms are already allocted, we are done */
448   - if (!net->sctp.auth_enable) {
  445 + /* If AUTH extension is disabled, we are done */
  446 + if (!ep->auth_enable) {
449 447 ep->auth_hmacs = NULL;
450 448 return 0;
451 449 }
452 450  
  451 + /* If the transforms are already allocated, we are done */
453 452 if (ep->auth_hmacs)
454 453 return 0;
455 454  
456 455  
... ... @@ -665,12 +664,10 @@
665 664 /* Check if peer requested that this chunk is authenticated */
666 665 int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
667 666 {
668   - struct net *net;
669 667 if (!asoc)
670 668 return 0;
671 669  
672   - net = sock_net(asoc->base.sk);
673   - if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
  670 + if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
674 671 return 0;
675 672  
676 673 return __sctp_auth_cid(chunk, asoc->peer.peer_chunks);
677 674  
... ... @@ -679,12 +676,10 @@
679 676 /* Check if we requested that peer authenticate this chunk. */
680 677 int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
681 678 {
682   - struct net *net;
683 679 if (!asoc)
684 680 return 0;
685 681  
686   - net = sock_net(asoc->base.sk);
687   - if (!net->sctp.auth_enable)
  682 + if (!asoc->ep->auth_enable)
688 683 return 0;
689 684  
690 685 return __sctp_auth_cid(chunk,
net/sctp/endpointola.c
... ... @@ -68,7 +68,8 @@
68 68 if (!ep->digest)
69 69 return NULL;
70 70  
71   - if (net->sctp.auth_enable) {
  71 + ep->auth_enable = net->sctp.auth_enable;
  72 + if (ep->auth_enable) {
72 73 /* Allocate space for HMACS and CHUNKS authentication
73 74 * variables. There are arrays that we encode directly
74 75 * into parameters to make the rest of the operations easier.
net/sctp/sm_make_chunk.c
... ... @@ -219,6 +219,7 @@
219 219 gfp_t gfp, int vparam_len)
220 220 {
221 221 struct net *net = sock_net(asoc->base.sk);
  222 + struct sctp_endpoint *ep = asoc->ep;
222 223 sctp_inithdr_t init;
223 224 union sctp_params addrs;
224 225 size_t chunksize;
... ... @@ -278,7 +279,7 @@
278 279 chunksize += vparam_len;
279 280  
280 281 /* Account for AUTH related parameters */
281   - if (net->sctp.auth_enable) {
  282 + if (ep->auth_enable) {
282 283 /* Add random parameter length*/
283 284 chunksize += sizeof(asoc->c.auth_random);
284 285  
... ... @@ -363,7 +364,7 @@
363 364 }
364 365  
365 366 /* Add SCTP-AUTH chunks to the parameter list */
366   - if (net->sctp.auth_enable) {
  367 + if (ep->auth_enable) {
367 368 sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
368 369 asoc->c.auth_random);
369 370 if (auth_hmacs)
... ... @@ -2010,7 +2011,7 @@
2010 2011 /* if the peer reports AUTH, assume that he
2011 2012 * supports AUTH.
2012 2013 */
2013   - if (net->sctp.auth_enable)
  2014 + if (asoc->ep->auth_enable)
2014 2015 asoc->peer.auth_capable = 1;
2015 2016 break;
2016 2017 case SCTP_CID_ASCONF:
... ... @@ -2102,6 +2103,7 @@
2102 2103 * SCTP_IERROR_NO_ERROR - continue with the chunk
2103 2104 */
2104 2105 static sctp_ierror_t sctp_verify_param(struct net *net,
  2106 + const struct sctp_endpoint *ep,
2105 2107 const struct sctp_association *asoc,
2106 2108 union sctp_params param,
2107 2109 sctp_cid_t cid,
... ... @@ -2152,7 +2154,7 @@
2152 2154 goto fallthrough;
2153 2155  
2154 2156 case SCTP_PARAM_RANDOM:
2155   - if (!net->sctp.auth_enable)
  2157 + if (!ep->auth_enable)
2156 2158 goto fallthrough;
2157 2159  
2158 2160 /* SCTP-AUTH: Secion 6.1
... ... @@ -2169,7 +2171,7 @@
2169 2171 break;
2170 2172  
2171 2173 case SCTP_PARAM_CHUNKS:
2172   - if (!net->sctp.auth_enable)
  2174 + if (!ep->auth_enable)
2173 2175 goto fallthrough;
2174 2176  
2175 2177 /* SCTP-AUTH: Section 3.2
... ... @@ -2185,7 +2187,7 @@
2185 2187 break;
2186 2188  
2187 2189 case SCTP_PARAM_HMAC_ALGO:
2188   - if (!net->sctp.auth_enable)
  2190 + if (!ep->auth_enable)
2189 2191 goto fallthrough;
2190 2192  
2191 2193 hmacs = (struct sctp_hmac_algo_param *)param.p;
... ... @@ -2220,10 +2222,9 @@
2220 2222 }
2221 2223  
2222 2224 /* Verify the INIT packet before we process it. */
2223   -int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
2224   - sctp_cid_t cid,
2225   - sctp_init_chunk_t *peer_init,
2226   - struct sctp_chunk *chunk,
  2225 +int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
  2226 + const struct sctp_association *asoc, sctp_cid_t cid,
  2227 + sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk,
2227 2228 struct sctp_chunk **errp)
2228 2229 {
2229 2230 union sctp_params param;
... ... @@ -2264,8 +2265,8 @@
2264 2265  
2265 2266 /* Verify all the variable length parameters */
2266 2267 sctp_walk_params(param, peer_init, init_hdr.params) {
2267   -
2268   - result = sctp_verify_param(net, asoc, param, cid, chunk, errp);
  2268 + result = sctp_verify_param(net, ep, asoc, param, cid,
  2269 + chunk, errp);
2269 2270 switch (result) {
2270 2271 case SCTP_IERROR_ABORT:
2271 2272 case SCTP_IERROR_NOMEM:
... ... @@ -2497,6 +2498,7 @@
2497 2498 struct sctp_af *af;
2498 2499 union sctp_addr_param *addr_param;
2499 2500 struct sctp_transport *t;
  2501 + struct sctp_endpoint *ep = asoc->ep;
2500 2502  
2501 2503 /* We maintain all INIT parameters in network byte order all the
2502 2504 * time. This allows us to not worry about whether the parameters
... ... @@ -2636,7 +2638,7 @@
2636 2638 goto fall_through;
2637 2639  
2638 2640 case SCTP_PARAM_RANDOM:
2639   - if (!net->sctp.auth_enable)
  2641 + if (!ep->auth_enable)
2640 2642 goto fall_through;
2641 2643  
2642 2644 /* Save peer's random parameter */
... ... @@ -2649,7 +2651,7 @@
2649 2651 break;
2650 2652  
2651 2653 case SCTP_PARAM_HMAC_ALGO:
2652   - if (!net->sctp.auth_enable)
  2654 + if (!ep->auth_enable)
2653 2655 goto fall_through;
2654 2656  
2655 2657 /* Save peer's HMAC list */
... ... @@ -2665,7 +2667,7 @@
2665 2667 break;
2666 2668  
2667 2669 case SCTP_PARAM_CHUNKS:
2668   - if (!net->sctp.auth_enable)
  2670 + if (!ep->auth_enable)
2669 2671 goto fall_through;
2670 2672  
2671 2673 asoc->peer.peer_chunks = kmemdup(param.p,
net/sctp/sm_statefuns.c
... ... @@ -357,7 +357,7 @@
357 357  
358 358 /* Verify the INIT chunk before processing it. */
359 359 err_chunk = NULL;
360   - if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
  360 + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
361 361 (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
362 362 &err_chunk)) {
363 363 /* This chunk contains fatal error. It is to be discarded.
... ... @@ -524,7 +524,7 @@
524 524  
525 525 /* Verify the INIT chunk before processing it. */
526 526 err_chunk = NULL;
527   - if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
  527 + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
528 528 (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
529 529 &err_chunk)) {
530 530  
... ... @@ -1430,7 +1430,7 @@
1430 1430  
1431 1431 /* Verify the INIT chunk before processing it. */
1432 1432 err_chunk = NULL;
1433   - if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
  1433 + if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
1434 1434 (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
1435 1435 &err_chunk)) {
1436 1436 /* This chunk contains fatal error. It is to be discarded.
... ... @@ -3321,10 +3321,10 @@
3321 3321 char __user *optval,
3322 3322 unsigned int optlen)
3323 3323 {
3324   - struct net *net = sock_net(sk);
  3324 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3325 3325 struct sctp_authchunk val;
3326 3326  
3327   - if (!net->sctp.auth_enable)
  3327 + if (!ep->auth_enable)
3328 3328 return -EACCES;
3329 3329  
3330 3330 if (optlen != sizeof(struct sctp_authchunk))
... ... @@ -3341,7 +3341,7 @@
3341 3341 }
3342 3342  
3343 3343 /* add this chunk id to the endpoint */
3344   - return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk);
  3344 + return sctp_auth_ep_add_chunkid(ep, val.sauth_chunk);
3345 3345 }
3346 3346  
3347 3347 /*
3348 3348  
... ... @@ -3354,12 +3354,12 @@
3354 3354 char __user *optval,
3355 3355 unsigned int optlen)
3356 3356 {
3357   - struct net *net = sock_net(sk);
  3357 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3358 3358 struct sctp_hmacalgo *hmacs;
3359 3359 u32 idents;
3360 3360 int err;
3361 3361  
3362   - if (!net->sctp.auth_enable)
  3362 + if (!ep->auth_enable)
3363 3363 return -EACCES;
3364 3364  
3365 3365 if (optlen < sizeof(struct sctp_hmacalgo))
... ... @@ -3376,7 +3376,7 @@
3376 3376 goto out;
3377 3377 }
3378 3378  
3379   - err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs);
  3379 + err = sctp_auth_ep_set_hmacs(ep, hmacs);
3380 3380 out:
3381 3381 kfree(hmacs);
3382 3382 return err;
3383 3383  
... ... @@ -3392,12 +3392,12 @@
3392 3392 char __user *optval,
3393 3393 unsigned int optlen)
3394 3394 {
3395   - struct net *net = sock_net(sk);
  3395 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3396 3396 struct sctp_authkey *authkey;
3397 3397 struct sctp_association *asoc;
3398 3398 int ret;
3399 3399  
3400   - if (!net->sctp.auth_enable)
  3400 + if (!ep->auth_enable)
3401 3401 return -EACCES;
3402 3402  
3403 3403 if (optlen <= sizeof(struct sctp_authkey))
... ... @@ -3418,7 +3418,7 @@
3418 3418 goto out;
3419 3419 }
3420 3420  
3421   - ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey);
  3421 + ret = sctp_auth_set_key(ep, asoc, authkey);
3422 3422 out:
3423 3423 kzfree(authkey);
3424 3424 return ret;
3425 3425  
... ... @@ -3434,11 +3434,11 @@
3434 3434 char __user *optval,
3435 3435 unsigned int optlen)
3436 3436 {
3437   - struct net *net = sock_net(sk);
  3437 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3438 3438 struct sctp_authkeyid val;
3439 3439 struct sctp_association *asoc;
3440 3440  
3441   - if (!net->sctp.auth_enable)
  3441 + if (!ep->auth_enable)
3442 3442 return -EACCES;
3443 3443  
3444 3444 if (optlen != sizeof(struct sctp_authkeyid))
... ... @@ -3450,8 +3450,7 @@
3450 3450 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
3451 3451 return -EINVAL;
3452 3452  
3453   - return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc,
3454   - val.scact_keynumber);
  3453 + return sctp_auth_set_active_key(ep, asoc, val.scact_keynumber);
3455 3454 }
3456 3455  
3457 3456 /*
3458 3457  
... ... @@ -3463,11 +3462,11 @@
3463 3462 char __user *optval,
3464 3463 unsigned int optlen)
3465 3464 {
3466   - struct net *net = sock_net(sk);
  3465 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
3467 3466 struct sctp_authkeyid val;
3468 3467 struct sctp_association *asoc;
3469 3468  
3470   - if (!net->sctp.auth_enable)
  3469 + if (!ep->auth_enable)
3471 3470 return -EACCES;
3472 3471  
3473 3472 if (optlen != sizeof(struct sctp_authkeyid))
... ... @@ -3479,8 +3478,7 @@
3479 3478 if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
3480 3479 return -EINVAL;
3481 3480  
3482   - return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc,
3483   - val.scact_keynumber);
  3481 + return sctp_auth_del_key_id(ep, asoc, val.scact_keynumber);
3484 3482  
3485 3483 }
3486 3484  
3487 3485  
3488 3486  
... ... @@ -5387,16 +5385,16 @@
5387 5385 static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
5388 5386 char __user *optval, int __user *optlen)
5389 5387 {
5390   - struct net *net = sock_net(sk);
  5388 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
5391 5389 struct sctp_hmacalgo __user *p = (void __user *)optval;
5392 5390 struct sctp_hmac_algo_param *hmacs;
5393 5391 __u16 data_len = 0;
5394 5392 u32 num_idents;
5395 5393  
5396   - if (!net->sctp.auth_enable)
  5394 + if (!ep->auth_enable)
5397 5395 return -EACCES;
5398 5396  
5399   - hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
  5397 + hmacs = ep->auth_hmacs_list;
5400 5398 data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t);
5401 5399  
5402 5400 if (len < sizeof(struct sctp_hmacalgo) + data_len)
5403 5401  
... ... @@ -5417,11 +5415,11 @@
5417 5415 static int sctp_getsockopt_active_key(struct sock *sk, int len,
5418 5416 char __user *optval, int __user *optlen)
5419 5417 {
5420   - struct net *net = sock_net(sk);
  5418 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
5421 5419 struct sctp_authkeyid val;
5422 5420 struct sctp_association *asoc;
5423 5421  
5424   - if (!net->sctp.auth_enable)
  5422 + if (!ep->auth_enable)
5425 5423 return -EACCES;
5426 5424  
5427 5425 if (len < sizeof(struct sctp_authkeyid))
... ... @@ -5436,7 +5434,7 @@
5436 5434 if (asoc)
5437 5435 val.scact_keynumber = asoc->active_key_id;
5438 5436 else
5439   - val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
  5437 + val.scact_keynumber = ep->active_key_id;
5440 5438  
5441 5439 len = sizeof(struct sctp_authkeyid);
5442 5440 if (put_user(len, optlen))
... ... @@ -5450,7 +5448,7 @@
5450 5448 static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
5451 5449 char __user *optval, int __user *optlen)
5452 5450 {
5453   - struct net *net = sock_net(sk);
  5451 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
5454 5452 struct sctp_authchunks __user *p = (void __user *)optval;
5455 5453 struct sctp_authchunks val;
5456 5454 struct sctp_association *asoc;
... ... @@ -5458,7 +5456,7 @@
5458 5456 u32 num_chunks = 0;
5459 5457 char __user *to;
5460 5458  
5461   - if (!net->sctp.auth_enable)
  5459 + if (!ep->auth_enable)
5462 5460 return -EACCES;
5463 5461  
5464 5462 if (len < sizeof(struct sctp_authchunks))
... ... @@ -5495,7 +5493,7 @@
5495 5493 static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
5496 5494 char __user *optval, int __user *optlen)
5497 5495 {
5498   - struct net *net = sock_net(sk);
  5496 + struct sctp_endpoint *ep = sctp_sk(sk)->ep;
5499 5497 struct sctp_authchunks __user *p = (void __user *)optval;
5500 5498 struct sctp_authchunks val;
5501 5499 struct sctp_association *asoc;
... ... @@ -5503,7 +5501,7 @@
5503 5501 u32 num_chunks = 0;
5504 5502 char __user *to;
5505 5503  
5506   - if (!net->sctp.auth_enable)
  5504 + if (!ep->auth_enable)
5507 5505 return -EACCES;
5508 5506  
5509 5507 if (len < sizeof(struct sctp_authchunks))
... ... @@ -5520,7 +5518,7 @@
5520 5518 if (asoc)
5521 5519 ch = (struct sctp_chunks_param *)asoc->c.auth_chunks;
5522 5520 else
5523   - ch = sctp_sk(sk)->ep->auth_chunk_list;
  5521 + ch = ep->auth_chunk_list;
5524 5522  
5525 5523 if (!ch)
5526 5524 goto num;
... ... @@ -64,6 +64,9 @@
64 64 static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write,
65 65 void __user *buffer, size_t *lenp,
66 66 loff_t *ppos);
  67 +static int proc_sctp_do_auth(struct ctl_table *ctl, int write,
  68 + void __user *buffer, size_t *lenp,
  69 + loff_t *ppos);
67 70  
68 71 static struct ctl_table sctp_table[] = {
69 72 {
... ... @@ -266,7 +269,7 @@
266 269 .data = &init_net.sctp.auth_enable,
267 270 .maxlen = sizeof(int),
268 271 .mode = 0644,
269   - .proc_handler = proc_dointvec,
  272 + .proc_handler = proc_sctp_do_auth,
270 273 },
271 274 {
272 275 .procname = "addr_scope_policy",
... ... @@ -397,6 +400,37 @@
397 400 return -EINVAL;
398 401 net->sctp.rto_max = new_value;
399 402 }
  403 + return ret;
  404 +}
  405 +
  406 +static int proc_sctp_do_auth(struct ctl_table *ctl, int write,
  407 + void __user *buffer, size_t *lenp,
  408 + loff_t *ppos)
  409 +{
  410 + struct net *net = current->nsproxy->net_ns;
  411 + struct ctl_table tbl;
  412 + int new_value, ret;
  413 +
  414 + memset(&tbl, 0, sizeof(struct ctl_table));
  415 + tbl.maxlen = sizeof(unsigned int);
  416 +
  417 + if (write)
  418 + tbl.data = &new_value;
  419 + else
  420 + tbl.data = &net->sctp.auth_enable;
  421 +
  422 + ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
  423 +
  424 + if (write) {
  425 + struct sock *sk = net->sctp.ctl_sock;
  426 +
  427 + net->sctp.auth_enable = new_value;
  428 + /* Update the value in the control socket */
  429 + lock_sock(sk);
  430 + sctp_sk(sk)->ep->auth_enable = new_value;
  431 + release_sock(sk);
  432 + }
  433 +
400 434 return ret;
401 435 }
402 436