Re: [PATCH net 2/2] ipv6: mcast: do not write past optlen in the source filter getsockopt

From: David Laight

Date: Fri Aug 07 2026 - 12:53:03 EST


On Thu, 06 Aug 2026 02:42:01 -0700
Breno Leitao <leitao@xxxxxxxxxx> wrote:

> getsockopt(MCAST_MSFILTER) on an IPv6 socket overruns the caller's buffer
> the same way the IPv4 one does. ip6_mc_msfget() fills the source list from
> the numsrc left in optval, and nothing compares that against optlen, which
> ipv6_get_msfilter() has already reused for the length of the reply.
>
> Clamp numsrc to what optlen holds, as the IPv4 side now does.

Nak, same as IPv4.

David

>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
> ---
> net/ipv6/ipv6_sockglue.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
> index b4c977434c2e0..2c3fbde7cb058 100644
> --- a/net/ipv6/ipv6_sockglue.c
> +++ b/net/ipv6/ipv6_sockglue.c
> @@ -1012,6 +1012,7 @@ static int ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
> {
> const int size0 = offsetof(struct group_filter, gf_slist_flex);
> struct group_filter gsf;
> + unsigned int max_numsrc;
> int num;
> int err;
>
> @@ -1021,6 +1022,11 @@ static int ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
> return -EFAULT;
> if (gsf.gf_group.ss_family != AF_INET6)
> return -EADDRNOTAVAIL;
> +
> + /* Number of sources that would fit in the userspace buffer */
> + max_numsrc = (len - size0) / sizeof(gsf.gf_slist_flex[0]);
> + gsf.gf_numsrc = min_t(u32, gsf.gf_numsrc, max_numsrc);
> +
> num = gsf.gf_numsrc;
> sockopt_lock_sock(sk);
> err = ip6_mc_msfget(sk, &gsf, optval, size0);
> @@ -1041,6 +1047,7 @@ static int compat_ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
> {
> const int size0 = offsetof(struct compat_group_filter, gf_slist_flex);
> struct compat_group_filter gf32;
> + unsigned int max_numsrc;
> struct group_filter gf;
> int err;
> int num;
> @@ -1050,6 +1057,10 @@ static int compat_ipv6_get_msfilter(struct sock *sk, sockptr_t optval,
>
> if (copy_from_sockptr(&gf32, optval, size0))
> return -EFAULT;
> +
> + max_numsrc = (len - size0) / sizeof(gf32.gf_slist_flex[0]);
> + gf32.gf_numsrc = min_t(u32, gf32.gf_numsrc, max_numsrc);
> +
> gf.gf_interface = gf32.gf_interface;
> gf.gf_fmode = gf32.gf_fmode;
> num = gf.gf_numsrc = gf32.gf_numsrc;
>