Skip to content

Commit 5051b7c

Browse files
Vlad Yasevichkamalmostafa
Vlad Yasevich
authored andcommitted
net: sctp: cache auth_enable per endpoint
[ Upstream commit b14878c ] 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]> Signed-off-by: Kamal Mostafa <[email protected]>
1 parent 18a3a3a commit 5051b7c

File tree

7 files changed

+93
-61
lines changed

7 files changed

+93
-61
lines changed

include/net/sctp/structs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,7 @@ struct sctp_endpoint {
12691269
/* SCTP-AUTH: endpoint shared keys */
12701270
struct list_head endpoint_shared_keys;
12711271
__u16 active_key_id;
1272+
__u8 auth_enable;
12721273
};
12731274

12741275
/* Recover the outter endpoint structure. */
@@ -1297,7 +1298,8 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *,
12971298
int sctp_has_association(struct net *net, const union sctp_addr *laddr,
12981299
const union sctp_addr *paddr);
12991300

1300-
int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
1301+
int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
1302+
const struct sctp_association *asoc,
13011303
sctp_cid_t, sctp_init_chunk_t *peer_init,
13021304
struct sctp_chunk *chunk, struct sctp_chunk **err_chunk);
13031305
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
@@ -392,14 +392,13 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep,
392392
*/
393393
int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
394394
{
395-
struct net *net = sock_net(asoc->base.sk);
396395
struct sctp_auth_bytes *secret;
397396
struct sctp_shared_key *ep_key;
398397

399398
/* If we don't support AUTH, or peer is not capable
400399
* we don't need to do anything.
401400
*/
402-
if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
401+
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
403402
return 0;
404403

405404
/* If the key_id is non-zero and we couldn't find an
@@ -446,16 +445,16 @@ struct sctp_shared_key *sctp_auth_get_shkey(
446445
*/
447446
int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
448447
{
449-
struct net *net = sock_net(ep->base.sk);
450448
struct crypto_hash *tfm = NULL;
451449
__u16 id;
452450

453-
/* if the transforms are already allocted, we are done */
454-
if (!net->sctp.auth_enable) {
451+
/* If AUTH extension is disabled, we are done */
452+
if (!ep->auth_enable) {
455453
ep->auth_hmacs = NULL;
456454
return 0;
457455
}
458456

457+
/* If the transforms are already allocated, we are done */
459458
if (ep->auth_hmacs)
460459
return 0;
461460

@@ -676,12 +675,10 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param)
676675
/* Check if peer requested that this chunk is authenticated */
677676
int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
678677
{
679-
struct net *net;
680678
if (!asoc)
681679
return 0;
682680

683-
net = sock_net(asoc->base.sk);
684-
if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
681+
if (!asoc->ep->auth_enable || !asoc->peer.auth_capable)
685682
return 0;
686683

687684
return __sctp_auth_cid(chunk, asoc->peer.peer_chunks);
@@ -690,12 +687,10 @@ int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
690687
/* Check if we requested that peer authenticate this chunk. */
691688
int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
692689
{
693-
struct net *net;
694690
if (!asoc)
695691
return 0;
696692

697-
net = sock_net(asoc->base.sk);
698-
if (!net->sctp.auth_enable)
693+
if (!asoc->ep->auth_enable)
699694
return 0;
700695

701696
return __sctp_auth_cid(chunk,

net/sctp/endpointola.c

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

78-
if (net->sctp.auth_enable) {
78+
ep->auth_enable = net->sctp.auth_enable;
79+
if (ep->auth_enable) {
7980
/* Allocate space for HMACS and CHUNKS authentication
8081
* variables. There are arrays that we encode directly
8182
* 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
@@ -199,6 +199,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
199199
gfp_t gfp, int vparam_len)
200200
{
201201
struct net *net = sock_net(asoc->base.sk);
202+
struct sctp_endpoint *ep = asoc->ep;
202203
sctp_inithdr_t init;
203204
union sctp_params addrs;
204205
size_t chunksize;
@@ -258,7 +259,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
258259
chunksize += vparam_len;
259260

260261
/* Account for AUTH related parameters */
261-
if (net->sctp.auth_enable) {
262+
if (ep->auth_enable) {
262263
/* Add random parameter length*/
263264
chunksize += sizeof(asoc->c.auth_random);
264265

@@ -343,7 +344,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
343344
}
344345

345346
/* Add SCTP-AUTH chunks to the parameter list */
346-
if (net->sctp.auth_enable) {
347+
if (ep->auth_enable) {
347348
sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
348349
asoc->c.auth_random);
349350
if (auth_hmacs)
@@ -2012,7 +2013,7 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
20122013
/* if the peer reports AUTH, assume that he
20132014
* supports AUTH.
20142015
*/
2015-
if (net->sctp.auth_enable)
2016+
if (asoc->ep->auth_enable)
20162017
asoc->peer.auth_capable = 1;
20172018
break;
20182019
case SCTP_CID_ASCONF:
@@ -2104,6 +2105,7 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
21042105
* SCTP_IERROR_NO_ERROR - continue with the chunk
21052106
*/
21062107
static sctp_ierror_t sctp_verify_param(struct net *net,
2108+
const struct sctp_endpoint *ep,
21072109
const struct sctp_association *asoc,
21082110
union sctp_params param,
21092111
sctp_cid_t cid,
@@ -2154,7 +2156,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
21542156
goto fallthrough;
21552157

21562158
case SCTP_PARAM_RANDOM:
2157-
if (!net->sctp.auth_enable)
2159+
if (!ep->auth_enable)
21582160
goto fallthrough;
21592161

21602162
/* SCTP-AUTH: Secion 6.1
@@ -2171,7 +2173,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
21712173
break;
21722174

21732175
case SCTP_PARAM_CHUNKS:
2174-
if (!net->sctp.auth_enable)
2176+
if (!ep->auth_enable)
21752177
goto fallthrough;
21762178

21772179
/* SCTP-AUTH: Section 3.2
@@ -2187,7 +2189,7 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
21872189
break;
21882190

21892191
case SCTP_PARAM_HMAC_ALGO:
2190-
if (!net->sctp.auth_enable)
2192+
if (!ep->auth_enable)
21912193
goto fallthrough;
21922194

21932195
hmacs = (struct sctp_hmac_algo_param *)param.p;
@@ -2221,10 +2223,9 @@ static sctp_ierror_t sctp_verify_param(struct net *net,
22212223
}
22222224

22232225
/* Verify the INIT packet before we process it. */
2224-
int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
2225-
sctp_cid_t cid,
2226-
sctp_init_chunk_t *peer_init,
2227-
struct sctp_chunk *chunk,
2226+
int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep,
2227+
const struct sctp_association *asoc, sctp_cid_t cid,
2228+
sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk,
22282229
struct sctp_chunk **errp)
22292230
{
22302231
union sctp_params param;
@@ -2267,8 +2268,8 @@ int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
22672268

22682269
/* Verify all the variable length parameters */
22692270
sctp_walk_params(param, peer_init, init_hdr.params) {
2270-
2271-
result = sctp_verify_param(net, asoc, param, cid, chunk, errp);
2271+
result = sctp_verify_param(net, ep, asoc, param, cid,
2272+
chunk, errp);
22722273
switch (result) {
22732274
case SCTP_IERROR_ABORT:
22742275
case SCTP_IERROR_NOMEM:
@@ -2500,6 +2501,7 @@ static int sctp_process_param(struct sctp_association *asoc,
25002501
struct sctp_af *af;
25012502
union sctp_addr_param *addr_param;
25022503
struct sctp_transport *t;
2504+
struct sctp_endpoint *ep = asoc->ep;
25032505

25042506
/* We maintain all INIT parameters in network byte order all the
25052507
* time. This allows us to not worry about whether the parameters
@@ -2640,7 +2642,7 @@ static int sctp_process_param(struct sctp_association *asoc,
26402642
goto fall_through;
26412643

26422644
case SCTP_PARAM_RANDOM:
2643-
if (!net->sctp.auth_enable)
2645+
if (!ep->auth_enable)
26442646
goto fall_through;
26452647

26462648
/* Save peer's random parameter */
@@ -2653,7 +2655,7 @@ static int sctp_process_param(struct sctp_association *asoc,
26532655
break;
26542656

26552657
case SCTP_PARAM_HMAC_ALGO:
2656-
if (!net->sctp.auth_enable)
2658+
if (!ep->auth_enable)
26572659
goto fall_through;
26582660

26592661
/* Save peer's HMAC list */
@@ -2669,7 +2671,7 @@ static int sctp_process_param(struct sctp_association *asoc,
26692671
break;
26702672

26712673
case SCTP_PARAM_CHUNKS:
2672-
if (!net->sctp.auth_enable)
2674+
if (!ep->auth_enable)
26732675
goto fall_through;
26742676

26752677
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
@@ -364,7 +364,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
364364

365365
/* Verify the INIT chunk before processing it. */
366366
err_chunk = NULL;
367-
if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
367+
if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
368368
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
369369
&err_chunk)) {
370370
/* This chunk contains fatal error. It is to be discarded.
@@ -531,7 +531,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
531531

532532
/* Verify the INIT chunk before processing it. */
533533
err_chunk = NULL;
534-
if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
534+
if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
535535
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
536536
&err_chunk)) {
537537

@@ -1437,7 +1437,7 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
14371437

14381438
/* Verify the INIT chunk before processing it. */
14391439
err_chunk = NULL;
1440-
if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
1440+
if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
14411441
(sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
14421442
&err_chunk)) {
14431443
/* This chunk contains fatal error. It is to be discarded.

0 commit comments

Comments
 (0)