From 085d61000845188a9aa9a9524f13a0622a1380d7 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 10 Dec 2021 16:59:59 +0800 Subject: [PATCH] Bonding: force user to add HWTSTAMP_FLAG_BONDED_PHC_INDEX when get/set HWTSTAMP When there is a failover, the PHC index of bond active interface will be changed. This may break the user space program if the author didn't aware. By setting this flag, the user should aware that the PHC index get/set by syscall is not stable. And the user space is able to deal with it. Without this flag, the kernel will reject the request forwarding to bonding. Reported-by: Jakub Kicinski Fixes: 94dd016ae538 ("bond: pass get_ts_info and SIOC[SG]HWTSTAMP ioctl to active device") Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 274f0c4f2dab..b60e22f6394a 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4094,6 +4094,7 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm struct mii_ioctl_data *mii = NULL; const struct net_device_ops *ops; struct net_device *real_dev; + struct hwtstamp_config cfg; struct ifreq ifrr; int res = 0; @@ -4124,21 +4125,29 @@ static int bond_eth_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cm break; case SIOCSHWTSTAMP: case SIOCGHWTSTAMP: - rcu_read_lock(); - real_dev = bond_option_active_slave_get_rcu(bond); - rcu_read_unlock(); - if (real_dev) { - strscpy_pad(ifrr.ifr_name, real_dev->name, IFNAMSIZ); - ifrr.ifr_ifru = ifr->ifr_ifru; + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + if (cfg.flags & HWTSTAMP_FLAG_BONDED_PHC_INDEX) { + rcu_read_lock(); + real_dev = bond_option_active_slave_get_rcu(bond); + rcu_read_unlock(); + if (real_dev) { + strscpy_pad(ifrr.ifr_name, real_dev->name, IFNAMSIZ); + ifrr.ifr_ifru = ifr->ifr_ifru; + + ops = real_dev->netdev_ops; + if (netif_device_present(real_dev) && ops->ndo_eth_ioctl) { + res = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd); - ops = real_dev->netdev_ops; - if (netif_device_present(real_dev) && ops->ndo_eth_ioctl) - res = ops->ndo_eth_ioctl(real_dev, &ifrr, cmd); + if (!res) + ifr->ifr_ifru = ifrr.ifr_ifru; - if (!res) - ifr->ifr_ifru = ifrr.ifr_ifru; + return res; + } + } } - break; + fallthrough; default: res = -EOPNOTSUPP; } -- 2.11.0