From a5d0034533de766dc3b908da43b172d5d3c295a6 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 29 Apr 2019 14:16:19 +0800 Subject: sctp: avoid running the sctp state machine recursively [ Upstream commit fbd019737d71e405f86549fd738f81e2ff3dd073 ] Ying triggered a call trace when doing an asconf testing: BUG: scheduling while atomic: swapper/12/0/0x10000100 Call Trace: [] dump_stack+0x19/0x1b [] __schedule_bug+0x64/0x72 [] __schedule+0x9ba/0xa00 [] __cond_resched+0x26/0x30 [] _cond_resched+0x3a/0x50 [] kmem_cache_alloc_node+0x38/0x200 [] __alloc_skb+0x5d/0x2d0 [] sctp_packet_transmit+0x610/0xa20 [sctp] [] sctp_outq_flush+0x2ce/0xc00 [sctp] [] sctp_outq_uncork+0x1c/0x20 [sctp] [] sctp_cmd_interpreter.isra.22+0xc8/0x1460 [sctp] [] sctp_do_sm+0xe1/0x350 [sctp] [] sctp_primitive_ASCONF+0x3d/0x50 [sctp] [] sctp_cmd_interpreter.isra.22+0x114/0x1460 [sctp] [] sctp_do_sm+0xe1/0x350 [sctp] [] sctp_assoc_bh_rcv+0xf4/0x1b0 [sctp] [] sctp_inq_push+0x51/0x70 [sctp] [] sctp_rcv+0xa8b/0xbd0 [sctp] As it shows, the first sctp_do_sm() running under atomic context (NET_RX softirq) invoked sctp_primitive_ASCONF() that uses GFP_KERNEL flag later, and this flag is supposed to be used in non-atomic context only. Besides, sctp_do_sm() was called recursively, which is not expected. Vlad tried to fix this recursive call in Commit c0786693404c ("sctp: Fix oops when sending queued ASCONF chunks") by introducing a new command SCTP_CMD_SEND_NEXT_ASCONF. But it didn't work as this command is still used in the first sctp_do_sm() call, and sctp_primitive_ASCONF() will be called in this command again. To avoid calling sctp_do_sm() recursively, we send the next queued ASCONF not by sctp_primitive_ASCONF(), but by sctp_sf_do_prm_asconf() in the 1st sctp_do_sm() directly. Reported-by: Ying Xu Signed-off-by: Xin Long Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/sm_sideeffect.c | 29 ----------------------------- 1 file changed, 29 deletions(-) (limited to 'net/sctp/sm_sideeffect.c') diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index e2d9a4b49c9c..fb857cf09ecd 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -1092,32 +1092,6 @@ static void sctp_cmd_send_msg(struct sctp_association *asoc, } -/* Sent the next ASCONF packet currently stored in the association. - * This happens after the ASCONF_ACK was succeffully processed. - */ -static void sctp_cmd_send_asconf(struct sctp_association *asoc) -{ - struct net *net = sock_net(asoc->base.sk); - - /* Send the next asconf chunk from the addip chunk - * queue. - */ - if (!list_empty(&asoc->addip_chunk_list)) { - struct list_head *entry = asoc->addip_chunk_list.next; - struct sctp_chunk *asconf = list_entry(entry, - struct sctp_chunk, list); - list_del_init(entry); - - /* Hold the chunk until an ASCONF_ACK is received. */ - sctp_chunk_hold(asconf); - if (sctp_primitive_ASCONF(net, asoc, asconf)) - sctp_chunk_free(asconf); - else - asoc->addip_last_asconf = asconf; - } -} - - /* These three macros allow us to pull the debugging code out of the * main flow of sctp_do_sm() to keep attention focused on the real * functionality there. @@ -1763,9 +1737,6 @@ static int sctp_cmd_interpreter(enum sctp_event event_type, } sctp_cmd_send_msg(asoc, cmd->obj.msg, gfp); break; - case SCTP_CMD_SEND_NEXT_ASCONF: - sctp_cmd_send_asconf(asoc); - break; case SCTP_CMD_PURGE_ASCONF_QUEUE: sctp_asconf_queue_teardown(asoc); break; -- cgit v1.2.3