[PATCH net v5 1/1] ipmr: only copy pktinfo to cache reports
flat view
COOLING6d
SUPERSEDED
From: Zhiling Zou <hidden>
Date: 2026-10-17 05:40:15
Subsystem:
networking [general], networking [ipv4/ipv6], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, David Ahern, Ido Schimmel, Linus Torvalds
Revision v5 of 3 in this series.
Revisions (3)
- v4 [diff vs current]
- v5 current
- v6 [diff vs current]
ipmr_cache_report() prepares IP_PKTINFO on the original skb. The
ipv4_pktinfo_prepare() helper updates skb->cb and clears the pktinfo fields
when packet info is disabled. Since the skb can continue through the data
path, preserve and restore its original control block around the helper.
The original implementation copies the entire control block to the report
skb. For synthetic RTM_GETROUTE packets, NETLINK_CB data is interpreted as
IPCB by the raw IPv4 receive path. With IP_RECVOPTS or IP_RETOPTS enabled,
corrupted option offsets cause out-of-bounds reads or a stack buffer
overflow. WHOLEPKT and WRVIFWHOLE reports also inherit stale IP option
offsets when their header is prepended.
Clear the report skb control block and copy only the pktinfo fields
prepared by ipv4_pktinfo_prepare(). Doing this after both report branches
preserves the input skb metadata and clears inherited IP options.
Fixes: bb7403655b3c ("ipmr: support IP_PKTINFO on cache report IGMP msg")
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <redacted>
Link: https://lore.kernel.org/netdev/20260903113055.GA90787@shredder/ (local)
Suggested-by: Ido Schimmel <idosch@nvidia.com>
Assisted-by: LLM
Signed-off-by: Zhiling Zou <redacted>
---
changes in v5:
- Save and restore pkt->cb around ipv4_pktinfo_prepare().
- Prepare pktinfo after both report branches, clear skb->cb, and copy only
the pktinfo fields; this also clears inherited IP options.
- Add the Fixes tag for the older WHOLEPKT/WRVIFWHOLE issue.
- v4 Link: https://lore.kernel.org/netdev/d8a36c317f6216d20f9cfd7e49f1888f62c35f7c.1788417128.git.zhilinz@nebusec.ai/ (local)
changes in v4:
- Clear IPCB(skb)->opt when prepending the 20-byte WHOLEPKT/WRVIFWHOLE
header, so stale option offsets are not inherited from the original packet.
- v3 Link: https://lore.kernel.org/all/e93d0d2fa5725ddd06b20e3e4223ab68b93b48d1.1785719031.git.zhilinz@nebusec.ai/ (local)
changes in v3:
- Go back to the v1 scope and stop changing the common path.
- Remove memset(), since alloc_skb() already clears the control block.
- v2 Link: https://lore.kernel.org/all/1b809975e5bd9c0a1dd6fdd1db534e701fe5a4b6.1785379072.git.zhilinz@nebusec.ai/ (local)
changes in v2:
- Reword the commit message to say the entire 48-byte skb control block
is copied.
- Mention that IP_RECVOPTS/IP_RETOPTS on the mrouted socket was unintended.
- Move the pktinfo copy to the common path to cover both report branches.
- v1 Link: https://lore.kernel.org/all/5bc7cd71c2d671b305f25497d88ae8a0aa663c08.1784894076.git.zhilinz@nebusec.ai/ (local)
net/ipv4/ipmr.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index b9c544d48c45..ef0d73e45b70 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c@@ -1057,6 +1057,7 @@ static void ipmr_cache_resolve(struct net *net, struct mr_table *mrt, static int ipmr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt, vifi_t vifi, int assert) { + unsigned char pkt_cb[sizeof(pkt->cb)]; const int ihl = ip_hdrlen(pkt); struct sock *mroute_sk; struct igmphdr *igmp;
@@ -1112,8 +1113,6 @@ static int ipmr_cache_report(const struct mr_table *mrt, msg = (struct igmpmsg *)skb_network_header(skb); msg->im_vif = vifi; msg->im_vif_hi = vifi >> 8; - ipv4_pktinfo_prepare(mroute_sk, pkt, false); - memcpy(skb->cb, pkt->cb, sizeof(skb->cb)); /* Add our header. * Note that code, csum and group fields are cleared. */
@@ -1124,6 +1123,12 @@ static int ipmr_cache_report(const struct mr_table *mrt, skb->transport_header = skb->network_header; } + memcpy(pkt_cb, pkt->cb, sizeof(pkt_cb)); + ipv4_pktinfo_prepare(mroute_sk, pkt, false); + memset(skb->cb, 0, sizeof(skb->cb)); + *PKTINFO_SKB_CB(skb) = *PKTINFO_SKB_CB(pkt); + memcpy(pkt->cb, pkt_cb, sizeof(pkt_cb)); + igmpmsg_netlink_event(mrt, skb); /* Deliver to mrouted */
--
2.55.0