From nobody@FreeBSD.org  Thu Sep 10 05:58:33 2009
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 844821065676
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 10 Sep 2009 05:58:33 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 59AED8FC16
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 10 Sep 2009 05:58:33 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n8A5wWoC068799
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 10 Sep 2009 05:58:32 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id n8A5wWDc068798;
	Thu, 10 Sep 2009 05:58:32 GMT
	(envelope-from nobody)
Message-Id: <200909100558.n8A5wWDc068798@www.freebsd.org>
Date: Thu, 10 Sep 2009 05:58:32 GMT
From: Stef Walter <stef@memberwebs.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Multicast: uninited memory used in filter at IP_DROP_MEMBERSHIP + IP_ADD_MEMBERSHIP
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         138690
>Category:       kern
>Synopsis:       [netinet] [patch] multicast: uninited memory used in filter at IP_DROP_MEMBERSHIP + IP_ADD_MEMBERSHIP
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-net
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Sep 10 06:00:09 UTC 2009
>Closed-Date:    Tue Sep 29 06:14:17 UTC 2009
>Last-Modified:  Tue Sep 29 06:14:17 UTC 2009
>Originator:     Stef Walter
>Release:        8.0-BETA4
>Organization:
>Environment:
FreeBSD northstar-gate.ws.local 8.0-BETA4 FreeBSD 8.0-BETA4 #8: Thu Sep 10 05:15:49 UTC 2009     op@northstar-gate.ws.local:/usr/src/sys/i386/compile/MESHNODE  i386

>Description:
If a multicast caller does an IP_DROP_MEMBERSHIP followed by a
IP_ADD_MEMBERSHIP, often an uninitialized filter is used for the
in_mfilter passed to in_joingroup_locked() in netinet/in_mcast.c.

The IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP have simple in_mreq input,
and are not using SSM or any of the new IGMPv3 features.

>How-To-Repeat:
This results in the following behavior shown by ifmcstat. Before the
drop + add you can see the following groups for the northstar1
interface. Note that 224.0.0.5 (ie: OSPF-ALL.MCAST.NET) is subscribed
with an empty exclude filter as you would expect from simple ASM mode:

> > # ifmcstat -i northstar1
> > northstar1:
> > 	inet 172.28.1.66
> > 	igmpv3 flags=0<> rv 2 qi 125 qri 10 uri 3
> > 		group 224.0.0.5 mode exclude
> > 		group 224.0.0.1 mode exclude

After the drop + add, it looks like the following. Note that now
224.0.0.5 is subscribed with an empty *include* filter which results in
no packets received.

> > # ifmcstat -i northstar1
> > northstar1:
> > 	inet 172.28.1.66
> > 	igmpv3 flags=0<> rv 2 qi 125 qri 10 uri 3
> > 		group 224.0.0.1 mode exclude
> > 		group 224.0.0.5 mode include

>Fix:
Patch is attached which fixes the problem. Bruce Simpson has signed off on this patch via the freebsd-net mailing list. 

Patch attached with submission follows:

--- sys/netinet/in_mcast.c.orig	2009-08-03 08:13:06.000000000 +0000
+++ sys/netinet/in_mcast.c	2009-09-09 15:01:24.000000000 +0000
@@ -2024,6 +2050,9 @@
 			error = ENOMEM;
 			goto out_imo_free;
 		}
