svn commit: r339554 - head/sys/net

Kristof Provost kp at FreeBSD.org
Tue Oct 23 04:17:47 UTC 2018


On 22 Oct 2018, at 17:51, Kristof Provost wrote:
> On 21 Oct 2018, at 11:24, Andrey V. Elsukov wrote:
>> Author: ae
>> Date: Sun Oct 21 18:24:20 2018
>> New Revision: 339554
>> URL: https://svnweb.freebsd.org/changeset/base/339554
>>
>> Log:
>>   Rework if_ipsec(4) to use epoch(9) instead of rmlock.
>>
>>   * use CK_LIST and FNV hash to keep chains of softc;
>>   * read access to softc is protected by epoch();
>>   * write access is protected by ipsec_ioctl_sx. Changing of softc 
>> fields
>>     is allowed only when softc is unlinked from CK_LIST chains.
>>   * linking/unlinking of softc is allowed only when ipsec_ioctl_sx is
>>     exclusive locked.
>>   * the plain LIST of all softc is replaced by hash table that uses 
>> ingress
>>     address of tunnels as a key.
>>   * added support for appearing/disappearing of ingress address 
>> handling.
>>     Now it is allowed configure non-local ingress IP address, and 
>> thus the
>>     problem with if_ipsec(4) configuration that happens on boot, when
>>     ingress address is not yet configured, is solved.
>>
>>   MFC after:	1 month
>>   Sponsored by:	Yandex LLC
>>   Differential Revision:	https://reviews.freebsd.org/D17190
>>
> This panics during the pf tests.
I think I understand what’s happening here.

With this patch I see a different panic:

	diff --git a/sys/net/if_ipsec.c b/sys/net/if_ipsec.c
	index 91b11a455b3..146cb59aaaa 100644
	--- a/sys/net/if_ipsec.c
	+++ b/sys/net/if_ipsec.c
	@@ -134,6 +134,9 @@ ipsec_srchash(const struct sockaddr *sa)
	 {
	        uint32_t hval;

	+       KASSERT(V_ipsec4_srchtbl, ("NULL"));
	+       KASSERT(V_ipsec6_srchtbl, ("NULL (v6)"));
	+
	        switch (sa->sa_family) {
	 #ifdef INET
	        case AF_INET:
	@@ -265,17 +274,22 @@ static void
	 vnet_ipsec_uninit(const void *unused __unused)
	 {

	        if_clone_detach(V_ipsec_cloner);
	        free(V_ipsec_idhtbl, M_IPSEC);
	 #ifdef INET
	        if (IS_DEFAULT_VNET(curvnet))
	                ip_encap_unregister_srcaddr(ipsec4_srctab);
	        free(V_ipsec4_srchtbl, M_IPSEC);
	+       V_ipsec4_srchtbl = NULL;
	+
	 #endif
	 #ifdef INET6
	        if (IS_DEFAULT_VNET(curvnet))
	                ip6_encap_unregister_srcaddr(ipsec6_srctab);
	        free(V_ipsec6_srchtbl, M_IPSEC);
	+       V_ipsec4_srchtbl = NULL;
	 #endif
	 }
	 VNET_SYSUNINIT(vnet_ipsec_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, 
SI_ORDER_ANY,

That trips the KASSERT() in ipsec_srchash(). Basically, the problem is 
that the V_ipsec4_srchtbl table gets freed in vnet_ipsec_uninit(), and 
later we get a srcaddr_change_event(), which tries to iterate the list 
(in ipsec_srcaddr()). Obviously iterating a freed list doesn’t go well 
for us (hence the 0xdeadc0dedeadc0de softc).

That also explains why this happens during the pf tests, even though 
they don’t actually use IPSec.

I’m not quite sure how to best fix this though. I suppose we could set 
V_ipsec4_srchtbl to NULL (well, copy the pointer first, set it to NULL 
and then free it so we don’t add a race condition) and then check for 
NULL in  ipsec_srcaddr().
It feels like the srcaddr_change_event needs to be per-vnet, so we can 
unregister before we free V_ipsec4_srchtbl.

Best regards,
Kristof


More information about the svn-src-head mailing list