[PATCH OLK-5.10] sctp: validate cookie AUTH state before use
From: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> mainline inclusion from mainline-v7.2 commit 3dbb44d88b1e94dd31fe43588af7437b34b44d56 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18398 CVE: CVE-2026-74752 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- When cookie authentication is disabled, COOKIE_ECHO restores fixed-size AUTH fields directly from peer-controlled cookie bytes. A forged RANDOM length, HMAC list, or CHUNKS list can then reach association consumers with lengths or identifiers that were never validated against the local backing arrays. A forged RANDOM length can cause out-of-bounds reads during key-vector construction. A forged HMAC identifier also caused a 32-byte write past a zero-length AUTH chunk, providing a primitive for a local privilege escalation chain. Validate the cookie's RANDOM, HMACS, and CHUNKS parameters at the cookie trust boundary before copying them into the association. Reject invalid types, malformed lengths, unsupported HMAC identifiers, HMAC lists without SHA1, and forbidden chunk ids. Fixes: bbd0d59809f9 ("[SCTP]: Implement the receive and verification of AUTH chunk") Fixes: 1f485649f529 ("[SCTP]: Implement SCTP-AUTH internals") Signed-off-by: Jérémy Jean <Jeremy.Jean@oss.cyber.gouv.fr> Acked-by: Xin Long <lucien.xin@gmail.com> Link: https://patch.msgid.link/20260804200042.2412009-1-Jeremy.Jean@oss.cyber.gouv... Signed-off-by: Jakub Kicinski <kuba@kernel.org> Conflicts: include/net/sctp/auth.h net/sctp/auth.c [Backport of upstream 3dbb44d88b1e adding sctp_auth_verify_cookie_params() to validate the cookie's RANDOM/HMACS/CHUNKS parameters before they are restored into an association. Two helpers used by the new function are provided by later mainline refactors absent on this tree and are replaced with in-tree equivalents: - sctp_sk(ep->base.sk)->cookie_auth_enable (from 2f3dd6ec901f2, which replaces sp->hmac with a bool) becomes sctp_sk(ep->base.sk)->hmac, whose non-NULL value keeps the same "cookie HMAC auth enabled" meaning already used by sctp_pack_cookie()/sctp_unpack_cookie(); - sctp_hmac_supported(hmac_id) (from bf40785fa437c) becomes the equivalent "hmac_id >= SCTP_AUTH_NUM_HMACS || !sctp_hmac_list[hmac_id].hmac_name" check matching auth.c style. In auth.h the new declaration and the struct sctp_cookie forward declaration are added while the downstream crypto_shash, init_hmacs, destroy_hmacs declarations and the non-const sctp_auth_get_hmac()/ sctp_auth_asoc_get_hmac() signatures (predating the const qualifiers of the upstream refactors) are preserved. The full validation logic is retained and is semantically equivalent to upstream.] Signed-off-by: Hulk Robot <hulkrobot@huawei.com> Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com> Signed-off-by: Jinjiang Tu <tujinjiang@huawei.com> --- include/net/sctp/auth.h | 3 ++ net/sctp/auth.c | 76 ++++++++++++++++++++++++++++++++++++++++ net/sctp/sm_make_chunk.c | 3 ++ 3 files changed, 82 insertions(+) diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h index d4b3b2dcd15b..c2399fb17889 100644 --- a/include/net/sctp/auth.h +++ b/include/net/sctp/auth.h @@ -23,6 +23,7 @@ struct sctp_association; struct sctp_authkey; struct sctp_hmacalgo; struct crypto_shash; +struct sctp_cookie; /* * Define a generic struct that will hold all the info @@ -77,6 +78,8 @@ struct sctp_shared_key *sctp_auth_get_shkey( int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, struct sctp_association *asoc, gfp_t gfp); +bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep, + const struct sctp_cookie *cookie); int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp); void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]); struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id); diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 34964145514e..e317a2df046d 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -376,6 +376,82 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, return -ENOMEM; } +static bool sctp_auth_chunk_id_forbidden(__u8 chunk_id) +{ + switch (chunk_id) { + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + case SCTP_CID_SHUTDOWN_COMPLETE: + case SCTP_CID_AUTH: + return true; + default: + return false; + } +} + +/* Verify AUTH parameters copied from a state cookie before they are restored + * into an association. When cookie authentication is disabled these fields + * are peer-controlled, so they must satisfy the same constraints as locally + * generated AUTH parameters. + */ +bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep, + const struct sctp_cookie *cookie) +{ + const struct sctp_paramhdr *random; + const struct sctp_hmac_algo_param *hmacs; + const struct sctp_chunks_param *chunks; + u16 hmacs_len, chunks_len; + u16 n_hmacs, n_chunks, i; + bool has_sha1 = false; + + if (sctp_sk(ep->base.sk)->hmac || !ep->auth_enable) + return true; + + random = (const struct sctp_paramhdr *)cookie->auth_random; + if (random->type != SCTP_PARAM_RANDOM || + ntohs(random->length) != sizeof(*random) + SCTP_AUTH_RANDOM_LENGTH) + return false; + + hmacs = (const struct sctp_hmac_algo_param *)cookie->auth_hmacs; + hmacs_len = ntohs(hmacs->param_hdr.length); + if (hmacs->param_hdr.type != SCTP_PARAM_HMAC_ALGO || + hmacs_len < sizeof(struct sctp_paramhdr) + + sizeof(hmacs->hmac_ids[0]) || + hmacs_len > sizeof(cookie->auth_hmacs) || + (hmacs_len - sizeof(struct sctp_paramhdr)) % + sizeof(hmacs->hmac_ids[0])) + return false; + + n_hmacs = (hmacs_len - sizeof(struct sctp_paramhdr)) / + sizeof(hmacs->hmac_ids[0]); + for (i = 0; i < n_hmacs; i++) { + u16 hmac_id = ntohs(hmacs->hmac_ids[i]); + + if (hmac_id >= SCTP_AUTH_NUM_HMACS || + !sctp_hmac_list[hmac_id].hmac_name) + return false; + if (hmac_id == SCTP_AUTH_HMAC_ID_SHA1) + has_sha1 = true; + } + if (!has_sha1) + return false; + + chunks = (const struct sctp_chunks_param *)cookie->auth_chunks; + chunks_len = ntohs(chunks->param_hdr.length); + if (chunks->param_hdr.type != SCTP_PARAM_CHUNKS || + chunks_len < sizeof(struct sctp_paramhdr) || + chunks_len > sizeof(cookie->auth_chunks)) + return false; + + n_chunks = chunks_len - sizeof(struct sctp_paramhdr); + for (i = 0; i < n_chunks; i++) { + if (sctp_auth_chunk_id_forbidden(chunks->chunks[i])) + return false; + } + + return true; +} + /* Public interface to create the association shared key. * See code above for the algorithm. diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 9ee24c361416..07b2a0c97f4a 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1828,6 +1828,9 @@ struct sctp_association *sctp_unpack_cookie( /* Set up our peer's port number. */ retval->peer.port = ntohs(chunk->sctp_hdr->source); + if (!sctp_auth_verify_cookie_params(ep, bear_cookie)) + goto malformed; + /* Populate the association from the cookie. */ memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie)); -- 2.43.0
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/27288 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/3A7... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/27288 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/3A7...
participants (2)
-
Jinjiang Tu -
patchwork bot