Merge branch 'ipv6-fix-error-handling-in-disable_ipv6-sysctl'

Fernando Fernandez Mancera says:

====================
ipv6: fix error handling in disable_ipv6 sysctl

While working on a different IPv6 patch series I have spotted multiple
minor bugs around sysctl error handling and notifications. In general,
they are not serious issues.

In addition, there is one more issue in forwarding sysctl as it does not
check for CAP_NET_ADMIN for the namespace. I am keeping that patch out
of this series and I am aiming it at the net-next tree once it re-opens.

During v3, Ido's pointed out that it is unnecessary to reset the
position pointer when the return value is negative as at
new_sync_write() the ppos is only advanced when ret return value is
positive. That means we can get rid of that operation in ipv4/ipv6
sysctls. That is going to be sent to net-next too.
====================

Link: https://patch.msgid.link/20260622130857.5115-1-fmancera@suse.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-06-23 19:12:49 -07:00
commit c793499057

View File

@ -913,7 +913,7 @@ static int addrconf_fixup_forwarding(const struct ctl_table *table, int *p, int
if (newf)
rt6_purge_dflt_routers(net);
return 1;
return 0;
}
static void addrconf_linkdown_change(struct net *net, __s32 newf)
@ -955,11 +955,7 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
NETCONFA_IFINDEX_DEFAULT,
net->ipv6.devconf_dflt);
rtnl_net_unlock(net);
return 0;
}
if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) {
} else if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) {
WRITE_ONCE(net->ipv6.devconf_dflt->ignore_routes_with_linkdown, newf);
addrconf_linkdown_change(net, newf);
if ((!newf) ^ (!old))
@ -968,11 +964,21 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
NETCONFA_IFINDEX_ALL,
net->ipv6.devconf_all);
} else {
if (!newf ^ !old) {
struct inet6_dev *idev = table->extra1;
inet6_netconf_notify_devconf(net,
RTM_NEWNETCONF,
NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
idev->dev->ifindex,
&idev->cnf);
}
}
rtnl_net_unlock(net);
return 1;
return 0;
}
#endif
@ -6370,6 +6376,8 @@ static int addrconf_sysctl_forward(const struct ctl_table *ctl, int write,
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
if (ret)
return ret;
if (write)
ret = addrconf_fixup_forwarding(ctl, valp, val);
@ -6467,6 +6475,8 @@ static int addrconf_sysctl_disable(const struct ctl_table *ctl, int write,
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
if (ret)
return ret;
if (write)
ret = addrconf_disable_ipv6(ctl, valp, val);
@ -6478,20 +6488,19 @@ static int addrconf_sysctl_disable(const struct ctl_table *ctl, int write,
static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
struct net *net = ctl->extra2;
int *valp = ctl->data;
int ret;
int old, new;
int ret;
if (write && !rtnl_net_trylock(net))
return restart_syscall();
old = *valp;
ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
new = *valp;
if (write && old != new) {
struct net *net = ctl->extra2;
if (!rtnl_net_trylock(net))
return restart_syscall();
if (valp == &net->ipv6.devconf_dflt->proxy_ndp) {
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
NETCONFA_PROXY_NEIGH,
@ -6510,8 +6519,9 @@ static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write,
idev->dev->ifindex,
&idev->cnf);
}
rtnl_net_unlock(net);
}
if (write)
rtnl_net_unlock(net);
return ret;
}
@ -6669,6 +6679,8 @@ int addrconf_sysctl_ignore_routes_with_linkdown(const struct ctl_table *ctl,
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
if (ret)
return ret;
if (write)
ret = addrconf_fixup_linkdown(ctl, valp, val);
@ -6763,6 +6775,8 @@ static int addrconf_sysctl_disable_policy(const struct ctl_table *ctl, int write
lctl = *ctl;
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
if (ret)
return ret;
if (write && (*valp != val))
ret = addrconf_disable_policy(ctl, valp, val);