Re: [PATCH net] sctp: fix use-after-free of cached ASCONF chunk
From: Xin Long
Date: Fri Aug 07 2026 - 15:44:57 EST
> > diff --git a/net/sctp/associola.c b/net/sctp/associola.c
> > index 5b0ae616e1ff9..737f8ea9d482f 100644
> > --- a/net/sctp/associola.c
> > +++ b/net/sctp/associola.c
> > @@ -1713,6 +1713,8 @@ void sctp_asconf_queue_teardown(struct sctp_association *asoc)
> > sctp_assoc_free_asconf_queue(asoc);
> >
> > /* Free any cached ASCONF chunk. */
> > - if (asoc->addip_last_asconf)
> > + if (asoc->addip_last_asconf) {
> > sctp_chunk_free(asoc->addip_last_asconf);
> > + asoc->addip_last_asconf = NULL;
> This is a pre-existing issue, but does setting this pointer to NULL here
> create a NULL pointer dereference in the T4 RTO timer handler?
> During a peer restart initiated by an unexpected COOKIE ECHO,
> sctp_sf_do_dupcook_a() queues a command to purge the ASCONF queue, which
> calls this function. It also queues a command to stop the T4 RTO timer
> using del_timer().
> Because del_timer() is not synchronous, if the T4 RTO timer is already
> executing on another CPU, it will block on bh_lock_sock(). Once the
> restart processing completes and the socket lock is released, the delayed
> timer resumes and can unconditionally dereference the now-NULL pointer:
> net/sctp/sm_statefuns.c:sctp_sf_t4_timer_expire() {
> struct sctp_chunk *chunk = asoc->addip_last_asconf;
> struct sctp_transport *transport = chunk->transport;
> ...
> }
> Previously this race caused a use-after-free, but with this change, it seems
> it will result in a guaranteed kernel panic. Are there any synchronization
> mechanisms preventing the timer from running and dereferencing this pointer
> after the queue is purged?
Hi, Yuxiang,
Please address the issue reported by both Sashikos in this patch by adding
a NULL check in sctp_sf_t4_timer_expire(), like:
@@ -6105,7 +6105,12 @@ enum sctp_disposition sctp_sf_t4_timer_expire(
struct sctp_cmd_seq *commands)
{
struct sctp_chunk *chunk = asoc->addip_last_asconf;
- struct sctp_transport *transport = chunk->transport;
+ struct sctp_transport *transport;
+
+ if (!chunk)
+ return SCTP_DISPOSITION_CONSUME;
+
+ transport = chunk->transport;
SCTP_INC_STATS(net, SCTP_MIB_T4_RTO_EXPIREDS);
Otherwise, this change would turn the existing issue into a NULL pointer
dereference.
Thanks.