mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
ipv6: initialize temporary ifaddr before publication
ipv6_create_tempaddr() holds a reference to the public ifaddr, publishes
the new temporary address through ipv6_add_addr(), and only then stores
the reference and final timestamps.
addrconf_ifdown() can remove the temporary address before ifpub is
stored, leaking the public ifaddr reference. Publishing ifpub alone is
insufficient: manage_tempaddrs() can then find the object before cstamp
and tstamp are final, update its lifetimes, and have the constructor
overwrite its timestamp with an older value.
This follow-on was found by source review and was not separately
triggered at runtime.
Pass the public ifaddr and both timestamps in ifa6_config. Initialize all
three fields before adding the temporary address to either the hash or
per-device lists. On success the existing public-ifaddr reference
transfers to the temporary object. On error it remains owned and released
by ipv6_create_tempaddr().
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <netdev-bot+sashiko@kernel.org>
Closes: https://lore.kernel.org/r/179122559913.434549.12720841717630168470@kernel.org
Link: https://lore.kernel.org/r/179161099665.434549.5858601179492551889@kernel.org
Link: https://lore.kernel.org/r/20261007164548.GA1153540@shredder
Link: https://lore.kernel.org/r/20261012145240.GA779501@shredder
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Daehyeon Ko <4ncienth@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Link: https://patch.msgid.link/20261015050651.1841557-4-4ncienth@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
06227034e2
commit
ed7f278812
|
|
@ -81,6 +81,9 @@ struct ifa6_config {
|
|||
u8 ifa_proto;
|
||||
|
||||
const struct in6_addr *peer_pfx;
|
||||
struct inet6_ifaddr *ifpub;
|
||||
unsigned long cstamp;
|
||||
unsigned long tstamp;
|
||||
|
||||
u32 rt_priority;
|
||||
u32 ifa_flags;
|
||||
|
|
|
|||
|
|
@ -1155,10 +1155,19 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
|
|||
ifa->flags |= IFA_F_TENTATIVE;
|
||||
ifa->valid_lft = cfg->valid_lft;
|
||||
ifa->prefered_lft = cfg->preferred_lft;
|
||||
ifa->cstamp = ifa->tstamp = jiffies;
|
||||
ifa->tokenized = false;
|
||||
|
||||
ifa->rt = f6i;
|
||||
ifa->ifpub = cfg->ifpub;
|
||||
if (cfg->ifpub) {
|
||||
ifa->cstamp = cfg->cstamp;
|
||||
ifa->tstamp = cfg->tstamp;
|
||||
} else {
|
||||
unsigned long now = jiffies;
|
||||
|
||||
ifa->cstamp = now;
|
||||
ifa->tstamp = now;
|
||||
}
|
||||
|
||||
ifa->idev = idev;
|
||||
in6_dev_hold(idev);
|
||||
|
|
@ -1491,6 +1500,9 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
|
|||
|
||||
cfg.pfx = &addr;
|
||||
cfg.scope = ipv6_addr_scope(cfg.pfx);
|
||||
cfg.ifpub = ifp;
|
||||
cfg.cstamp = now;
|
||||
cfg.tstamp = tmp_tstamp;
|
||||
|
||||
ift = ipv6_add_addr(idev, &cfg, block, NULL);
|
||||
if (IS_ERR(ift)) {
|
||||
|
|
@ -1501,12 +1513,6 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
|
|||
goto retry;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ift->lock);
|
||||
ift->ifpub = ifp;
|
||||
ift->cstamp = now;
|
||||
ift->tstamp = tmp_tstamp;
|
||||
spin_unlock_bh(&ift->lock);
|
||||
|
||||
addrconf_dad_start(ift);
|
||||
in6_ifa_put(ift);
|
||||
in6_dev_put(idev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user