From: Wyatt Feng When ADD_OUT_STREAMS is denied, SCTP only shrinks the queued chunks and then lowers outcnt. That leaves removed stream metadata behind, so a later re-add can reuse a stale ext and hit a null-pointer dereference in the scheduler get path. Fix the rollback by tearing down the removed stream state the same way other stream resizes do. Unschedule the current scheduler state, clear out_curr if it still points at a removed stream, drop the removed stream ext state with sctp_stream_outq_migrate(), and then reschedule the remaining streams. This keeps scheduler-private RR/FC/PRIO lists consistent while fully rolling back denied outgoing stream additions. Fixes: 637784ade221 ("sctp: introduce priority based stream scheduler") Cc: stable@kernel.org Reported-by: Yuan Tan Reported-by: Yifan Wu Reported-by: Juefei Pu Reported-by: Zhengchuan Liang Reported-by: Xin Liu Assisted-by: Codex:GPT-5.4 Signed-off-by: Wyatt Feng Signed-off-by: Ren Wei --- net/sctp/stream.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/net/sctp/stream.c b/net/sctp/stream.c index c2247793c88b..5c07c6148228 100644 --- a/net/sctp/stream.c +++ b/net/sctp/stream.c @@ -1037,6 +1037,7 @@ struct sctp_chunk *sctp_process_strreset_resp( *evp = sctp_ulpevent_make_assoc_reset_event(asoc, flags, stsn, rtsn, GFP_ATOMIC); } else if (req->type == SCTP_PARAM_RESET_ADD_OUT_STREAMS) { + const struct sctp_sched_ops *sched; struct sctp_strreset_addstrm *addstrm; __u16 number; @@ -1048,7 +1049,16 @@ struct sctp_chunk *sctp_process_strreset_resp( for (i = number; i < stream->outcnt; i++) SCTP_SO(stream, i)->state = SCTP_STREAM_OPEN; } else { - sctp_stream_shrink_out(stream, number); + sched = sctp_sched_ops_from_stream(stream); + sched->unsched_all(stream); + if (stream->out_curr) + for (i = number; i < stream->outcnt; i++) + if (stream->out_curr == SCTP_SO(stream, i)) { + stream->out_curr = NULL; + break; + } + sctp_stream_outq_migrate(stream, NULL, number); + sched->sched_all(stream); stream->outcnt = number; } -- 2.43.7