mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
ethtool: rss: Fix hfunc and input_xfrm parsing on big endian
ETHTOOL_A_RSS_HFUNC and ETHTOOL_A_RSS_INPUT_XFRM are NLA_U32 attributes, but ethnl_rss_set() and ethnl_rss_create_doit() parse them with ethnl_update_u8(), which reads a single byte. On little endian this happens to read the least significant byte and works as long as the value fits in a byte. On big endian it reads the most significant byte, so the requested value is parsed incorrectly. The destination fields in struct ethtool_rxfh_param are u8, so the attribute can't be read directly with ethnl_update_u32(). Cap the hfunc policy at U8_MAX so an out of range value is rejected instead of being silently truncated into the u8 field, and add ethnl_update_u8_u32() to read the full u32 and narrow it into the u8 destination. Fixes:82ae67cbc4("ethtool: rss: support setting hfunc via Netlink") Fixes:d3e2c7bab1("ethtool: rss: support setting input-xfrm via Netlink") Fixes:a166ab7816("ethtool: rss: support creating contexts via Netlink") Reviewed-by: Dragos Tatulea <dtatulea@nvidia.com> Reviewed-by: Nimrod Oren <noren@nvidia.com> Signed-off-by: Gal Pressman <gal@nvidia.com> Link: https://patch.msgid.link/20260706055017.3355806-1-gal@nvidia.com Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
committed by
Paolo Abeni
parent
c914307e1d
commit
b62869a81a
@@ -114,6 +114,34 @@ static inline void ethnl_update_u8(u8 *dst, const struct nlattr *attr,
|
||||
*mod = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ethnl_update_u8_u32() - update u8 value from an NLA_U32 attribute
|
||||
* @dst: value to update
|
||||
* @attr: netlink attribute with new value or null
|
||||
* @mod: pointer to bool for modification tracking
|
||||
*
|
||||
* Some attributes are NLA_U32 on the wire but are stored in a u8. Read the
|
||||
* full 32-bit value from NLA_U32 netlink attribute @attr and narrow it into
|
||||
* the u8 pointed to by @dst; do nothing if @attr is null.
|
||||
* Bool pointed to by @mod is set to true if this function changed the value
|
||||
* of *dst, otherwise it is left as is.
|
||||
*/
|
||||
static inline void ethnl_update_u8_u32(u8 *dst, const struct nlattr *attr,
|
||||
bool *mod)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (!attr)
|
||||
return;
|
||||
val = nla_get_u32(attr);
|
||||
DEBUG_NET_WARN_ON_ONCE(val > U8_MAX);
|
||||
if (*dst == val)
|
||||
return;
|
||||
|
||||
*dst = val;
|
||||
*mod = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* ethnl_update_bool32() - update u32 used as bool from NLA_U8 attribute
|
||||
* @dst: value to update
|
||||
|
||||
@@ -570,7 +570,7 @@ static const struct nla_policy ethnl_rss_flows_policy[] = {
|
||||
const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = {
|
||||
[ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
|
||||
[ETHTOOL_A_RSS_CONTEXT] = { .type = NLA_U32, },
|
||||
[ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
|
||||
[ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX),
|
||||
[ETHTOOL_A_RSS_INDIR] = { .type = NLA_BINARY, },
|
||||
[ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
|
||||
[ETHTOOL_A_RSS_INPUT_XFRM] =
|
||||
@@ -851,7 +851,7 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
|
||||
indir_mod = !!tb[ETHTOOL_A_RSS_INDIR];
|
||||
|
||||
rxfh.hfunc = data.hfunc;
|
||||
ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
|
||||
ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
|
||||
if (rxfh.hfunc == data.hfunc)
|
||||
rxfh.hfunc = ETH_RSS_HASH_NO_CHANGE;
|
||||
|
||||
@@ -860,7 +860,8 @@ ethnl_rss_set(struct ethnl_req_info *req_info, struct genl_info *info)
|
||||
goto exit_free_indir;
|
||||
|
||||
rxfh.input_xfrm = data.input_xfrm;
|
||||
ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod);
|
||||
ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM],
|
||||
&mod);
|
||||
xfrm_sym = rxfh.input_xfrm || data.input_xfrm;
|
||||
if (rxfh.input_xfrm == data.input_xfrm)
|
||||
rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
|
||||
@@ -934,7 +935,7 @@ const struct ethnl_request_ops ethnl_rss_request_ops = {
|
||||
const struct nla_policy ethnl_rss_create_policy[ETHTOOL_A_RSS_INPUT_XFRM + 1] = {
|
||||
[ETHTOOL_A_RSS_HEADER] = NLA_POLICY_NESTED(ethnl_header_policy),
|
||||
[ETHTOOL_A_RSS_CONTEXT] = NLA_POLICY_MIN(NLA_U32, 1),
|
||||
[ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_MIN(NLA_U32, 1),
|
||||
[ETHTOOL_A_RSS_HFUNC] = NLA_POLICY_RANGE(NLA_U32, 1, U8_MAX),
|
||||
[ETHTOOL_A_RSS_INDIR] = NLA_POLICY_MIN(NLA_BINARY, 1),
|
||||
[ETHTOOL_A_RSS_HKEY] = NLA_POLICY_MIN(NLA_BINARY, 1),
|
||||
[ETHTOOL_A_RSS_INPUT_XFRM] =
|
||||
@@ -1048,14 +1049,15 @@ int ethnl_rss_create_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
goto exit_clean_data;
|
||||
indir_user_size = ret;
|
||||
|
||||
ethnl_update_u8(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
|
||||
ethnl_update_u8_u32(&rxfh.hfunc, tb[ETHTOOL_A_RSS_HFUNC], &mod);
|
||||
|
||||
ret = rss_set_prep_hkey(dev, info, &data, &rxfh, &mod);
|
||||
if (ret)
|
||||
goto exit_free_indir;
|
||||
|
||||
rxfh.input_xfrm = RXH_XFRM_NO_CHANGE;
|
||||
ethnl_update_u8(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM], &mod);
|
||||
ethnl_update_u8_u32(&rxfh.input_xfrm, tb[ETHTOOL_A_RSS_INPUT_XFRM],
|
||||
&mod);
|
||||
|
||||
ctx = ethtool_rxfh_ctx_alloc(ops, data.indir_size, data.hkey_size);
|
||||
if (!ctx) {
|
||||
|
||||
Reference in New Issue
Block a user