A384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gZdwF5qxvz3M0l for ; Tue, 09 Jun 2026 19:17:49 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1781032669; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Q9WTZ/UT3xOh+W5gityrZKUdjESZ/rKXuh+FoPQJ39Q=; b=wI5CwVvUSOrTDNSRnet1aooEYsleyPLh/QIk+EuZsFXqsIjw1tUxb4+Ie0haeqpEsX5VtK CUCNQhNR03SZmRhcwdvnVAszKqI3LBmvijEwXdgCzqSkspy4NcNsEMVt4jwzFd9Bd32v/H 1N7XK6eUmfI04nAIvqarpWKRzwnROtBKzKWAcWSYzbbQm1zQaZaWLcpu4hHJ5dHKrS7NwT d8ZjYZAZn34jIlFwdXVQkyQYSr96ji7S0KkPptLcrFRLgT1T8LCBmhL5FzJ5iZvSDNsk1q nSax0xbEEhcfx/9M+6bD9NZQKMnop9NmUUekcXijCrbBpsexbAy1SmqWz8OWiw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1781032669; a=rsa-sha256; cv=none; b=YrpXjFRi7s+nMxKEiGoOwoNkMgH9c1ILZ1s/q/q3eWYD6YvPtgwsPzumUvCaJB2XjpH9wE ro/kg37Xd2Q7LlkOcQwIrYaAL85p6zqyK8JlSAldi2JKT207IR5e5/S8m3w3PgrcUH5by4 nzIZaB76ZzZQi8/QxLuZjqMjh1HpWiHxtbo3wulcxQj8FZMbo5iFnscpuyXMpN2jreHJhp fVCDcwHaKVL1H+DwA8V0+lWDWod6kXzVXiRprPAB/92UA0MFuUP0Q3QrEog2Qn6XRPSO+M 1rdtrAc/eBkyfmFM0PmTW9qAqGZbwHhVPoKXH4k8CrHm0f4R8ZuQYtFyG7lYNA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1781032669; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Q9WTZ/UT3xOh+W5gityrZKUdjESZ/rKXuh+FoPQJ39Q=; b=N9hLNKqLQ4KItR2LhNtDxNbDRoc6GM+qGtguxx7ZUqg39xAIAm2qWcO1SlWTSbdt6Nx1bQ EUMprhBaIeyPrkCSa8YPoT0m20W3ib4xeSFxS9L64E6DDfkH6Bs/a7egb+iCnwIvKuhphn /f+T5JzFui7/e//a/5eazCZgVowuneJFta6BdxRnl654RC/vJWna1GxxRkDa0ClCqCPtwU pqkWZE9BuTtCh/HNdeGPnEOQbufKo38PA7mI9zm+xS6Zy+pPCFpHhPtOQKqsI8Ggn4Fo7W 23so5rew5vVn6KQ6PUUNjI9FQ/UHlbW0/KhaoIwaRblQh8VeNuoYT2G5BWObew== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gZdwF5MKVznrJ for ; Tue, 09 Jun 2026 19:17:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3ebbb by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 09 Jun 2026 19:17:49 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: 522182827ea1 - stable/14 - in6_mcast: Fix a race in in6p_set_source_filter() List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/stable/14 X-Git-Reftype: branch X-Git-Commit: 522182827ea173e07668b1ac40a8173c620bb99e Auto-Submitted: auto-generated Date: Tue, 09 Jun 2026 19:17:49 +0000 Message-Id: <6a2866dd.3ebbb.42687757@gitrepo.freebsd.org> The branch stable/14 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=522182827ea173e07668b1ac40a8173c620bb99e commit 522182827ea173e07668b1ac40a8173c620bb99e Author: Mark Johnston AuthorDate: 2026-05-29 20:12:24 +0000 Commit: Mark Johnston CommitDate: 2026-06-09 19:15:21 +0000 in6_mcast: Fix a race in in6p_set_source_filter() We drop the inpcb lock in order to copy in the source list, but this leaves a window where the multicast filter structure might be freed. This can be exploited to obtain root privileges. In the v4 code this race is mitigated by holding the global multicast lock across the gap. Restructure the code to copy in filters before doing anything else, so that there's no need to drop the inpcb lock and reason about the correctness of doing so. Do the same in the v4 code for consistency. Approved by: so Security: FreeBSD-SA-26:29.ip6_multicast Security: CVE-2026-49412 Reported by: Andrew Griffiths Reported by: Maik Münch Reviewed by: glebius Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D57347 --- sys/netinet/in_mcast.c | 40 +++++++++++++++++----------------------- sys/netinet6/in6_mcast.c | 41 +++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 45 deletions(-) diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index b0be48b65437..4fd00bac3ae4 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -2524,6 +2524,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) { struct epoch_tracker et; struct __msfilterreq msfr; + struct sockaddr_storage *kss; sockunion_t *gsa; struct ifnet *ifp; struct in_mfilter *imf; @@ -2536,9 +2537,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) return (error); - if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) - return (ENOBUFS); - if ((msfr.msfr_fmode != MCAST_EXCLUDE && msfr.msfr_fmode != MCAST_INCLUDE)) return (EINVAL); @@ -2551,13 +2549,24 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr))) return (EINVAL); + if (msfr.msfr_nsrcs > in_mcast_maxsocksrc) + return (ENOBUFS); + kss = mallocarray(msfr.msfr_nsrcs, sizeof(struct sockaddr_storage), + M_TEMP, M_WAITOK); + error = copyin(msfr.msfr_srcs, kss, + sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); + if (error) + goto out_inp_unlocked; + gsa->sin.sin_port = 0; /* ignore port */ NET_EPOCH_ENTER(et); ifp = ifnet_byindex(msfr.msfr_ifindex); NET_EPOCH_EXIT(et); /* XXXGL: unsafe ifp */ - if (ifp == NULL) - return (EADDRNOTAVAIL); + if (ifp == NULL) { + error = EADDRNOTAVAIL; + goto out_inp_unlocked; + } IN_MULTI_LOCK(); @@ -2589,25 +2598,9 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (msfr.msfr_nsrcs > 0) { struct in_msource *lims; struct sockaddr_in *psin; - struct sockaddr_storage *kss, *pkss; + struct sockaddr_storage *pkss; int i; - INP_WUNLOCK(inp); - - CTR2(KTR_IGMPV3, "%s: loading %lu source list entries", - __func__, (unsigned long)msfr.msfr_nsrcs); - kss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs, - M_TEMP, M_WAITOK); - error = copyin(msfr.msfr_srcs, kss, - sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); - if (error) { - IN_MULTI_UNLOCK(); - free(kss, M_TEMP); - return (error); - } - - INP_WLOCK(inp); - /* * Mark all source filters as UNDEFINED at t1. * Restore new group filter mode, as imf_leave() @@ -2642,7 +2635,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) break; lims->imsl_st[1] = imf->imf_st[1]; } - free(kss, M_TEMP); } if (error) @@ -2679,6 +2671,8 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); IN_MULTI_UNLOCK(); +out_inp_unlocked: + free(kss, M_TEMP); return (error); } diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index a6186568ecb2..4ec9f36cd9ac 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -2489,6 +2489,7 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) { struct __msfilterreq msfr; struct epoch_tracker et; + struct sockaddr_storage *kss; sockunion_t *gsa; struct ifnet *ifp; struct in6_mfilter *imf; @@ -2501,9 +2502,6 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) return (error); - if (msfr.msfr_nsrcs > in6_mcast_maxsocksrc) - return (ENOBUFS); - if (msfr.msfr_fmode != MCAST_EXCLUDE && msfr.msfr_fmode != MCAST_INCLUDE) return (EINVAL); @@ -2516,19 +2514,31 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (!IN6_IS_ADDR_MULTICAST(&gsa->sin6.sin6_addr)) return (EINVAL); + if (msfr.msfr_nsrcs > in6_mcast_maxsocksrc) + return (ENOBUFS); + kss = mallocarray(msfr.msfr_nsrcs, sizeof(struct sockaddr_storage), + M_TEMP, M_WAITOK); + error = copyin(msfr.msfr_srcs, kss, + sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); + if (error) + goto out_in6p_unlocked; + gsa->sin6.sin6_port = 0; /* ignore port */ NET_EPOCH_ENTER(et); ifp = ifnet_byindex(msfr.msfr_ifindex); NET_EPOCH_EXIT(et); - if (ifp == NULL) - return (EADDRNOTAVAIL); + if (ifp == NULL) { + error = EADDRNOTAVAIL; + goto out_in6p_unlocked; + } (void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); /* * Take the INP write lock. * Check if this socket is a member of this group. */ + IN6_MULTI_LOCK(); imo = in6p_findmoptions(inp); imf = im6o_match_group(imo, ifp, &gsa->sa); if (imf == NULL) { @@ -2553,24 +2563,9 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (msfr.msfr_nsrcs > 0) { struct in6_msource *lims; struct sockaddr_in6 *psin; - struct sockaddr_storage *kss, *pkss; + struct sockaddr_storage *pkss; int i; - INP_WUNLOCK(inp); - - CTR2(KTR_MLD, "%s: loading %lu source list entries", - __func__, (unsigned long)msfr.msfr_nsrcs); - kss = malloc(sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs, - M_TEMP, M_WAITOK); - error = copyin(msfr.msfr_srcs, kss, - sizeof(struct sockaddr_storage) * msfr.msfr_nsrcs); - if (error) { - free(kss, M_TEMP); - return (error); - } - - INP_WLOCK(inp); - /* * Mark all source filters as UNDEFINED at t1. * Restore new group filter mode, as im6f_leave() @@ -2615,7 +2610,6 @@ in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) break; lims->im6sl_st[1] = imf->im6f_st[1]; } - free(kss, M_TEMP); } if (error) @@ -2650,6 +2644,9 @@ out_im6f_rollback: out_in6p_locked: INP_WUNLOCK(inp); + IN6_MULTI_UNLOCK(); +out_in6p_unlocked: + free(kss, M_TEMP); return (error); }