From nobody Tue Jun 9 19:20:10 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gZdyy71Cmz6gVXm for ; Tue, 09 Jun 2026 19:20:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (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 4gZdyy46Pdz3R0g for ; Tue, 09 Jun 2026 19:20:10 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1781032810; 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=tvsRWg3t3HEdPvcELconrVNpOoNRmpZy11R6zCti5/E=; b=w1c0BqkcDnq1D+8+bxg48oAc7r8cXxVqtGAl6EV77bwhL/JdgttI+tgUxysD4JVYQn2lKZ jbctpoVpVcLVbnDiLUFT72bXdFFFObS0NXR2gwvLMlqf924I/VyWiLhNKxAfYys4cu9iWx lD0+xXHDPqN2rzXJnqSseJovUTCxyn6GkPH/VxeFSz+SBEdxC8D0xNt/B4M+DCaeR77oqd bCMgGubbtuR2fWEciD1XUwIQay0PA2ZcycGrzwmciYIi6Ven7OxrS7C/0OPj4AifARs5Mq 03ysy9sCmU/u1+ul4dY8G1jHkaE2WI7OGZVgT3lHHfAikn5Mf64+8WCy4zhWzQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1781032810; a=rsa-sha256; cv=none; b=Fzf7NHM/5B2mkQ2nD5mGx0XjnlDwAyKbxba+kcq4xyLYch8jEhYmQN230vmAxKyLAbMJVc 8R9fuh581Gg4VGRoqyfdUEZADQYOxXn7JhBYZpnxAOlmNV84lFsydq6DG4dQPax3APQb07 KPqPd1hM5zIt+9ONbqk9nZ1NbhtAcnnyGZFarUFc1B9CaTGvC+ImV2T796qSfof8ejZiLz pjBKnqHFDpIovR2q1TMJ6CbeuP1P5vV3u08pfuIr2xVwX7kHFiZIo6bnrFZ5kmsHLAtWXE wqIXO1stg326hyp8DzU5SOnlrOwhug1FsboeS5jHLdJetSwZx3nZOdyyqmcACw== 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=1781032810; 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=tvsRWg3t3HEdPvcELconrVNpOoNRmpZy11R6zCti5/E=; b=S9Fprw5da0Dmg6QMfjzYapmph95ODSm6pv8kYptlp4d/cQu5tAWx1kVgQpLglTKl41esj6 9p7UYvFoz0idC/1h6kX7RmnLZe7o4B1tGiwuI/Us+Vq5mpDXdsJl7L5Cl8MidVw4KDsfu3 mzlzzS9zYT8a2pJUwKouGSxmMTD8URT3e3U8esW55fB+Atd7yx82EFfvdFJ/tx1rrQuJie cUekui/SyJnOtN2Qbu9FoL+lwPn//TdkW32zMn5pas52KKk+POfxKC7HAz4qxxRSNe0lYe APogPVYb5GVRwjXTMlbqigtrBZYFCHannSywpEpyqABxim1z1pA/IMaaNUaCvQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gZdyy3hzvznwQ for ; Tue, 09 Jun 2026 19:20:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3f52e by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 09 Jun 2026 19:20:10 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Mark Johnston Subject: git: 3d80e4aec3c1 - releng/15.1 - in6_mcast: Fix a race in in6p_set_source_filter() List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@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/releng/15.1 X-Git-Reftype: branch X-Git-Commit: 3d80e4aec3c1656faace076ae2b1b9d97e4c0e89 Auto-Submitted: auto-generated Date: Tue, 09 Jun 2026 19:20:10 +0000 Message-Id: <6a28676a.3f52e.607b0132@gitrepo.freebsd.org> The branch releng/15.1 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=3d80e4aec3c1656faace076ae2b1b9d97e4c0e89 commit 3d80e4aec3c1656faace076ae2b1b9d97e4c0e89 Author: Mark Johnston AuthorDate: 2026-05-29 20:12:24 +0000 Commit: Mark Johnston CommitDate: 2026-06-09 02:59:48 +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: re (cperciva) 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 08c536bc71c0..502d41bbbf39 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); }