Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bridge-vxlan-harden-nd-option-parsing-paths'

Yang Yang says:

====================
bridge/vxlan: harden ND option parsing paths

This series hardens ND option parsing in bridge and vxlan paths.

Patch 1 linearizes the request skb in br_nd_send() before walking ND
options. Patch 2 adds explicit ND option length validation in
br_nd_send(). Patch 3 adds matching ND option length validation in
vxlan_na_create().
====================

Link: https://patch.msgid.link/20260326034441.2037420-1-n05ec@lzu.edu.cn
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+15 -9
+4 -2
drivers/net/vxlan/vxlan_core.c
··· 1965 1965 ns_olen = request->len - skb_network_offset(request) - 1966 1966 sizeof(struct ipv6hdr) - sizeof(*ns); 1967 1967 for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) { 1968 - if (!ns->opt[i + 1]) { 1968 + if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) { 1969 1969 kfree_skb(reply); 1970 1970 return NULL; 1971 1971 } 1972 1972 if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) { 1973 - daddr = ns->opt + i + sizeof(struct nd_opt_hdr); 1973 + if ((ns->opt[i + 1] << 3) >= 1974 + sizeof(struct nd_opt_hdr) + ETH_ALEN) 1975 + daddr = ns->opt + i + sizeof(struct nd_opt_hdr); 1974 1976 break; 1975 1977 } 1976 1978 }
+11 -7
net/bridge/br_arp_nd_proxy.c
··· 251 251 252 252 static void br_nd_send(struct net_bridge *br, struct net_bridge_port *p, 253 253 struct sk_buff *request, struct neighbour *n, 254 - __be16 vlan_proto, u16 vlan_tci, struct nd_msg *ns) 254 + __be16 vlan_proto, u16 vlan_tci) 255 255 { 256 256 struct net_device *dev = request->dev; 257 257 struct net_bridge_vlan_group *vg; 258 + struct nd_msg *na, *ns; 258 259 struct sk_buff *reply; 259 - struct nd_msg *na; 260 260 struct ipv6hdr *pip6; 261 261 int na_olen = 8; /* opt hdr + ETH_ALEN for target */ 262 262 int ns_olen; ··· 264 264 u8 *daddr; 265 265 u16 pvid; 266 266 267 - if (!dev) 267 + if (!dev || skb_linearize(request)) 268 268 return; 269 269 270 270 len = LL_RESERVED_SPACE(dev) + sizeof(struct ipv6hdr) + ··· 281 281 skb_set_mac_header(reply, 0); 282 282 283 283 daddr = eth_hdr(request)->h_source; 284 + ns = (struct nd_msg *)(skb_network_header(request) + 285 + sizeof(struct ipv6hdr)); 284 286 285 287 /* Do we need option processing ? */ 286 288 ns_olen = request->len - (skb_network_offset(request) + 287 289 sizeof(struct ipv6hdr)) - sizeof(*ns); 288 290 for (i = 0; i < ns_olen - 1; i += (ns->opt[i + 1] << 3)) { 289 - if (!ns->opt[i + 1]) { 291 + if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) { 290 292 kfree_skb(reply); 291 293 return; 292 294 } 293 295 if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) { 294 - daddr = ns->opt + i + sizeof(struct nd_opt_hdr); 296 + if ((ns->opt[i + 1] << 3) >= 297 + sizeof(struct nd_opt_hdr) + ETH_ALEN) 298 + daddr = ns->opt + i + sizeof(struct nd_opt_hdr); 295 299 break; 296 300 } 297 301 } ··· 476 472 if (vid != 0) 477 473 br_nd_send(br, p, skb, n, 478 474 skb->vlan_proto, 479 - skb_vlan_tag_get(skb), msg); 475 + skb_vlan_tag_get(skb)); 480 476 else 481 - br_nd_send(br, p, skb, n, 0, 0, msg); 477 + br_nd_send(br, p, skb, n, 0, 0); 482 478 replied = true; 483 479 } 484 480