Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Jan 2019 08:25:03 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r343394 - head/sys/netinet6
Message-ID:  <201901240825.x0O8P3fd070682@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Thu Jan 24 08:25:02 2019
New Revision: 343394
URL: https://svnweb.freebsd.org/changeset/base/343394

Log:
  When detaching a network interface drain the workqueue freeing the inm's
  because the destructor will access the if_ioctl() callback in the ifnet
  pointer which is about to be freed. This prevents use-after-free.
  
  PR:			233535
  Differential Revision:	https://reviews.freebsd.org/D18887
  Reviewed by:		bz (net)
  Tested by:		ae
  MFC after:		1 week
  Sponsored by:		Mellanox Technologies

Modified:
  head/sys/netinet6/in6_ifattach.c
  head/sys/netinet6/in6_mcast.c
  head/sys/netinet6/in6_var.h

Modified: head/sys/netinet6/in6_ifattach.c
==============================================================================
--- head/sys/netinet6/in6_ifattach.c	Thu Jan 24 08:18:02 2019	(r343393)
+++ head/sys/netinet6/in6_ifattach.c	Thu Jan 24 08:25:02 2019	(r343394)
@@ -884,6 +884,13 @@ in6_purgemaddrs(struct ifnet *ifp)
 	IN6_MULTI_LIST_UNLOCK();
 	IN6_MULTI_UNLOCK();
 	in6m_release_list_deferred(&purgeinms);
+
+	/*
+	 * Make sure all multicast deletions invoking if_ioctl() are
+	 * completed before returning. Else we risk accessing a freed
+	 * ifnet structure pointer.
+	 */
+	in6m_release_wait();
 }
 
 void

Modified: head/sys/netinet6/in6_mcast.c
==============================================================================
--- head/sys/netinet6/in6_mcast.c	Thu Jan 24 08:18:02 2019	(r343393)
+++ head/sys/netinet6/in6_mcast.c	Thu Jan 24 08:25:02 2019	(r343394)
@@ -585,6 +585,14 @@ in6m_release_list_deferred(struct in6_multi_head *inmh
 }
 
 void
+in6m_release_wait(void)
+{
+
+	/* Wait for all jobs to complete. */
+	gtaskqueue_drain_all(free_gtask.gt_taskqueue);
+}
+
+void
 in6m_disconnect(struct in6_multi *inm)
 {
 	struct ifnet *ifp;

Modified: head/sys/netinet6/in6_var.h
==============================================================================
--- head/sys/netinet6/in6_var.h	Thu Jan 24 08:18:02 2019	(r343393)
+++ head/sys/netinet6/in6_var.h	Thu Jan 24 08:25:02 2019	(r343394)
@@ -811,6 +811,7 @@ void	in6m_print(const struct in6_multi *);
 int	in6m_record_source(struct in6_multi *, const struct in6_addr *);
 void	in6m_release_deferred(struct in6_multi *);
 void	in6m_release_list_deferred(struct in6_multi_head *);
+void	in6m_release_wait(void);
 void	ip6_freemoptions(struct ip6_moptions *);
 int	ip6_getmoptions(struct inpcb *, struct sockopt *);
 int	ip6_setmoptions(struct inpcb *, struct sockopt *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201901240825.x0O8P3fd070682>