* [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets
@ 2026-04-08 7:08 Hangbin Liu
2026-04-08 7:08 ` [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest Hangbin Liu
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Hangbin Liu @ 2026-04-08 7:08 UTC (permalink / raw)
To: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Andrew Lunn
Cc: netdev, linux-kernel, Hangbin Liu
This series addresses a silent data corruption issue triggered when ynl
retrieves string sets from NICs with a large number of statistics entries
(e.g. mlx5_core with thousands of ETH_SS_STATS strings).
The root cause is that struct nlattr.nla_len is a __u16 (max 65535
bytes). When a NIC exports enough statistics strings, the
ETHTOOL_A_STRINGSET_STRINGS nest built by strset_fill_set() exceeds
this limit. nla_nest_end() silently truncates the length on assignment,
producing a corrupted netlink message.
Patch 1 moves ethtool.py to selftest.
Patch 2 improves the ethtool tool: rename the doit/dumpit helpers
to do_set/do_get and convert do_get to use ynl.do() with an
explicit device header instead of a full dump with client-side filtering.
Patch 3 adds a --dbg-small-recv option to the YNL ethtool tool,
matching the same option already present in cli.py, to help debug netlink
message size issues
Patch 4 adds a new helper nla_nest_end_safe() to check whether the nla_len
is overflow and return -EMSGSIZE early if so.
Patch 5 uses the new helper in ethtool to make sure the ethtool doesn't
reply a corrupted netlink message.
---
Changes in v2:
- move ethtool.py to selftest (Jakub Kicinski)
- add a new helper nla_nest_end_safe (Jakub Kicinski)
- Link to v1: https://lore.kernel.org/r/20260331-b4-ynl_ethtool-v1-0-dda2a9b55df8@gmail.com
---
Hangbin Liu (5):
tools: ynl: move ethtool.py to selftest
tools: ynl: ethtool: use doit instead of dumpit for per-device GET
tools: ynl: ethtool: add --dbg-small-recv option
netlink: add a nla_nest_end_safe() helper
ethtool: strset: check nla_len overflow
include/net/netlink.h | 19 ++++++++
net/ethtool/strset.c | 3 +-
tools/net/ynl/tests/Makefile | 5 +-
tools/net/ynl/{pyynl => tests}/ethtool.py | 79 ++++++++++++++++---------------
tools/net/ynl/tests/test_ynl_ethtool.sh | 2 +-
5 files changed, 68 insertions(+), 40 deletions(-)
---
base-commit: e65d8b6f3092398efd7c74e722cb7a516d9a0d6d
change-id: 20260324-b4-ynl_ethtool-f87cd42f572c
Best regards,
--
Hangbin Liu <liuhangbin@gmail.com>
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest 2026-04-08 7:08 [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets Hangbin Liu @ 2026-04-08 7:08 ` Hangbin Liu 2026-04-08 16:42 ` Stanislav Fomichev 2026-04-08 7:08 ` [PATCH net-next v2 2/5] tools: ynl: ethtool: use doit instead of dumpit for per-device GET Hangbin Liu ` (3 subsequent siblings) 4 siblings, 1 reply; 8+ messages in thread From: Hangbin Liu @ 2026-04-08 7:08 UTC (permalink / raw) To: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn Cc: netdev, linux-kernel, Hangbin Liu We have converted all the samples to selftests. This script is the last piece of random "PoC" code we still have lying around. Let's move it to tests. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> --- tools/net/ynl/tests/Makefile | 5 ++++- tools/net/ynl/{pyynl => tests}/ethtool.py | 2 +- tools/net/ynl/tests/test_ynl_ethtool.sh | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/net/ynl/tests/Makefile b/tools/net/ynl/tests/Makefile index 2a02958c7039..94bf0346b54d 100644 --- a/tools/net/ynl/tests/Makefile +++ b/tools/net/ynl/tests/Makefile @@ -36,7 +36,10 @@ TEST_GEN_FILES := \ rt-route \ # end of TEST_GEN_FILES -TEST_FILES := ynl_nsim_lib.sh +TEST_FILES := \ + ethtool.py \ + ynl_nsim_lib.sh \ +# end of TEST_FILES CFLAGS_netdev:=$(CFLAGS_netdev) $(CFLAGS_rt-link) CFLAGS_ovs:=$(CFLAGS_ovs_datapath) diff --git a/tools/net/ynl/pyynl/ethtool.py b/tools/net/ynl/tests/ethtool.py similarity index 99% rename from tools/net/ynl/pyynl/ethtool.py rename to tools/net/ynl/tests/ethtool.py index f1a2a2a89985..6eeeb867edcf 100755 --- a/tools/net/ynl/pyynl/ethtool.py +++ b/tools/net/ynl/tests/ethtool.py @@ -14,7 +14,7 @@ import re import os # pylint: disable=no-name-in-module,wrong-import-position -sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) +sys.path.append(pathlib.Path(__file__).resolve().parent.parent.joinpath('pyynl').as_posix()) # pylint: disable=import-error from cli import schema_dir, spec_dir from lib import YnlFamily diff --git a/tools/net/ynl/tests/test_ynl_ethtool.sh b/tools/net/ynl/tests/test_ynl_ethtool.sh index b826269017f4..b4480e9be7b7 100755 --- a/tools/net/ynl/tests/test_ynl_ethtool.sh +++ b/tools/net/ynl/tests/test_ynl_ethtool.sh @@ -8,7 +8,7 @@ KSELFTEST_KTAP_HELPERS="$(dirname "$(realpath "$0")")/../../../testing/selftests source "$KSELFTEST_KTAP_HELPERS" # Default ynl-ethtool path for direct execution, can be overridden by make install -ynl_ethtool="../pyynl/ethtool.py" +ynl_ethtool="./ethtool.py" readonly NSIM_ID="1337" readonly NSIM_DEV_NAME="nsim${NSIM_ID}" -- Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest 2026-04-08 7:08 ` [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest Hangbin Liu @ 2026-04-08 16:42 ` Stanislav Fomichev 0 siblings, 0 replies; 8+ messages in thread From: Stanislav Fomichev @ 2026-04-08 16:42 UTC (permalink / raw) To: Hangbin Liu Cc: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn, netdev, linux-kernel On 04/08, Hangbin Liu wrote: > We have converted all the samples to selftests. This script is > the last piece of random "PoC" code we still have lying around. > Let's move it to tests. > > Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> > --- > tools/net/ynl/tests/Makefile | 5 ++++- > tools/net/ynl/{pyynl => tests}/ethtool.py | 2 +- > tools/net/ynl/tests/test_ynl_ethtool.sh | 2 +- > 3 files changed, 6 insertions(+), 3 deletions(-) > > diff --git a/tools/net/ynl/tests/Makefile b/tools/net/ynl/tests/Makefile > index 2a02958c7039..94bf0346b54d 100644 > --- a/tools/net/ynl/tests/Makefile > +++ b/tools/net/ynl/tests/Makefile > @@ -36,7 +36,10 @@ TEST_GEN_FILES := \ > rt-route \ > # end of TEST_GEN_FILES > > -TEST_FILES := ynl_nsim_lib.sh > +TEST_FILES := \ > + ethtool.py \ > + ynl_nsim_lib.sh \ > +# end of TEST_FILES > > CFLAGS_netdev:=$(CFLAGS_netdev) $(CFLAGS_rt-link) > CFLAGS_ovs:=$(CFLAGS_ovs_datapath) > diff --git a/tools/net/ynl/pyynl/ethtool.py b/tools/net/ynl/tests/ethtool.py > similarity index 99% > rename from tools/net/ynl/pyynl/ethtool.py > rename to tools/net/ynl/tests/ethtool.py > index f1a2a2a89985..6eeeb867edcf 100755 > --- a/tools/net/ynl/pyynl/ethtool.py > +++ b/tools/net/ynl/tests/ethtool.py > @@ -14,7 +14,7 @@ import re > import os > > # pylint: disable=no-name-in-module,wrong-import-position > -sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) > +sys.path.append(pathlib.Path(__file__).resolve().parent.parent.joinpath('pyynl').as_posix()) > # pylint: disable=import-error > from cli import schema_dir, spec_dir > from lib import YnlFamily > diff --git a/tools/net/ynl/tests/test_ynl_ethtool.sh b/tools/net/ynl/tests/test_ynl_ethtool.sh > index b826269017f4..b4480e9be7b7 100755 > --- a/tools/net/ynl/tests/test_ynl_ethtool.sh > +++ b/tools/net/ynl/tests/test_ynl_ethtool.sh > @@ -8,7 +8,7 @@ KSELFTEST_KTAP_HELPERS="$(dirname "$(realpath "$0")")/../../../testing/selftests > source "$KSELFTEST_KTAP_HELPERS" > > # Default ynl-ethtool path for direct execution, can be overridden by make install > -ynl_ethtool="../pyynl/ethtool.py" > +ynl_ethtool="./ethtool.py" > > readonly NSIM_ID="1337" > readonly NSIM_DEV_NAME="nsim${NSIM_ID}" Do we need to add some expects/asserts to the script to really make it into a test? Right now it just prints things, so it's not really a test. ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net-next v2 2/5] tools: ynl: ethtool: use doit instead of dumpit for per-device GET 2026-04-08 7:08 [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest Hangbin Liu @ 2026-04-08 7:08 ` Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 3/5] tools: ynl: ethtool: add --dbg-small-recv option Hangbin Liu ` (2 subsequent siblings) 4 siblings, 0 replies; 8+ messages in thread From: Hangbin Liu @ 2026-04-08 7:08 UTC (permalink / raw) To: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn Cc: netdev, linux-kernel, Hangbin Liu Rename the local helper doit() to do_set() and dumpit() to do_get() to better reflect their purpose. Convert do_get() to use ynl.do() with an explicit device header instead of ynl.dump() followed by client-side filtering. This is more efficient as the kernel only processes and returns data for the requested device, rather than dumping all devices across the netns. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> --- tools/net/ynl/tests/ethtool.py | 68 ++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/tools/net/ynl/tests/ethtool.py b/tools/net/ynl/tests/ethtool.py index 6eeeb867edcf..63854d21818c 100755 --- a/tools/net/ynl/tests/ethtool.py +++ b/tools/net/ynl/tests/ethtool.py @@ -84,9 +84,9 @@ def print_speed(name, value): speed = [ k for k, v in value.items() if v and speed_re.match(k) ] print(f'{name}: {" ".join(speed)}') -def doit(ynl, args, op_name): +def do_set(ynl, args, op_name): """ - Prepare request header, parse arguments and doit. + Prepare request header, parse arguments and do a set operation. """ req = { 'header': { @@ -97,26 +97,24 @@ def doit(ynl, args, op_name): args_to_req(ynl, op_name, args.args, req) ynl.do(op_name, req) -def dumpit(ynl, args, op_name, extra=None): +def do_get(ynl, args, op_name, extra=None): """ - Prepare request header, parse arguments and dumpit (filtering out the - devices we're not interested in). + Prepare request header and get info for a specific device using doit. """ extra = extra or {} - reply = ynl.dump(op_name, { 'header': {} } | extra) + req = {'header': {'dev-name': args.device}} + req['header'].update(extra.pop('header', {})) + req.update(extra) + + reply = ynl.do(op_name, req) if not reply: return {} - for msg in reply: - if msg['header']['dev-name'] == args.device: - if args.json: - pprint.PrettyPrinter().pprint(msg) - sys.exit(0) - msg.pop('header', None) - return msg - - print(f"Not supported for device {args.device}") - sys.exit(1) + if args.json: + pprint.PrettyPrinter().pprint(reply) + sys.exit(0) + reply.pop('header', None) + return reply def bits_to_dict(attr): """ @@ -181,15 +179,15 @@ def main(): return if args.set_eee: - doit(ynl, args, 'eee-set') + do_set(ynl, args, 'eee-set') return if args.set_pause: - doit(ynl, args, 'pause-set') + do_set(ynl, args, 'pause-set') return if args.set_coalesce: - doit(ynl, args, 'coalesce-set') + do_set(ynl, args, 'coalesce-set') return if args.set_features: @@ -198,20 +196,20 @@ def main(): return if args.set_channels: - doit(ynl, args, 'channels-set') + do_set(ynl, args, 'channels-set') return if args.set_ring: - doit(ynl, args, 'rings-set') + do_set(ynl, args, 'rings-set') return if args.show_priv_flags: - flags = bits_to_dict(dumpit(ynl, args, 'privflags-get')['flags']) + flags = bits_to_dict(do_get(ynl, args, 'privflags-get')['flags']) print_field(flags) return if args.show_eee: - eee = dumpit(ynl, args, 'eee-get') + eee = do_get(ynl, args, 'eee-get') ours = bits_to_dict(eee['modes-ours']) peer = bits_to_dict(eee['modes-peer']) @@ -232,18 +230,18 @@ def main(): return if args.show_pause: - print_field(dumpit(ynl, args, 'pause-get'), + print_field(do_get(ynl, args, 'pause-get'), ('autoneg', 'Autonegotiate', 'bool'), ('rx', 'RX', 'bool'), ('tx', 'TX', 'bool')) return if args.show_coalesce: - print_field(dumpit(ynl, args, 'coalesce-get')) + print_field(do_get(ynl, args, 'coalesce-get')) return if args.show_features: - reply = dumpit(ynl, args, 'features-get') + reply = do_get(ynl, args, 'features-get') available = bits_to_dict(reply['hw']) requested = bits_to_dict(reply['wanted']).keys() active = bits_to_dict(reply['active']).keys() @@ -270,7 +268,7 @@ def main(): return if args.show_channels: - reply = dumpit(ynl, args, 'channels-get') + reply = do_get(ynl, args, 'channels-get') print(f'Channel parameters for {args.device}:') print('Pre-set maximums:') @@ -290,7 +288,7 @@ def main(): return if args.show_ring: - reply = dumpit(ynl, args, 'channels-get') + reply = do_get(ynl, args, 'channels-get') print(f'Ring parameters for {args.device}:') @@ -319,7 +317,7 @@ def main(): print('NIC statistics:') # TODO: pass id? - strset = dumpit(ynl, args, 'strset-get') + strset = do_get(ynl, args, 'strset-get') pprint.PrettyPrinter().pprint(strset) req = { @@ -338,7 +336,7 @@ def main(): }, } - rsp = dumpit(ynl, args, 'stats-get', req) + rsp = do_get(ynl, args, 'stats-get', req) pprint.PrettyPrinter().pprint(rsp) return @@ -349,7 +347,7 @@ def main(): }, } - tsinfo = dumpit(ynl, args, 'tsinfo-get', req) + tsinfo = do_get(ynl, args, 'tsinfo-get', req) print(f'Time stamping parameters for {args.device}:') @@ -377,7 +375,7 @@ def main(): return print(f'Settings for {args.device}:') - linkmodes = dumpit(ynl, args, 'linkmodes-get') + linkmodes = do_get(ynl, args, 'linkmodes-get') ours = bits_to_dict(linkmodes['ours']) supported_ports = ('TP', 'AUI', 'BNC', 'MII', 'FIBRE', 'Backplane') @@ -425,7 +423,7 @@ def main(): 5: 'Directly Attached Copper', 0xef: 'None', } - linkinfo = dumpit(ynl, args, 'linkinfo-get') + linkinfo = do_get(ynl, args, 'linkinfo-get') print(f'Port: {ports.get(linkinfo["port"], "Other")}') print_field(linkinfo, ('phyaddr', 'PHYAD')) @@ -447,11 +445,11 @@ def main(): mdix = mdix_ctrl.get(linkinfo['tp-mdix'], 'Unknown (auto)') print(f'MDI-X: {mdix}') - debug = dumpit(ynl, args, 'debug-get') + debug = do_get(ynl, args, 'debug-get') msgmask = bits_to_dict(debug.get("msgmask", [])).keys() print(f'Current message level: {" ".join(msgmask)}') - linkstate = dumpit(ynl, args, 'linkstate-get') + linkstate = do_get(ynl, args, 'linkstate-get') detected_states = { 0: 'no', 1: 'yes', -- Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net-next v2 3/5] tools: ynl: ethtool: add --dbg-small-recv option 2026-04-08 7:08 [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 2/5] tools: ynl: ethtool: use doit instead of dumpit for per-device GET Hangbin Liu @ 2026-04-08 7:08 ` Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 4/5] netlink: add a nla_nest_end_safe() helper Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 5/5] ethtool: strset: check nla_len overflow Hangbin Liu 4 siblings, 0 replies; 8+ messages in thread From: Hangbin Liu @ 2026-04-08 7:08 UTC (permalink / raw) To: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn Cc: netdev, linux-kernel, Hangbin Liu Add a --dbg-small-recv debug option to control the recv() buffer size used by YNL, matching the same option already present in cli.py. This is useful if user need to get large netlink message. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> --- tools/net/ynl/tests/ethtool.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/net/ynl/tests/ethtool.py b/tools/net/ynl/tests/ethtool.py index 63854d21818c..db3b62c652e7 100755 --- a/tools/net/ynl/tests/ethtool.py +++ b/tools/net/ynl/tests/ethtool.py @@ -166,12 +166,19 @@ def main(): parser.add_argument('device', metavar='device', type=str) parser.add_argument('args', metavar='args', type=str, nargs='*') + dbg_group = parser.add_argument_group('Debug options') + dbg_group.add_argument('--dbg-small-recv', default=0, const=4000, + action='store', nargs='?', type=int, metavar='INT', + help="Length of buffers used for recv()") + args = parser.parse_args() spec = os.path.join(spec_dir(), 'ethtool.yaml') schema = os.path.join(schema_dir(), 'genetlink-legacy.yaml') - ynl = YnlFamily(spec, schema) + ynl = YnlFamily(spec, schema, recv_size=args.dbg_small_recv) + if args.dbg_small_recv: + ynl.set_recv_dbg(True) if args.set_priv_flags: # TODO: parse the bitmask -- Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net-next v2 4/5] netlink: add a nla_nest_end_safe() helper 2026-04-08 7:08 [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets Hangbin Liu ` (2 preceding siblings ...) 2026-04-08 7:08 ` [PATCH net-next v2 3/5] tools: ynl: ethtool: add --dbg-small-recv option Hangbin Liu @ 2026-04-08 7:08 ` Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 5/5] ethtool: strset: check nla_len overflow Hangbin Liu 4 siblings, 0 replies; 8+ messages in thread From: Hangbin Liu @ 2026-04-08 7:08 UTC (permalink / raw) To: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn Cc: netdev, linux-kernel, Hangbin Liu The nla_len field in struct nlattr is a __u16, which can only hold values up to 65535. If a nested attribute grows beyond this limit, nla_nest_end() silently truncates the length, producing a corrupted netlink message with no indication of the problem. Since nla_nest_end() is used everywhere and this issue rarely happens, let's add a new helper to check the length. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> --- include/net/netlink.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/net/netlink.h b/include/net/netlink.h index 1a8356ca4b78..546d10586576 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -2264,6 +2264,25 @@ static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start) return skb->len; } +/** + * nla_nest_end_safe - Validate and finalize nesting of attributes + * @skb: socket buffer the attributes are stored in + * @start: container attribute + * + * Corrects the container attribute header to include all appended + * attributes. + * + * Returns: the total data length of the skb, or -EMSGSIZE if the + * nested attribute length exceeds U16_MAX. + */ +static inline int nla_nest_end_safe(struct sk_buff *skb, struct nlattr *start) +{ + if (skb_tail_pointer(skb) - (unsigned char *)start > U16_MAX) + return -EMSGSIZE; + + return nla_nest_end(skb, start); +} + /** * nla_nest_cancel - Cancel nesting of attributes * @skb: socket buffer the message is stored in -- Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH net-next v2 5/5] ethtool: strset: check nla_len overflow 2026-04-08 7:08 [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets Hangbin Liu ` (3 preceding siblings ...) 2026-04-08 7:08 ` [PATCH net-next v2 4/5] netlink: add a nla_nest_end_safe() helper Hangbin Liu @ 2026-04-08 7:08 ` Hangbin Liu 2026-04-08 16:43 ` Stanislav Fomichev 4 siblings, 1 reply; 8+ messages in thread From: Hangbin Liu @ 2026-04-08 7:08 UTC (permalink / raw) To: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn Cc: netdev, linux-kernel, Hangbin Liu The netlink attribute length field nla_len is a __u16, which can only represent values up to 65535 bytes. NICs with a large number of statistics strings (e.g. mlx5_core with thousands of ETH_SS_STATS entries) can produce a ETHTOOL_A_STRINGSET_STRINGS nest that exceeds this limit. When nla_nest_end() writes the actual nest size back to nla_len, the value is silently truncated. This results in a corrupted netlink message being sent to userspace: the parser reads a wrong (truncated) attribute length and misaligns all subsequent attribute boundaries, causing decode errors. Fix this by using the new helper nla_nest_end_safe and error out if the size exceeds U16_MAX. Signed-off-by: Hangbin Liu <liuhangbin@gmail.com> --- net/ethtool/strset.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c index 9271aba8255e..bb1e829ba099 100644 --- a/net/ethtool/strset.c +++ b/net/ethtool/strset.c @@ -443,7 +443,8 @@ static int strset_fill_set(struct sk_buff *skb, if (strset_fill_string(skb, set_info, i) < 0) goto nla_put_failure; } - nla_nest_end(skb, strings_attr); + if (nla_nest_end_safe(skb, strings_attr) < 0) + goto nla_put_failure; } nla_nest_end(skb, stringset_attr); -- Git-155) ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH net-next v2 5/5] ethtool: strset: check nla_len overflow 2026-04-08 7:08 ` [PATCH net-next v2 5/5] ethtool: strset: check nla_len overflow Hangbin Liu @ 2026-04-08 16:43 ` Stanislav Fomichev 0 siblings, 0 replies; 8+ messages in thread From: Stanislav Fomichev @ 2026-04-08 16:43 UTC (permalink / raw) To: Hangbin Liu Cc: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman, Andrew Lunn, netdev, linux-kernel On 04/08, Hangbin Liu wrote: > The netlink attribute length field nla_len is a __u16, which can only > represent values up to 65535 bytes. NICs with a large number of > statistics strings (e.g. mlx5_core with thousands of ETH_SS_STATS > entries) can produce a ETHTOOL_A_STRINGSET_STRINGS nest that exceeds > this limit. > > When nla_nest_end() writes the actual nest size back to nla_len, the > value is silently truncated. This results in a corrupted netlink message > being sent to userspace: the parser reads a wrong (truncated) attribute > length and misaligns all subsequent attribute boundaries, causing decode > errors. > > Fix this by using the new helper nla_nest_end_safe and error out if > the size exceeds U16_MAX. Not sure that's the user supposed to do? Does it mean there is no way to retrieve ETHTOOL_A_STRINGSET_STRINGS for those devices with too many strings? ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-04-08 16:43 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-04-08 7:08 [PATCH net-next v2 0/5] ynl/ethtool/netlink: fix nla_len overflow for large string sets Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 1/5] tools: ynl: move ethtool.py to selftest Hangbin Liu 2026-04-08 16:42 ` Stanislav Fomichev 2026-04-08 7:08 ` [PATCH net-next v2 2/5] tools: ynl: ethtool: use doit instead of dumpit for per-device GET Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 3/5] tools: ynl: ethtool: add --dbg-small-recv option Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 4/5] netlink: add a nla_nest_end_safe() helper Hangbin Liu 2026-04-08 7:08 ` [PATCH net-next v2 5/5] ethtool: strset: check nla_len overflow Hangbin Liu 2026-04-08 16:43 ` Stanislav Fomichev
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox