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

net: hsr: fix mac_len checks

Commit 2e9f60932a2c ("net: hsr: check skb can contain struct hsr_ethhdr
in fill_frame_info") added the following which resulted in -EINVAL
always being returned:
if (skb->mac_len < sizeof(struct hsr_ethhdr))
return -EINVAL;

mac_len was not being set correctly so this check completely broke
HSR/PRP since it was always 14, not 20.

Set mac_len correctly and modify the mac_len checks to test in the
correct places since sometimes it is legitimately 14.

Fixes: 2e9f60932a2c ("net: hsr: check skb can contain struct hsr_ethhdr in fill_frame_info")
Signed-off-by: George McCollister <george.mccollister@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

George McCollister and committed by
David S. Miller
48b491a5 a4dd4fc6

+34 -21
+2
net/hsr/hsr_device.c
··· 218 218 if (master) { 219 219 skb->dev = master->dev; 220 220 skb_reset_mac_header(skb); 221 + skb_reset_mac_len(skb); 221 222 hsr_forward_skb(skb, master); 222 223 } else { 223 224 atomic_long_inc(&dev->tx_dropped); ··· 260 259 goto out; 261 260 262 261 skb_reset_mac_header(skb); 262 + skb_reset_mac_len(skb); 263 263 skb_reset_network_header(skb); 264 264 skb_reset_transport_header(skb); 265 265
+21 -9
net/hsr/hsr_forward.c
··· 474 474 } 475 475 } 476 476 477 - void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb, 478 - struct hsr_frame_info *frame) 477 + int hsr_fill_frame_info(__be16 proto, struct sk_buff *skb, 478 + struct hsr_frame_info *frame) 479 479 { 480 480 struct hsr_port *port = frame->port_rcv; 481 481 struct hsr_priv *hsr = port->hsr; ··· 483 483 /* HSRv0 supervisory frames double as a tag so treat them as tagged. */ 484 484 if ((!hsr->prot_version && proto == htons(ETH_P_PRP)) || 485 485 proto == htons(ETH_P_HSR)) { 486 + /* Check if skb contains hsr_ethhdr */ 487 + if (skb->mac_len < sizeof(struct hsr_ethhdr)) 488 + return -EINVAL; 489 + 486 490 /* HSR tagged frame :- Data or Supervision */ 487 491 frame->skb_std = NULL; 488 492 frame->skb_prp = NULL; 489 493 frame->skb_hsr = skb; 490 494 frame->sequence_nr = hsr_get_skb_sequence_nr(skb); 491 - return; 495 + return 0; 492 496 } 493 497 494 498 /* Standard frame or PRP from master port */ 495 499 handle_std_frame(skb, frame); 500 + 501 + return 0; 496 502 } 497 503 498 - void prp_fill_frame_info(__be16 proto, struct sk_buff *skb, 499 - struct hsr_frame_info *frame) 504 + int prp_fill_frame_info(__be16 proto, struct sk_buff *skb, 505 + struct hsr_frame_info *frame) 500 506 { 501 507 /* Supervision frame */ 502 508 struct prp_rct *rct = skb_get_PRP_rct(skb); ··· 513 507 frame->skb_std = NULL; 514 508 frame->skb_prp = skb; 515 509 frame->sequence_nr = prp_get_skb_sequence_nr(rct); 516 - return; 510 + return 0; 517 511 } 518 512 handle_std_frame(skb, frame); 513 + 514 + return 0; 519 515 } 520 516 521 517 static int fill_frame_info(struct hsr_frame_info *frame, ··· 527 519 struct hsr_vlan_ethhdr *vlan_hdr; 528 520 struct ethhdr *ethhdr; 529 521 __be16 proto; 522 + int ret; 530 523 531 - /* Check if skb contains hsr_ethhdr */ 532 - if (skb->mac_len < sizeof(struct hsr_ethhdr)) 524 + /* Check if skb contains ethhdr */ 525 + if (skb->mac_len < sizeof(struct ethhdr)) 533 526 return -EINVAL; 534 527 535 528 memset(frame, 0, sizeof(*frame)); ··· 557 548 558 549 frame->is_from_san = false; 559 550 frame->port_rcv = port; 560 - hsr->proto_ops->fill_frame_info(proto, skb, frame); 551 + ret = hsr->proto_ops->fill_frame_info(proto, skb, frame); 552 + if (ret) 553 + return ret; 554 + 561 555 check_local_dest(port->hsr, skb, frame); 562 556 563 557 return 0;
+4 -4
net/hsr/hsr_forward.h
··· 24 24 struct hsr_port *port); 25 25 bool prp_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port); 26 26 bool hsr_drop_frame(struct hsr_frame_info *frame, struct hsr_port *port); 27 - void prp_fill_frame_info(__be16 proto, struct sk_buff *skb, 28 - struct hsr_frame_info *frame); 29 - void hsr_fill_frame_info(__be16 proto, struct sk_buff *skb, 30 - struct hsr_frame_info *frame); 27 + int prp_fill_frame_info(__be16 proto, struct sk_buff *skb, 28 + struct hsr_frame_info *frame); 29 + int hsr_fill_frame_info(__be16 proto, struct sk_buff *skb, 30 + struct hsr_frame_info *frame); 31 31 #endif /* __HSR_FORWARD_H */
+2 -2
net/hsr/hsr_main.h
··· 186 186 struct hsr_port *port); 187 187 struct sk_buff * (*create_tagged_frame)(struct hsr_frame_info *frame, 188 188 struct hsr_port *port); 189 - void (*fill_frame_info)(__be16 proto, struct sk_buff *skb, 190 - struct hsr_frame_info *frame); 189 + int (*fill_frame_info)(__be16 proto, struct sk_buff *skb, 190 + struct hsr_frame_info *frame); 191 191 bool (*invalid_dan_ingress_frame)(__be16 protocol); 192 192 void (*update_san_info)(struct hsr_node *node, bool is_sup); 193 193 };
+5 -6
net/hsr/hsr_slave.c
··· 60 60 goto finish_pass; 61 61 62 62 skb_push(skb, ETH_HLEN); 63 - 64 - if (skb_mac_header(skb) != skb->data) { 65 - WARN_ONCE(1, "%s:%d: Malformed frame at source port %s)\n", 66 - __func__, __LINE__, port->dev->name); 67 - goto finish_consume; 68 - } 63 + skb_reset_mac_header(skb); 64 + if ((!hsr->prot_version && protocol == htons(ETH_P_PRP)) || 65 + protocol == htons(ETH_P_HSR)) 66 + skb_set_network_header(skb, ETH_HLEN + HSR_HLEN); 67 + skb_reset_mac_len(skb); 69 68 70 69 hsr_forward_skb(skb, port); 71 70