In in6_update_ifa(), jump to 'cleanup' rather than returning directly
in one additional case, avoiding an ifaddr reference leak. Defer releasing the in6_ifaddr's in6_ifaddrhead reference until the end of in6_unlink_ifa(), as callers are inconsistent regarding whether or not they hold a reference across the call. This avoids using the ifaddr after it may have been freed. Reported by: tegge Reviewed by: tegge Approved by: re (blanket) MFC after: 6 weeks
This commit is contained in:
parent
395cbe82d2
commit
f291b9cd38
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=195102
@ -970,8 +970,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
"%s on %s (errno=%d)\n",
|
||||
ip6_sprintf(ip6buf, &llsol), if_name(ifp),
|
||||
error));
|
||||
in6_purgeaddr((struct ifaddr *)ia);
|
||||
return (error);
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships,
|
||||
imm, i6mm_chain);
|
||||
@ -1378,10 +1377,14 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
ifa_free(&ia->ia_ifa); /* if_addrhead */
|
||||
|
||||
/*
|
||||
* Defer the release of what might be the last reference to the
|
||||
* in6_ifaddr so that it can't be freed before the remainder of the
|
||||
* cleanup.
|
||||
*/
|
||||
IN6_IFADDR_WLOCK();
|
||||
TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link);
|
||||
IN6_IFADDR_WUNLOCK();
|
||||
ifa_free(&ia->ia_ifa); /* in6_ifaddrhead */
|
||||
|
||||
/*
|
||||
* Release the reference to the base prefix. There should be a
|
||||
@ -1404,7 +1407,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) {
|
||||
pfxlist_onlink_check();
|
||||
}
|
||||
|
||||
ifa_free(&ia->ia_ifa); /* in6_ifaddrhead */
|
||||
splx(s);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user