Netdev List
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: sigefriedhyy@gmail.com
Cc: davem@davemloft.net, dsahern@kernel.org, donald.hunter@gmail.com,
	edumazet@google.com, idosch@nvidia.com, kuba@kernel.org,
	kuniyu@google.com, nicolas.dichtel@6wind.com,
	nickgarlis@gmail.com, pabeni@redhat.com, sd@queasysnail.net,
	shuah@kernel.org, horms@kernel.org, sdf.kernel@gmail.com,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	netdev@vger.kernel.org
Subject: Re: [PATCH net-next v2 1/3] rtnetlink: add AF_PACKET multicast dumps
Date: Thu, 10 Sep 2026 01:48:12 +0000	[thread overview]
Message-ID: <178900489222.219967.5701707176821161509@kernel.org> (raw)
In-Reply-To: <20260909013401.14408-2-sigefriedhyy@gmail.com>

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 1 (1) · Low: 2

- [Medium] rtnl_dump_mcaddr()/rtnl_dump_mcaddr_dev()
  (net/core/rtnetlink.c:4598-4623, 4655-4694) resume a multi-part…
- [Low] The commit message claims 'AF_UNSPEC keeps its "all families"
  meaning from RTM_GETADDR'.
- [Low] Concern (validated as resolved within this series): after this
  patch alone, Documentation/netlink/specs/rt-addr.yaml still described…

Pre-existing issues:
- [Medium] rtnl_fill_mcaddr() emits IFA_MULTICAST with a length read from
  dev->addr_len at dump time (net/core/rtnetlink.c:4588), while struct…

--

rtnetlink: add AF_PACKET multicast dumps

This adds a PF_PACKET RTM_GETMULTICAST dump handler that walks dev->mc and
reports each netdev_hw_addr in the existing ifaddrmsg format, so the
link-layer multicast filter no longer has to be read from
/proc/net/dev_mcast.  The handler runs unlocked with respect to RTNL, under
RCU and netif_addr_lock_bh().

A few questions below.

>     This covers every column of /proc/net/dev_mcast. AF_PACKET is the
>     family iproute2 already uses for link-layer addresses ("ip -0"), and
>     AF_UNSPEC keeps its "all families" meaning from RTM_GETADDR.

[Severity: Low]
Is the AF_UNSPEC part of this sentence accurate for RTM_GETMULTICAST?

