Skip to content

Commit b14878c

Browse files
Vlad Yasevichdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: Vlad Yasevich <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Neil Horman <[email protected]> Tested-by: Joshua Kinard <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5a292f7 commit b14878c

File tree

7 files changed

+92
-60
lines changed

7 files changed

+92
-60
lines changed

include/net/sctp/structs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,7 @@ struct sctp_endpoint {
12411241
/* SCTP-AUTH: endpoint shared keys */
12421242
struct list_head endpoint_shared_keys;
12431243
__u16 active_key_id;
1244+
__u8 auth_enable;
12441245
};
12451246

12461247
/* Recover the outter endpoint structure. */
@@ -1269,7 +1270,8 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *,
12691270
int sctp_has_association(struct net *net, const union sctp_addr *laddr,
12701271
const union sctp_addr *paddr);
12711272

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,
12731275
sctp_cid_t, sctp_init_chunk_t *peer_init,
12741276
struct sctp_chunk *chunk, struct sctp_chunk **err_chunk);
12751277
int sctp_process_init(struct sctp_association *, struct sctp_chunk *chunk,

net/sctp/auth.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,13 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep,
386386
*/
387387
int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
388388
{
389-
struct net *net = sock_net(asoc->base.sk);
390389
struct sctp_auth_bytes *secret;
391390
struct sctp_shared_key *ep_key;
392391

393392
/* If we don't support AUTH, or peer is not capable
394393
* we don't need to do anything.
395394
*/
396-
if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
395+
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
397396
return 0;
398397

399398
/* If the key_id is non-zero and we couldn't find an
@@ -440,16 +439,16 @@ struct sctp_shared_key *sctp_auth_get_shkey(
440439
*/
441440
int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
442441
{
443-
struct net *net = sock_net(ep->base.sk);
444442
struct crypto_hash *tfm = NULL;
445443
__u16 id;
446444

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) {
449447
ep->auth_hmacs = NULL;
450448
return 0;
451449
}
452450

451+
/* If the transforms are already allocated, we are done */
453452
if (ep->auth_hmacs)
454453
return 0;
455454

@@ -665,12 +664,10 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param)
665664
/* Check if peer requested that this chunk is authenticated */
666665
int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
667666
{
668-
struct net *net;
669667
if (!asoc)
670668
return 0;
671669

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)
674671
return 0;
675672

676673
return __sctp_auth_cid(chunk, asoc->peer.peer_chunks);
@@ -679,12 +676,10 @@ int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
679676
/* Check if we requested that peer authenticate this chunk. */
680677
int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
681678
{
682-
struct net *net;
683679
if (!asoc)
684680
return 0;
685681

686-
net = sock_net(asoc->base.sk);
687-
if (!net->sctp.auth_enable)
682+
if (!asoc->ep->auth_enable)
688683
return 0;
689684

690685
return __sctp_auth_cid(chunk,

net/sctp/endpointola.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
6868
if (!ep->digest)
6969
return NULL;
7070

71-
if (net->sctp.auth_enable) {
71+
ep->auth_enable = net->sctp.auth_enable;
72+
if (ep->auth_enable) {
7273
/* Allocate space for HMACS and CHUNKS authentication
7374
* variables. There are arrays that we encode directly
7475
* into parameters to make the rest of the operations easier.

net/sctp/sm_make_chunk.c

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
219219
gfp_t gfp, int vparam_len)
220220
{
221221
struct net *net = sock_net(asoc->base.sk);
222+
struct sctp_endpoint *ep = asoc->ep;
222223
sctp_inithdr_t init;
223224
union sctp_params addrs;
224225
size_t chunksize;
@@ -278,7 +279,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
278279
chunksize += vparam_len;
279280

280281
/* Account for AUTH related parameters */
281-
if (net->sctp.auth_enable) {
282+
if (ep->auth_enable) {
282283
/* Add random parameter length*/
283284
chunksize += sizeof(asoc->c.auth_random);
284285

@@ -363,7 +364,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
363364
}
364365

365366
/* Add SCTP-AUTH chunks to the parameter list */
366-
if (net->sctp.auth_enable) {
367+
if (ep->auth_enable) {
367368
sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
368369
asoc->c.auth_random);
369370
if (auth_hmacs)
@@ -2010,7 +2011,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
20102011
/* if the peer reports AUTH, assume that he
20112012
* supports AUTH.
20122013
*/
2013-
if (net->sctp.auth_enable)
2014+
if (asoc->ep->auth_enable)
20142015
asoc->peer.auth_capable = 1;
20152016
break;
20162017
case SCTP_CID_ASCONF:
@@ -2102,6 +2103,7 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
21022103
* SCTP_IERROR_NO_ERROR - continue with the chunk
21032104
*/
21042105
static sctp_ierror_t sctp_verify_param(struct net *net,
2106+
const struct sctp_endpoint *ep,
21052107
const struct sctp_association *asoc,
21062108
union sctp_params param,
21072109
sctp_cid_t cid,
@@ -2152,7 +2154,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
21522154
goto fallthrough;
21532155

21542156
case SCTP_PARAM_RANDOM:
2155-
if (!net->sctp.auth_enable)
2157+
if (!ep->auth_enable)
21562158
goto fallthrough;
21572159

21582160
/* SCTP-AUTH: Secion 6.1
@@ -2169,7 +2171,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
21692171
break;
21702172

21712173
case SCTP_PARAM_CHUNKS:
2172-
if (!net->sctp.auth_enable)
2174+
if (!ep->auth_enable)
21732175
goto fallthrough;
21742176

21752177
/* SCTP-AUTH: Section 3.2
@@ -2185,7 +2187,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
21852187
break;
21862188

21872189
case SCTP_PARAM_HMAC_ALGO:
2188-
if (!net->sctp.auth_enable)
2190+
if (!ep->auth_enable)
21892191
goto fallthrough;
21902192

21912193
hmacs = (struct sctp_hmac_algo_param *)param.p;
@@ -2220,10 +2222,9 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
22202222
}
22212223

22222224
/* 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,
22272228
struct sctp_chunk **errp)
22282229
{
22292230
union sctp_params param;
@@ -2264,8 +2265,8 @@ int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
22642265

22652266
/* Verify all the variable length parameters */
22662267
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);
22692270
switch (result) {
22702271
case SCTP_IERROR_ABORT:
22712272
case SCTP_IERROR_NOMEM:
@@ -2497,6 +2498,7 @@ static int sctp_process_param(struct sctp_association *asoc,
24972498
struct sctp_af *af;
24982499
union sctp_addr_param *addr_param;
24992500
struct sctp_transport *t;
2501+
struct sctp_endpoint *ep = asoc->ep;
25002502

25012503
/* We maintain all INIT parameters in network byte order all the
25022504
* time. This allows us to not worry about whether the parameters
@@ -2636,7 +2638,7 @@ static int sctp_process_param(struct sctp_association *asoc,
26362638
goto fall_through;
26372639

26382640
case SCTP_PARAM_RANDOM:
2639-
if (!net->sctp.auth_enable)
2641+
if (!ep->auth_enable)
26402642
goto fall_through;
26412643

26422644
/* Save peer's random parameter */
@@ -2649,7 +2651,7 @@ static int sctp_process_param(struct sctp_association *asoc,
26492651
break;
26502652

26512653
case SCTP_PARAM_HMAC_ALGO:
2652-
if (!net->sctp.auth_enable)
2654+
if (!ep->auth_enable)
26532655
goto fall_through;
26542656

26552657
/* Save peer's HMAC list */
@@ -2665,7 +2667,7 @@ static int sctp_process_param(struct sctp_association *asoc,
26652667
break;
26662668

26672669
case SCTP_PARAM_CHUNKS:
2668-
if (!net->sctp.auth_enable)
2670+
if (!ep->auth_enable)
26692671
goto fall_through;
26702672

26712673
asoc->peer.peer_chunks = kmemdup(param.p,

net/sctp/sm_statefuns.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
357357

358358
/* Verify the INIT chunk before processing it. */
359359
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,
361361
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
362362
&err_chunk)) {
363363
/* This chunk contains fatal error. It is to be discarded.
@@ -524,7 +524,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
524524

525525
/* Verify the INIT chunk before processing it. */
526526
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,
528528
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
529529
&err_chunk)) {
530530

@@ -1430,7 +1430,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
14301430

14311431
/* Verify the INIT chunk before processing it. */
14321432
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,
14341434
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
14351435
&err_chunk)) {
14361436
/* This chunk contains fatal error. It is to be discarded.

0 commit comments

Comments
 (0)