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
This commit is contained in:
Hans Petter Selasky 2019-01-24 08:25:02 +00:00
parent 7a02897647
commit dea72f062a
3 changed files with 16 additions and 0 deletions

View File

@ -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

View File

@ -584,6 +584,14 @@ in6m_release_list_deferred(struct in6_multi_head *inmh)
GROUPTASK_ENQUEUE(&free_gtask);
}
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)
{

View File

@ -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 *);