Grepping the tree, RTM_GETMULTICAST has a dumpit registered only for
PF_INET (net/ipv4/devinet.c), PF_INET6 (net/ipv6/addrconf.c) and, with this
patch, PF_PACKET.  There is no PF_UNSPEC handler, so an AF_UNSPEC dump ends
up in the fallback in rtnetlink_rcv_msg():

	link = rtnl_get_link(family, type);
	if (!link || !link->dumpit) {
		family = PF_UNSPEC;
		link = rtnl_get_link(family, type);
		if (!link || !link->dumpit)
			goto err_unlock;

and returns -EOPNOTSUPP.

Additionally, rtnl_dump_all() explicitly skips PF_PACKET:

	if (idx < s_idx || idx == PF_PACKET)
		continue;

so even if a PF_UNSPEC RTM_GETMULTICAST handler were added later, these new
link-layer entries would not appear in an all-families dump.  Could the
changelog drop or reword that claim?

> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
> index 81c5a6104dea..b2febdb6915e 100644
> --- a/net/core/rtnetlink.c
> +++ b/net/core/rtnetlink.c
> @@ -4566,6 +4566,133 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb)
>  	return skb->len ? : ret;
>  }
>  
> +static int rtnl_fill_mcaddr(struct sk_buff *skb, const struct net_device *dev,
> +			    const struct netdev_hw_addr *ha, u32 portid,
> +			    u32 seq, unsigned int flags)
> +{
> +	struct ifaddrmsg *ifm;
> +	struct nlmsghdr *nlh;
> +
> +	nlh = nlmsg_put(skb, portid, seq, RTM_GETMULTICAST, sizeof(*ifm),
> +			flags);
> +	if (!nlh)
> +		return -EMSGSIZE;
> +
> +	ifm = nlmsg_data(nlh);
> +	ifm->ifa_family = AF_PACKET;
> +	ifm->ifa_prefixlen = 0;
> +	ifm->ifa_flags = ha->global_use ? IFA_F_PERMANENT : 0;
> +	ifm->ifa_scope = RT_SCOPE_LINK;
> +	ifm->ifa_index = dev->ifindex;
> +
> +	if (nla_put(skb, IFA_MULTICAST, dev->addr_len, ha->addr) ||

[Severity: Medium]
This isn't a bug introduced by this patch, but can this copy expose
uninitialized bytes from ha->addr?

The length comes from dev->addr_len as read at dump time, while the entry
was filled in at insertion time by __hw_addr_create() in
net/core/dev_addr_lists.c:

	ha = kmalloc(alloc_size, GFP_ATOMIC);
	if (!ha)
		return NULL;
	memcpy(ha->addr, addr, addr_len);

The allocation is not zeroed and only addr_len bytes of
ha->addr[MAX_ADDR_LEN] are written.

If dev->addr_len grows after the entry was created, the tail is
uninitialized heap.  One such path is tun's TUNSETLINK, which does:

	tun->dev->type = (int) arg;
	tun->dev->addr_len = tun_get_addr_len(tun->dev->type);

without flushing dev->mc, so a 6-byte entry added with SIOCADDMULTI while
the device was ARPHRD_ETHER would later be dumped as 16 bytes.

The same disclosure already exists through the world-readable
/proc/net/dev_mcast, where dev_mc_seq_show() prints with (int)dev->addr_len
over the same buffer, so this is not new here.  Would it make sense to
bound the copy (min_t(unsigned int, dev->addr_len, MAX_ADDR_LEN)) and/or
zero the allocation in __hw_addr_create()?

[Severity: Low]
With this patch alone, Documentation/netlink/specs/rt-addr.yaml still
describes operation getmulticast as:

      name: getmulticast
      doc: Get / dump IPv4/IPv6 multicast addresses.

while this reply carries a link-layer IFA_MULTICAST of dev->addr_len bytes,
no IFA_CACHEINFO, ifa_scope of RT_SCOPE_LINK and IFA_F_PERMANENT with a
different meaning.  The following patch in the series, "netlink: specs:
rt-addr: document AF_PACKET multicast dumps", updates that doc, so the
divergence only exists at this point in the series and needs no action.

> +	    nla_put_u32(skb, IFA_MC_USERS, ha->refcount)) {
> +		nlmsg_cancel(skb, nlh);
> +		return -EMSGSIZE;
> +	}
> +
> +	nlmsg_end(skb, nlh);
> +	return 0;
> +}
> +
> +static int rtnl_dump_mcaddr_dev(struct net_device *dev, struct sk_buff *skb,
> +				struct netlink_callback *cb, int *s_addr_idx,
> +				unsigned int flags)
> +{
> +	struct netdev_hw_addr *ha;
> +	int addr_idx = 0;
> +	int err = 0;
> +
> +	netif_addr_lock_bh(dev);
> +	netdev_for_each_mc_addr(ha, dev) {
> +		if (addr_idx < *s_addr_idx) {
> +			addr_idx++;
> +			continue;
> +		}
> +		err = rtnl_fill_mcaddr(skb, dev, ha, NETLINK_CB(cb->skb).portid,
> +				       cb->nlh->nlmsg_seq, flags);
> +		if (err < 0)
> +			break;
> +		addr_idx++;
> +	}
> +	netif_addr_unlock_bh(dev);
> +
> +	*s_addr_idx = err < 0 ? addr_idx : 0;

[Severity: Medium]
Can this positional resume cursor silently skip dev->mc entries?

Resume state is the ordinal position in the list, and both
netif_addr_lock_bh() and rcu_read_lock() are dropped before the callback
returns, so between netlink dump rounds a writer can unlink an entry that
sits before the saved index:

net/core/dev_addr_lists.c:__hw_addr_del_entry() {
	...
	list_del_rcu(&ha->list);
	kfree_rcu(ha, rcu_head);
	list->count--;
	...
}

Writers reaching that only need netif_addr_lock_bh() (dev_mc_del() from an
IGMP/MLD leave, SIOCDELMULTI, driver or bonding rx_mode churn), and RTNL
holders are free to run as well since the handler is registered with
RTNL_FLAG_DUMP_UNLOCKED.  Removing N entries ahead of the saved addr_idx
shifts the survivors down and drops N entries that were never reported;
device add/remove similarly shifts the for_each_netdev_dump() cursor.

Neither cb->seq nor nl_dump_check_consistent() is used here, so
NLM_F_DUMP_INTR can never be set and user space sees a truncated dump that
looks complete.

The sibling handler for the same message type does maintain that:

net/ipv4/devinet.c:inet_dump_addr() {
	...
	cb->seq = inet_base_seq(tgt_net);
	...
}

net/ipv4/devinet.c:in_dev_dump_ifmcaddr() {
	...
		nl_dump_check_consistent(cb, nlmsg_hdr(skb));
	...
}

Would setting cb->seq from a generation counter and calling
nl_dump_check_consistent() in rtnl_dump_mcaddr_dev() be appropriate here
too?

> +
> +	return err;
> +}
> +

[ ... ]

> +static int rtnl_dump_mcaddr(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	struct net *net = sock_net(skb->sk);
> +	unsigned int flags = NLM_F_MULTI;
> +	struct {
> +		unsigned long ifindex;
> +		int addr_idx;
> +	} *ctx = (void *)cb->ctx;

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260909013401.14408-1-sigefriedhyy%40gmail.com

  parent reply	other threads:[~2026-09-10  1:48 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-09  1:33 [PATCH net-next v2 0/3] rtnetlink: dump link-layer multicast addresses Yuyang Huang
2026-09-09  1:33 ` [PATCH net-next v2 1/3] rtnetlink: add AF_PACKET multicast dumps Yuyang Huang
2026-09-09  8:44   ` Nicolas Dichtel
2026-09-09 11:15     ` Yuyang Huang
2026-09-10  1:48   ` netdev-bot+sashiko [this message]
2026-09-10  3:21     ` Yuyang Huang
2026-09-09  1:34 ` [PATCH net-next v2 2/3] netlink: specs: rt-addr: document " Yuyang Huang
2026-09-10  1:48   ` netdev-bot+sashiko
2026-09-10  3:29     ` Yuyang Huang
2026-09-09  1:34 ` [PATCH net-next v2 3/3] selftests: net: test " Yuyang Huang
2026-09-10  1:48   ` netdev-bot+sashiko
2026-09-10  3:31     ` Yuyang Huang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178900489222.219967.5701707176821161509@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=davem@davemloft.net \
    --cc=donald.hunter@gmail.com \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=idosch@nvidia.com \
    --cc=kuba@kernel.org \
    --cc=kuniyu@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=nickgarlis@gmail.com \
    --cc=nicolas.dichtel@6wind.com \
    --cc=pabeni@redhat.com \
    --cc=sd@queasysnail.net \
    --cc=sdf.kernel@gmail.com \
    --cc=shuah@kernel.org \
    --cc=sigefriedhyy@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox