Skip to content

Commit

Permalink
net: ethtool: Unify ETHTOOL_{G,S}RXFH rxnfc copy
Browse files Browse the repository at this point in the history
ETHTOOL_GRXFH correctly copies in the full struct ethtool_rxnfc when
FLOW_RSS is set; ETHTOOL_SRXFH needs a similar code path to handle the
FLOW_RSS case so that ethtool can set the flow hash for custom RSS
contexts (if supported by the driver).

The copy code from ETHTOOL_GRXFH has been pulled out in to a helper so
that it can be called in both ETHTOOL_{G,S}RXFH code paths.

Acked-by: Edward Cree <[email protected]>
Signed-off-by: Joe Damato <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jdamato-fsly authored and davem330 committed Jul 28, 2023
1 parent 3d40aed commit 801b27e
Showing 1 changed file with 38 additions and 37 deletions.
75 changes: 38 additions & 37 deletions net/ethtool/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -907,6 +907,38 @@ static int ethtool_rxnfc_copy_to_compat(void __user *useraddr,
return 0;
}

static int ethtool_rxnfc_copy_struct(u32 cmd, struct ethtool_rxnfc *info,
size_t *info_size, void __user *useraddr)
{
/* struct ethtool_rxnfc was originally defined for
* ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
* members. User-space might still be using that
* definition.
*/
if (cmd == ETHTOOL_GRXFH || cmd == ETHTOOL_SRXFH)
*info_size = (offsetof(struct ethtool_rxnfc, data) +
sizeof(info->data));

if (ethtool_rxnfc_copy_from_user(info, useraddr, *info_size))
return -EFAULT;

if ((cmd == ETHTOOL_GRXFH || cmd == ETHTOOL_SRXFH) && info->flow_type & FLOW_RSS) {
*info_size = sizeof(*info);
if (ethtool_rxnfc_copy_from_user(info, useraddr, *info_size))
return -EFAULT;
/* Since malicious users may modify the original data,
* we need to check whether FLOW_RSS is still requested.
*/
if (!(info->flow_type & FLOW_RSS))
return -EINVAL;
}

if (info->cmd != cmd)
return -EINVAL;

return 0;
}

static int ethtool_rxnfc_copy_to_user(void __user *useraddr,
const struct ethtool_rxnfc *rxnfc,
size_t size, const u32 *rule_buf)
Expand Down Expand Up @@ -944,16 +976,9 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
if (!dev->ethtool_ops->set_rxnfc)
return -EOPNOTSUPP;

/* struct ethtool_rxnfc was originally defined for
* ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
* members. User-space might still be using that
* definition. */
if (cmd == ETHTOOL_SRXFH)
info_size = (offsetof(struct ethtool_rxnfc, data) +
sizeof(info.data));

if (ethtool_rxnfc_copy_from_user(&info, useraddr, info_size))
return -EFAULT;
rc = ethtool_rxnfc_copy_struct(cmd, &info, &info_size, useraddr);
if (rc)
return rc;

rc = dev->ethtool_ops->set_rxnfc(dev, &info);
if (rc)
Expand All @@ -978,33 +1003,9 @@ static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev,
if (!ops->get_rxnfc)
return -EOPNOTSUPP;

/* struct ethtool_rxnfc was originally defined for
* ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data
* members. User-space might still be using that
* definition. */
if (cmd == ETHTOOL_GRXFH)
info_size = (offsetof(struct ethtool_rxnfc, data) +
sizeof(info.data));

if (ethtool_rxnfc_copy_from_user(&info, useraddr, info_size))
return -EFAULT;

/* If FLOW_RSS was requested then user-space must be using the
* new definition, as FLOW_RSS is newer.
*/
if (cmd == ETHTOOL_GRXFH && info.flow_type & FLOW_RSS) {
info_size = sizeof(info);
if (ethtool_rxnfc_copy_from_user(&info, useraddr, info_size))
return -EFAULT;
/* Since malicious users may modify the original data,
* we need to check whether FLOW_RSS is still requested.
*/
if (!(info.flow_type & FLOW_RSS))
return -EINVAL;
}

if (info.cmd != cmd)
return -EINVAL;
ret = ethtool_rxnfc_copy_struct(cmd, &info, &info_size, useraddr);
if (ret)
return ret;

if (info.cmd == ETHTOOL_GRXCLSRLALL) {
if (info.rule_cnt > 0) {
Expand Down

0 comments on commit 801b27e

Please sign in to comment.