Re: [PATCH net 1/1] net: sctp: fix AUTH HMAC list overflow into auth_chunks
From: Xin Long <lucien.xin@gmail.com>
Date: 2026-07-03 20:20:27
Also in:
linux-sctp
Subsystem:
networking [general], sctp protocol, the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Marcelo Ricardo Leitner, Xin Long, Linus Torvalds
On Fri, Jul 3, 2026 at 3:19 AM Ren Wei [off-list ref] wrote:
quoted hunk ↗ jump to hunk
From: Zihan Xi <redacted> sctp_auth_ep_set_hmacs() may advertise a 12-byte HMAC-ALGO parameter when four identifiers are configured, but the association only stores ten bytes in c.auth_hmacs. sctp_association_init() copies the advertised length and overwrites the adjacent auth_chunks field, so sctp_auth_asoc_verify_hmac_id() accepts forged HMAC identifiers and sctp_auth_get_hmac() indexes past sctp_hmac_list. Clamp the stored parameter length to the association buffer, copy only that many bytes when initializing an association, and reject out-of-range HMAC identifiers in sctp_auth_get_hmac(). Fixes: 65b07e5d0d09 ("[SCTP]: API updates to suport SCTP-AUTH extensions.") Cc: stable@vger.kernel.org Reported-by: Yuan Tan <redacted> Reported-by: Xin Liu <redacted> Assisted-by: Codex:gpt-5.4 Signed-off-by: Zihan Xi <redacted> Reviewed-by: Ren Wei <redacted> --- net/sctp/associola.c | 10 +++++++--- net/sctp/auth.c | 10 ++++++++-- net/sctp/sm_statefuns.c | 2 ++ 3 files changed, 17 insertions(+), 5 deletions(-)diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 62d3cc1558..760457def6 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c@@ -260,9 +260,13 @@ static struct sctp_association *sctp_association_init( asoc->strreset_enable = ep->strreset_enable; /* Save the hmacs and chunks list into this association */ - if (ep->auth_hmacs_list) - memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, - ntohs(ep->auth_hmacs_list->param_hdr.length)); + if (ep->auth_hmacs_list) { + size_t hmac_len = min_t(size_t, + ntohs(ep->auth_hmacs_list->param_hdr.length), + sizeof(asoc->c.auth_hmacs)); + + memcpy(asoc->c.auth_hmacs, ep->auth_hmacs_list, hmac_len); + } if (ep->auth_chunk_list) memcpy(asoc->c.auth_chunks, ep->auth_chunk_list, ntohs(ep->auth_chunk_list->param_hdr.length));diff --git a/net/sctp/auth.c b/net/sctp/auth.c index be9782760f..4d14bd6185 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c@@ -447,6 +447,8 @@ struct sctp_shared_key *sctp_auth_get_shkey( const struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id) { + if (hmac_id >= SCTP_AUTH_NUM_HMACS) + return NULL; return &sctp_hmac_list[hmac_id]; }@@ -510,6 +512,9 @@ int sctp_auth_asoc_verify_hmac_id(const struct sctp_association *asoc, hmacs = (struct sctp_hmac_algo_param *)asoc->c.auth_hmacs; n_elt = (ntohs(hmacs->param_hdr.length) - sizeof(struct sctp_paramhdr)) >> 1; + n_elt = min_t(__u16, n_elt, + (sizeof(asoc->c.auth_hmacs) - + sizeof(struct sctp_paramhdr)) / sizeof(__u16)); return __sctp_auth_find_hmacid(hmacs->hmac_ids, n_elt, hmac_id); }@@ -708,8 +713,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, ep->auth_hmacs_list->hmac_ids[i] = htons(hmacs->shmac_idents[i]); ep->auth_hmacs_list->param_hdr.length = - htons(sizeof(struct sctp_paramhdr) + - hmacs->shmac_num_idents * sizeof(__u16)); + htons(min_t(__u16, sizeof(struct sctp_paramhdr) + + hmacs->shmac_num_idents * sizeof(__u16), + SCTP_AUTH_NUM_HMACS * sizeof(__u16) + 2)); return 0; }diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index d23d935e12..21cda509a0 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c@@ -4431,6 +4431,8 @@ static enum sctp_ierror sctp_sf_authenticate( sig_len = ntohs(chunk->chunk_hdr->length) - sizeof(struct sctp_auth_chunk); hmac = sctp_auth_get_hmac(ntohs(auth_hdr->hmac_id)); + if (!hmac) + return SCTP_IERROR_AUTH_BAD_HMAC; if (sig_len != hmac->hmac_len) return SCTP_IERROR_PROTO_VIOLATION; --2.43.0
I think real issue is the member: __u8 auth_hmacs[SCTP_AUTH_NUM_HMACS * sizeof(__u16) + 2] in struct sctp_cookie. It's supposed to include a 'struct struct sctp_paramhdr' + N * hmac_id. However, sizeof(struct struct sctp_paramhdr) is 4 not 2, which causes the overflow when copying it from ep to asoc. The right fix should be:
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index affee44bd38e..cccc662561aa 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h@@ -312,7 +312,8 @@ struct sctp_cookie { __u8 auth_random[sizeof(struct sctp_paramhdr) + SCTP_AUTH_RANDOM_LENGTH]; - __u8 auth_hmacs[SCTP_AUTH_NUM_HMACS * sizeof(__u16) + 2]; + __u8 auth_hmacs[sizeof(struct sctp_paramhdr) + + SCTP_AUTH_NUM_HMACS * sizeof(__u16)]; __u8 auth_chunks[sizeof(struct sctp_paramhdr) + SCTP_AUTH_MAX_CHUNKS]; /* This is a shim for my peer's INIT packet, followed by
Please give it a try in your test env, Thanks.