]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
sctp: fix SCTP_RESET_STREAMS stream list length limit
authorYousef Alhouseen <alhouseenyousef@gmail.com>
Thu, 25 Jun 2026 14:23:54 +0000 (16:23 +0200)
committerJakub Kicinski <kuba@kernel.org>
Sat, 27 Jun 2026 22:39:35 +0000 (15:39 -0700)
SCTP_RESET_STREAMS carries a flexible array of u16 stream IDs, but the
optlen clamps treat USHRT_MAX as a byte count and then multiply
sizeof(__u16) by the fixed header size.

That caps the copied and validated option buffer at about 64 KiB, which
rejects valid requests containing more than about half of the u16 stream
ID range.

Use struct_size_t() for the maximum struct sctp_reset_streams layout
instead, so the bound matches the flexible array described by
srs_number_streams.

Fixes: 5960cefab9df ("sctp: add a ceiling to optlen in some sockopts")
Acked-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: Yousef Alhouseen <alhouseenyousef@gmail.com>
Link: https://patch.msgid.link/20260625142354.2600-1-alhouseenyousef@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/sctp/socket.c

index c8481461f7d8b92f09ca22eded5c47fdeac0a20f..c7b9e325ec1cd359707c5cae31a9e3b55ad7386c 100644 (file)
@@ -4111,8 +4111,9 @@ static int sctp_setsockopt_reset_streams(struct sock *sk,
        if (optlen < sizeof(*params))
                return -EINVAL;
        /* srs_number_streams is u16, so optlen can't be bigger than this. */
-       optlen = min_t(unsigned int, optlen, USHRT_MAX +
-                                            sizeof(__u16) * sizeof(*params));
+       optlen = min_t(unsigned int, optlen,
+                      struct_size_t(struct sctp_reset_streams, srs_stream_list,
+                                    USHRT_MAX));
 
        if (params->srs_number_streams * sizeof(__u16) >
            optlen - sizeof(*params))
@@ -4598,8 +4599,8 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
        if (optlen > 0) {
                /* Trim it to the biggest size sctp sockopt may need if necessary */
                optlen = min_t(unsigned int, optlen,
-                              PAGE_ALIGN(USHRT_MAX +
-                                         sizeof(__u16) * sizeof(struct sctp_reset_streams)));
+                              PAGE_ALIGN(struct_size_t(struct sctp_reset_streams,
+                                                       srs_stream_list, USHRT_MAX)));
                kopt = memdup_sockptr(optval, optlen);
                if (IS_ERR(kopt))
                        return PTR_ERR(kopt);