net/mctp/device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Some mctp configurations result in the userspace application
`mctp addr show`, which triggers an `mctp_dump_addrinfo`, to
be given infinite data. This was introduced by commit 2d20773aec14.
In `mctp_dump_addrinfo`, when the userspace buffer doesn't hold
enough space for all of the addresses, the function keeps the current
index in the netlink_callback so that it can resume on subsequent
calls. There are two indexes held: interface and address. When a
all the addresses for an interface has been sent, the code reset
the address to zero and relies on `for_each_netdev_dump` for
incrementing the index. However, `for_each_netdev_dump` (which is
using `xa_for_each_start`) does not set the index for the last
entry[1]. This can lead to the subsequent userspace request re-sending
the entire last interface.
Fix this by explicitly setting the index to ULONG_MAX[2] when all of
the interfaces and addresses have been successfully sent. This will
cause subsequent userspace request to be past the last interface in the
next `for_each_netdev_dump` call.
The previous failure could be aggravated by on a system using
aspeed-bmc-facebook-harma.dts by running:
```
mctp addr add 8 dev mctpi2c1
mctp addr show
```
[1]: https://github.com/torvalds/linux/blob/e271ed52b344ac02d4581286961d0c40acc54c03/lib/xarray.c#L2261
[2]: https://github.com/torvalds/linux/blob/e271ed52b344ac02d4581286961d0c40acc54c03/include/linux/xarray.h#L481
Fixes: 2d20773aec14 ("mctp: no longer rely on net->dev_index_head[]")
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
---
net/mctp/device.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/mctp/device.c b/net/mctp/device.c
index 4d404edd7446..a865445234af 100644
--- a/net/mctp/device.c
+++ b/net/mctp/device.c
@@ -140,9 +140,11 @@ static int mctp_dump_addrinfo(struct sk_buff *skb, struct netlink_callback *cb)
rc = mctp_dump_dev_addrinfo(mdev, skb, cb);
mctp_dev_put(mdev);
if (rc < 0)
- break;
+ goto out;
mcb->a_idx = 0;
}
+ mcb->ifindex = ULONG_MAX;
+out:
rcu_read_unlock();
return skb->len;
--
2.49.0
Hi Patrick, [+CC Peter Yin, who has reported a similar thing] Thanks for the report and patch. I've been staring at the for_each_netdev_dump() behaviour, and I'm not (yet) certain that the fix is sufficient: > When all the addresses for an interface has been sent, the code reset > the address to zero and relies on `for_each_netdev_dump` for > incrementing the index. However, `for_each_netdev_dump` (which is > using `xa_for_each_start`) does not set the index for the last > entry[1]. but that still seems to be acceptable: - if entry there is null (and so we're not updating *indexp), then xa_find() will be returning NULL - if xa_find returns NULL, we're not iterating the for-loop - therefore the original indexp value is sufficient to act as the loop terminator If an xa_find() of the index *does* yield a device, we'll increment index as part of the for_each_netdev_dump() macro (unless we're still working through the address array, in which case we do want to use the same index at the next call). FWIW, I'm not able to reproduce the issue here on v6.15, even when forcing various combinations of netlink-message splits, but we do have other reports of it happening. Are you able to share a trace of the recvfrom() calls for `mctp addr`? That may help to understand the breakage. So, it seems like there's something more subtle happening here - or I have misunderstood something about the fix (I'm unsure of the reference to xa_for_each_start; for_each_netdev_dump only calls xa_start?). I'll continue with the debug and update shortly. Cheers, Jeremy
Hi Patrick,
[+CC Andrew, for openbmc kernel reasons]
> So, it seems like there's something more subtle happening here - or I
> have misunderstood something about the fix (I'm unsure of the
> reference to xa_for_each_start; for_each_netdev_dump only calls xa_start?).
Ah! Are you on the openbmc 6.6 backport perhaps?
It look the xa_for_each_start()-implementation of netdev_for_each_dump()
would not be compatible with a direct backport of 2d20773aec14 ("mctp: no
longer rely on net->dev_index_head[]").
This was the update for the for_each_netdev_dump() macro:
commit f22b4b55edb507a2b30981e133b66b642be4d13f
Author: Jakub Kicinski <kuba@kernel.org>
Date: Thu Jun 13 14:33:16 2024 -0700
net: make for_each_netdev_dump() a little more bug-proof
I find the behavior of xa_for_each_start() slightly counter-intuitive.
It doesn't end the iteration by making the index point after the last
element. IOW calling xa_for_each_start() again after it "finished"
will run the body of the loop for the last valid element, instead
of doing nothing.
... which sounds like what's happening here.
Cheers,
Jeremy
On Sat, Jun 07, 2025 at 03:47:09PM +0800, Jeremy Kerr wrote:
> Hi Patrick,
>
> [+CC Andrew, for openbmc kernel reasons]
>
> > So, it seems like there's something more subtle happening here - or I
> > have misunderstood something about the fix (I'm unsure of the
> > reference to xa_for_each_start; for_each_netdev_dump only calls xa_start?).
>
> Ah! Are you on the openbmc 6.6 backport perhaps?
>
> It look the xa_for_each_start()-implementation of netdev_for_each_dump()
> would not be compatible with a direct backport of 2d20773aec14 ("mctp: no
> longer rely on net->dev_index_head[]").
>
> This was the update for the for_each_netdev_dump() macro:
>
> commit f22b4b55edb507a2b30981e133b66b642be4d13f
> Author: Jakub Kicinski <kuba@kernel.org>
> Date: Thu Jun 13 14:33:16 2024 -0700
>
> net: make for_each_netdev_dump() a little more bug-proof
>
> I find the behavior of xa_for_each_start() slightly counter-intuitive.
> It doesn't end the iteration by making the index point after the last
> element. IOW calling xa_for_each_start() again after it "finished"
> will run the body of the loop for the last valid element, instead
> of doing nothing.
>
> ... which sounds like what's happening here.
Ah, yep. That's exactly what is going on here. I guess this change
isn't needed for master and it looks like you've already requested a
revert for 6.6?
--
Patrick Williams
© 2016 - 2025 Red Hat, Inc.