mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ipv6: reject wrapped temporary address preferred lifetimes
ipv6_create_tempaddr() raises a temporary address's preferred lifetime to regen_advance + age + 1 when the configured lifetime is too short. The result is stored in a u32, while regen_advance and age are unsigned long. If the sum wraps or is truncated, the stored lifetime can still be less than or equal to regen_advance + age. addrconf_verify_rtnl() then sees the new address as due for regeneration and creates another one. Temporary addresses are not limited by max_addresses since commit4b08a8f1bd("ipv6: remove max_addresses check from ipv6_create_tempaddr"), so this can cause unbounded address growth. With dad_transmits set to -1, a baseline kernel reached 2859 loopback addresses in two seconds. After storing the adjusted lifetime, verify that it is still greater than regen_advance + age. Reject the new address if the check fails. On an x86-64 KASAN kernel, the normal configuration created three IPv6 addresses. The negative dad_transmits, positive multiplication overflow, and large retransmission-time cases each left only the loopback and public addresses. An i386 defconfig and an x86-64 allmodconfig both built addrconf.o with W=1. Fixes:f4bcbf360a("net: ipv6/addrconf: clamp preferred_lft to the minimum required") Cc: stable@vger.kernel.org Suggested-by: Ido Schimmel <idosch@nvidia.com> Link: https://lore.kernel.org/netdev/20261029175827.GA1411453@shredder/ Signed-off-by: Yingjie Wang <1075151112@qq.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Alex Henrie <alexhenrie24@gmail.com> Link: https://patch.msgid.link/tencent_7A270291DDE5CD89DAFFE8A745D094D5BD06@qq.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
3ae20e4697
commit
c3e67bd82b
|
|
@ -1487,7 +1487,8 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
|
|||
age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
|
||||
if (cfg.preferred_lft <= regen_advance + age) {
|
||||
cfg.preferred_lft = regen_advance + age + 1;
|
||||
if (cfg.preferred_lft > cfg.valid_lft ||
|
||||
if (cfg.preferred_lft <= regen_advance + age ||
|
||||
cfg.preferred_lft > cfg.valid_lft ||
|
||||
cfg.preferred_lft > if_public_preferred_lft) {
|
||||
in6_ifa_put(ifp);
|
||||
in6_dev_put(idev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user