net/ipv6: delete temporary address if mngtmpaddr is removed or unmanaged
[ Upstream commit00b5b7aab9] RFC8981 section 3.4 says that existing temporary addresses must have their lifetimes adjusted so that no temporary addresses should ever remain "valid" or "preferred" longer than the incoming SLAAC Prefix Information. This would strongly imply in Linux's case that if the "mngtmpaddr" address is deleted or un-flagged as such, its corresponding temporary addresses must be cleared out right away. But now the temporary address is renewed even after ‘mngtmpaddr’ is removed or becomes unmanaged as manage_tempaddrs() set temporary addresses prefered/valid time to 0, and later in addrconf_verify_rtnl() all checkings failed to remove the addresses. Fix this by deleting the temporary address directly for these situations. Fixes:778964f2fd("ipv6/addrconf: fix timing bug in tempaddr regen") Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ac774812a9
commit
cb74207ef9
+29
-12
@@ -2570,6 +2570,24 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
|
||||
return idev;
|
||||
}
|
||||
|
||||
static void delete_tempaddrs(struct inet6_dev *idev,
|
||||
struct inet6_ifaddr *ifp)
|
||||
{
|
||||
struct inet6_ifaddr *ift, *tmp;
|
||||
|
||||
write_lock_bh(&idev->lock);
|
||||
list_for_each_entry_safe(ift, tmp, &idev->tempaddr_list, tmp_list) {
|
||||
if (ift->ifpub != ifp)
|
||||
continue;
|
||||
|
||||
in6_ifa_hold(ift);
|
||||
write_unlock_bh(&idev->lock);
|
||||
ipv6_del_addr(ift);
|
||||
write_lock_bh(&idev->lock);
|
||||
}
|
||||
write_unlock_bh(&idev->lock);
|
||||
}
|
||||
|
||||
static void manage_tempaddrs(struct inet6_dev *idev,
|
||||
struct inet6_ifaddr *ifp,
|
||||
__u32 valid_lft, __u32 prefered_lft,
|
||||
@@ -3124,11 +3142,12 @@ static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags,
|
||||
in6_ifa_hold(ifp);
|
||||
read_unlock_bh(&idev->lock);
|
||||
|
||||
if (!(ifp->flags & IFA_F_TEMPORARY) &&
|
||||
(ifa_flags & IFA_F_MANAGETEMPADDR))
|
||||
manage_tempaddrs(idev, ifp, 0, 0, false,
|
||||
jiffies);
|
||||
ipv6_del_addr(ifp);
|
||||
|
||||
if (!(ifp->flags & IFA_F_TEMPORARY) &&
|
||||
(ifp->flags & IFA_F_MANAGETEMPADDR))
|
||||
delete_tempaddrs(idev, ifp);
|
||||
|
||||
addrconf_verify_rtnl(net);
|
||||
if (ipv6_addr_is_multicast(pfx)) {
|
||||
ipv6_mc_config(net->ipv6.mc_autojoin_sk,
|
||||
@@ -4952,14 +4971,12 @@ static int inet6_addr_modify(struct net *net, struct inet6_ifaddr *ifp,
|
||||
}
|
||||
|
||||
if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) {
|
||||
if (was_managetempaddr &&
|
||||
!(ifp->flags & IFA_F_MANAGETEMPADDR)) {
|
||||
cfg->valid_lft = 0;
|
||||
cfg->preferred_lft = 0;
|
||||
}
|
||||
manage_tempaddrs(ifp->idev, ifp, cfg->valid_lft,
|
||||
cfg->preferred_lft, !was_managetempaddr,
|
||||
jiffies);
|
||||
if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR))
|
||||
delete_tempaddrs(ifp->idev, ifp);
|
||||
else
|
||||
manage_tempaddrs(ifp->idev, ifp, cfg->valid_lft,
|
||||
cfg->preferred_lft, !was_managetempaddr,
|
||||
jiffies);
|
||||
}
|
||||
|
||||
addrconf_verify_rtnl(net);
|
||||
|
||||
Reference in New Issue
Block a user