+	} else if (is_new) {
+		/* Old style ASM filter mode is always exclude */
+		imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE);
 	}
 
 	/*


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-net 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Sat Sep 12 03:37:52 UTC 2009 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=138690 
State-Changed-From-To: open->patched 
State-Changed-By: bms 
State-Changed-When: Sat 12 Sep 2009 19:46:44 UTC 
State-Changed-Why:  
An appropriate fix has been committed to HEAD as SVN rev 197132. 
[There was a potential issue further up with the handling of unspecified 
source on an existing inclusive group.] 


http://www.freebsd.org/cgi/query-pr.cgi?pr=138690 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/138690: commit references a PR
Date: Sat, 12 Sep 2009 19:46:12 +0000 (UTC)

 Author: bms
 Date: Sat Sep 12 19:45:55 2009
 New Revision: 197132
 URL: http://svn.freebsd.org/changeset/base/197132
 
 Log:
   Tighten input checking in inp_join_group():
    * Don't try to use the source address, when its family is unspecified.
    * If we get a join without a source, on an existing inclusive
      mode group, this is an error, as it would change the filter mode.
   
   Fix a problem with the handling of in_mfilter for new memberships:
    * Do not rely on imf being NULL; it is explicitly initialized to a
      non-NULL pointer when constructing a membership.
    * Explicitly initialize *imf to EX mode when the source address
      is unspecified.
   
   This fixes a problem with in_mfilter slot recycling in the join path.
   
   PR:		138690
   Submitted by:	Stef Walter
   MFC after:	5 days
 
 Modified:
   head/sys/netinet/in_mcast.c
 
 Modified: head/sys/netinet/in_mcast.c
 ==============================================================================
 --- head/sys/netinet/in_mcast.c	Sat Sep 12 19:27:54 2009	(r197131)
 +++ head/sys/netinet/in_mcast.c	Sat Sep 12 19:45:55 2009	(r197132)
 @@ -1957,11 +1957,6 @@ inp_join_group(struct inpcb *inp, struct
  	if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
  		return (EADDRNOTAVAIL);
  
 -	/*
 -	 * MCAST_JOIN_SOURCE on an exclusive membership is an error.
 -	 * On an existing inclusive membership, it just adds the
 -	 * source to the filter list.
 -	 */
  	imo = inp_findmoptions(inp);
  	idx = imo_match_group(imo, ifp, &gsa->sa);
  	if (idx == -1) {
 @@ -1969,15 +1964,33 @@ inp_join_group(struct inpcb *inp, struct
  	} else {
  		inm = imo->imo_membership[idx];
  		imf = &imo->imo_mfilters[idx];
 -		if (ssa->ss.ss_family != AF_UNSPEC &&
 -		    imf->imf_st[1] != MCAST_INCLUDE) {
 -			error = EINVAL;
 -			goto out_inp_locked;
 -		}
 -		lims = imo_match_source(imo, idx, &ssa->sa);
 -		if (lims != NULL) {
 -			error = EADDRNOTAVAIL;
 -			goto out_inp_locked;
 +		if (ssa->ss.ss_family != AF_UNSPEC) {
 +			/*
 +			 * MCAST_JOIN_SOURCE on an exclusive membership
 +			 * is an error. On an existing inclusive membership,
 +			 * it just adds the source to the filter list.
 +			 */
 +			if (imf->imf_st[1] != MCAST_INCLUDE) {
 +				error = EINVAL;
 +				goto out_inp_locked;
 +			}
 +			/* Throw out duplicates. */
 +			lims = imo_match_source(imo, idx, &ssa->sa);
 +			if (lims != NULL) {
 +				error = EADDRNOTAVAIL;
 +				goto out_inp_locked;
 +			}
 +		} else {
 +			/*
 +			 * MCAST_JOIN_GROUP on an existing inclusive
 +			 * membership is an error; if you want to change
 +			 * filter mode, you must use the userland API
 +			 * setsourcefilter().
 +			 */
 +			if (imf->imf_st[1] == MCAST_INCLUDE) {
 +				error = EINVAL;
 +				goto out_inp_locked;
 +			}
  		}
  	}
  
 @@ -2010,7 +2023,8 @@ inp_join_group(struct inpcb *inp, struct
  	/*
  	 * Graft new source into filter list for this inpcb's
  	 * membership of the group. The in_multi may not have
 -	 * been allocated yet if this is a new membership.
 +	 * been allocated yet if this is a new membership, however,
 +	 * the in_mfilter slot will be allocated and must be initialized.
  	 */
  	if (ssa->ss.ss_family != AF_UNSPEC) {
  		/* Membership starts in IN mode */
 @@ -2027,6 +2041,12 @@ inp_join_group(struct inpcb *inp, struct
  			error = ENOMEM;
  			goto out_imo_free;
  		}
 +	} else {
 +		/* No address specified; Membership starts in EX mode */
 +		if (is_new) {
 +			CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__);
 +			imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE);
 +		}
  	}
  
  	/*
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/138690: commit references a PR
Date: Thu, 17 Sep 2009 13:42:09 +0000 (UTC)

 Author: bms
 Date: Thu Sep 17 13:41:59 2009
 New Revision: 197280
 URL: http://svn.freebsd.org/changeset/base/197280
 
 Log:
   MFC revs 197129,197130,197132:
    Fixes to mcast userland API.
   --
     Fix an API issue in leave processing for IPv4 multicast groups.
      * Do not assume that the group lookup performed by imo_match_group()
        is valid when ifp is NULL in this case.
      * Instead, return EADDRNOTAVAIL if the ifp cannot be resolved for the
        membership we are being asked to leave.
   
     Caveat user:
      * The way IPv4 multicast memberships are implemented in the inpcb layer
        at the moment, has the side-effect that struct ip_moptions will
        still hold the membership, under the old ifp, until ip_freemoptions()
        is called for the parent inpcb.
      * The underlying issue is: the inpcb layer does not get notification
        of ifp being detached going away in a thread-safe manner.
        This is non-trivial to fix.
   --
     Fix an obvious logic error in the IPv4 multicast leave processing,
     where the filter mode vector was not updated correctly after the leave.
   --
     Tighten input checking in inp_join_group():
      * Don't try to use the source address, when its family is unspecified.
      * If we get a join without a source, on an existing inclusive
        mode group, this is an error, as it would change the filter mode.
   
     Fix a problem with the handling of in_mfilter for new memberships:
      * Do not rely on imf being NULL; it is explicitly initialized to a
        non-NULL pointer when constructing a membership.
      * Explicitly initialize *imf to EX mode when the source address
        is unspecified.
     This fixes a problem with in_mfilter slot recycling in the join path.
   --
     Don't allow joins w/o source on an existing group.
     This is almost always pilot error.
   
     We don't need to check for group filter UNDEFINED state at t1,
     because we only ever allocate filters with their groups, so we
     unconditionally reject such calls with EINVAL.
     Trying to change the active filter mode w/o going through IP_MSFILTER
     is also disallowed.
   
     Deals with the case described in PR 137164 upfront, cumulative
     with the fix in svn rev 197132 which only calls imo_match_source()
     if the source address family was not unspecified.
   --
   
   Revision 197136 has a text conflict, however it is a comment only change.
   
   PR:		137164, 138689, 138690, 138691
   Submitted by:	Stef Walter (with fixups)
   Approved by:	re (kib)
 
 Modified:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
   stable/8/sys/dev/ciss/   (props changed)
   stable/8/sys/dev/xen/xenpci/   (props changed)
   stable/8/sys/netinet/in_mcast.c
 
 Modified: stable/8/sys/netinet/in_mcast.c
 ==============================================================================
 --- stable/8/sys/netinet/in_mcast.c	Thu Sep 17 13:33:40 2009	(r197279)
 +++ stable/8/sys/netinet/in_mcast.c	Thu Sep 17 13:41:59 2009	(r197280)
 @@ -1957,11 +1957,6 @@ inp_join_group(struct inpcb *inp, struct
  	if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0)
  		return (EADDRNOTAVAIL);
  
 -	/*
 -	 * MCAST_JOIN_SOURCE on an exclusive membership is an error.
 -	 * On an existing inclusive membership, it just adds the
 -	 * source to the filter list.
 -	 */
  	imo = inp_findmoptions(inp);
  	idx = imo_match_group(imo, ifp, &gsa->sa);
  	if (idx == -1) {
 @@ -1969,15 +1964,33 @@ inp_join_group(struct inpcb *inp, struct
  	} else {
  		inm = imo->imo_membership[idx];
  		imf = &imo->imo_mfilters[idx];
 -		if (ssa->ss.ss_family != AF_UNSPEC &&
 -		    imf->imf_st[1] != MCAST_INCLUDE) {
 -			error = EINVAL;
 -			goto out_inp_locked;
 -		}
 -		lims = imo_match_source(imo, idx, &ssa->sa);
 -		if (lims != NULL) {
 -			error = EADDRNOTAVAIL;
 -			goto out_inp_locked;
 +		if (ssa->ss.ss_family != AF_UNSPEC) {
 +			/*
 +			 * MCAST_JOIN_SOURCE on an exclusive membership
 +			 * is an error. On an existing inclusive membership,
 +			 * it just adds the source to the filter list.
 +			 */
 +			if (imf->imf_st[1] != MCAST_INCLUDE) {
 +				error = EINVAL;
 +				goto out_inp_locked;
 +			}
 +			/* Throw out duplicates. */
 +			lims = imo_match_source(imo, idx, &ssa->sa);
 +			if (lims != NULL) {
 +				error = EADDRNOTAVAIL;
 +				goto out_inp_locked;
 +			}
 +		} else {
 +			/*
 +			 * MCAST_JOIN_GROUP on an existing inclusive
 +			 * membership is an error; if you want to change
 +			 * filter mode, you must use the userland API
 +			 * setsourcefilter().
 +			 */
 +			if (imf->imf_st[1] == MCAST_INCLUDE) {
 +				error = EINVAL;
 +				goto out_inp_locked;
 +			}
  		}
  	}
  
 @@ -2010,7 +2023,8 @@ inp_join_group(struct inpcb *inp, struct
  	/*
  	 * Graft new source into filter list for this inpcb's
  	 * membership of the group. The in_multi may not have
 -	 * been allocated yet if this is a new membership.
 +	 * been allocated yet if this is a new membership, however,
 +	 * the in_mfilter slot will be allocated and must be initialized.
  	 */
  	if (ssa->ss.ss_family != AF_UNSPEC) {
  		/* Membership starts in IN mode */
 @@ -2027,6 +2041,12 @@ inp_join_group(struct inpcb *inp, struct
  			error = ENOMEM;
  			goto out_imo_free;
  		}
 +	} else {
 +		/* No address specified; Membership starts in EX mode */
 +		if (is_new) {
 +			CTR1(KTR_IGMPV3, "%s: new join w/o source", __func__);
 +			imf_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE);
 +		}
  	}
  
  	/*
 @@ -2189,6 +2209,9 @@ inp_leave_group(struct inpcb *inp, struc
  	if (!IN_MULTICAST(ntohl(gsa->sin.sin_addr.s_addr)))
  		return (EINVAL);
  
 +	if (ifp == NULL)
 +		return (EADDRNOTAVAIL);
 +
  	/*
  	 * Find the membership in the membership array.
  	 */
 @@ -2275,9 +2298,11 @@ out_imf_rollback:
  	imf_reap(imf);
  
  	if (is_final) {
 -		/* Remove the gap in the membership array. */
 -		for (++idx; idx < imo->imo_num_memberships; ++idx)
 +		/* Remove the gap in the membership and filter array. */
 +		for (++idx; idx < imo->imo_num_memberships; ++idx) {
  			imo->imo_membership[idx-1] = imo->imo_membership[idx];
 +			imo->imo_mfilters[idx-1] = imo->imo_mfilters[idx];
 +		}
  		imo->imo_num_memberships--;
  	}
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: bms 
State-Changed-When: Tue 29 Sep 2009 06:14:05 UTC 
State-Changed-Why:  
MFCed and in 8.0-RC1 


http://www.freebsd.org/cgi/query-pr.cgi?pr=138690 
>Unformatted:
