mainline inclusion from mainline-v6.6-rc2 commit ac28b1ec6135649b5d78b028e47264cb3ebca5ea category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I869PY CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
---------------------------
I got the below warning when do fuzzing test: unregister_netdevice: waiting for bond0 to become free. Usage count = 2
It can be repoduced via:
ip link add bond0 type bond sysctl -w net.ipv4.conf.bond0.promote_secondaries=1 ip addr add 4.117.174.103/0 scope 0x40 dev bond0 ip addr add 192.168.100.111/255.255.255.254 scope 0 dev bond0 ip addr add 0.0.0.4/0 scope 0x40 secondary dev bond0 ip addr del 4.117.174.103/0 scope 0x40 dev bond0 ip link delete bond0 type bond
In this reproduction test case, an incorrect 'last_prim' is found in __inet_del_ifa(), as a result, the secondary address(0.0.0.4/0 scope 0x40) is lost. The memory of the secondary address is leaked and the reference of in_device and net_device is leaked.
Fix this problem: Look for 'last_prim' starting at location of the deleted IP and inserting the promoted IP into the location of 'last_prim'.
Fixes: 0ff60a45678e ("[IPV4]: Fix secondary IP addresses after promotion") Signed-off-by: Liu Jian liujian56@huawei.com Signed-off-by: Julian Anastasov ja@ssi.bg Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Liu Jian liujian56@huawei.com
Conflicts: net/ipv4/devinet.c --- net/ipv4/devinet.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 12a2cea9d606..64f0fa0be370 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -341,12 +341,13 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, { struct in_ifaddr *promote = NULL; struct in_ifaddr *ifa, *ifa1 = *ifap; - struct in_ifaddr *last_prim = in_dev->ifa_list; + struct in_ifaddr **last_prim; struct in_ifaddr *prev_prom = NULL; int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);
ASSERT_RTNL();
+ last_prim = ifap; if (in_dev->dead) goto no_promotions;
@@ -360,7 +361,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, while ((ifa = *ifap1) != NULL) { if (!(ifa->ifa_flags & IFA_F_SECONDARY) && ifa1->ifa_scope <= ifa->ifa_scope) - last_prim = ifa; + last_prim = &ifa->ifa_next;
if (!(ifa->ifa_flags & IFA_F_SECONDARY) || ifa1->ifa_mask != ifa->ifa_mask || @@ -420,8 +421,8 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
if (prev_prom) { prev_prom->ifa_next = promote->ifa_next; - promote->ifa_next = last_prim->ifa_next; - last_prim->ifa_next = promote; + promote->ifa_next = *last_prim; + *last_prim = promote; }
promote->ifa_flags &= ~IFA_F_SECONDARY;