Commit 6e701eb9 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Jakub Kicinski

ipv4: Set ifa->ifa_dev in inet_alloc_ifa().

When a new IPv4 address is assigned via ioctl(SIOCSIFADDR),
inet_set_ifa() sets ifa->ifa_dev if it's different from in_dev
passed as an argument.

In this case, ifa is always a newly allocated object, and
ifa->ifa_dev is NULL.

inet_set_ifa() can be called for an existing reused ifa, then,
this check is always false.

Let's set ifa_dev in inet_alloc_ifa() and remove the check
in inet_set_ifa().

Now, inet_alloc_ifa() is symmetric with inet_rcu_free_ifa().
Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20240809235406.50187-3-kuniyu@amazon.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent e3af3d3c
......@@ -216,9 +216,18 @@ static void devinet_sysctl_unregister(struct in_device *idev)
/* Locks all the inet devices. */
static struct in_ifaddr *inet_alloc_ifa(void)
static struct in_ifaddr *inet_alloc_ifa(struct in_device *in_dev)
{
return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL_ACCOUNT);
struct in_ifaddr *ifa;
ifa = kzalloc(sizeof(*ifa), GFP_KERNEL_ACCOUNT);
if (!ifa)
return NULL;
in_dev_hold(in_dev);
ifa->ifa_dev = in_dev;
return ifa;
}
static void inet_rcu_free_ifa(struct rcu_head *head)
......@@ -576,11 +585,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
if (ifa->ifa_dev != in_dev) {
WARN_ON(ifa->ifa_dev);
in_dev_hold(in_dev);
ifa->ifa_dev = in_dev;
}
if (ipv4_is_loopback(ifa->ifa_local))
ifa->ifa_scope = RT_SCOPE_HOST;
return inet_insert_ifa(ifa);
......@@ -871,7 +876,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
if (!in_dev)
goto errout;
ifa = inet_alloc_ifa();
ifa = inet_alloc_ifa(in_dev);
if (!ifa)
/*
* A potential indev allocation can be left alive, it stays
......@@ -881,7 +886,6 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
ipv4_devconf_setall(in_dev);
neigh_parms_data_state_setall(in_dev->arp_parms);
in_dev_hold(in_dev);
if (!tb[IFA_ADDRESS])
tb[IFA_ADDRESS] = tb[IFA_LOCAL];
......@@ -892,8 +896,6 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) :
ifm->ifa_flags;
ifa->ifa_scope = ifm->ifa_scope;
ifa->ifa_dev = in_dev;
ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]);
ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]);
......@@ -1182,7 +1184,7 @@ int devinet_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr)
ret = -ENOBUFS;
if (!in_dev)
break;
ifa = inet_alloc_ifa();
ifa = inet_alloc_ifa(in_dev);
if (!ifa)
break;
INIT_HLIST_NODE(&ifa->hash);
......@@ -1584,7 +1586,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
if (!inetdev_valid_mtu(dev->mtu))
break;
if (dev->flags & IFF_LOOPBACK) {
struct in_ifaddr *ifa = inet_alloc_ifa();
struct in_ifaddr *ifa = inet_alloc_ifa(in_dev);
if (ifa) {
INIT_HLIST_NODE(&ifa->hash);
......@@ -1592,8 +1594,6 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
ifa->ifa_address = htonl(INADDR_LOOPBACK);
ifa->ifa_prefixlen = 8;
ifa->ifa_mask = inet_make_mask(8);
in_dev_hold(in_dev);
ifa->ifa_dev = in_dev;
ifa->ifa_scope = RT_SCOPE_HOST;
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
set_ifa_lifetime(ifa, INFINITY_LIFE_TIME,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment