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 tag 'firewire-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394

Pull FireWire (IEEE 1394) fixes from Stefan Richter:

- add missing input validation to the firewire-net driver. Invalid
IP-over-1394 encapsulation headers could trigger buffer overflows
(CVE 2016-8633).

- IP-over-1394 link fragmentation headers were read and written
incorrectly, breaking fragmented RX/TX with other OS's stacks.

* tag 'firewire-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394:
firewire: net: fix fragmented datagram_size off-by-one
firewire: net: guard against rx buffer overflows

+39 -20
+39 -20
drivers/firewire/net.c
··· 73 73 74 74 #define fwnet_get_hdr_lf(h) (((h)->w0 & 0xc0000000) >> 30) 75 75 #define fwnet_get_hdr_ether_type(h) (((h)->w0 & 0x0000ffff)) 76 - #define fwnet_get_hdr_dg_size(h) (((h)->w0 & 0x0fff0000) >> 16) 76 + #define fwnet_get_hdr_dg_size(h) ((((h)->w0 & 0x0fff0000) >> 16) + 1) 77 77 #define fwnet_get_hdr_fg_off(h) (((h)->w0 & 0x00000fff)) 78 78 #define fwnet_get_hdr_dgl(h) (((h)->w1 & 0xffff0000) >> 16) 79 79 80 - #define fwnet_set_hdr_lf(lf) ((lf) << 30) 80 + #define fwnet_set_hdr_lf(lf) ((lf) << 30) 81 81 #define fwnet_set_hdr_ether_type(et) (et) 82 - #define fwnet_set_hdr_dg_size(dgs) ((dgs) << 16) 82 + #define fwnet_set_hdr_dg_size(dgs) (((dgs) - 1) << 16) 83 83 #define fwnet_set_hdr_fg_off(fgo) (fgo) 84 84 85 85 #define fwnet_set_hdr_dgl(dgl) ((dgl) << 16) ··· 578 578 int retval; 579 579 u16 ether_type; 580 580 581 + if (len <= RFC2374_UNFRAG_HDR_SIZE) 582 + return 0; 583 + 581 584 hdr.w0 = be32_to_cpu(buf[0]); 582 585 lf = fwnet_get_hdr_lf(&hdr); 583 586 if (lf == RFC2374_HDR_UNFRAG) { ··· 605 602 return fwnet_finish_incoming_packet(net, skb, source_node_id, 606 603 is_broadcast, ether_type); 607 604 } 605 + 608 606 /* A datagram fragment has been received, now the fun begins. */ 607 + 608 + if (len <= RFC2374_FRAG_HDR_SIZE) 609 + return 0; 610 + 609 611 hdr.w1 = ntohl(buf[1]); 610 612 buf += 2; 611 613 len -= RFC2374_FRAG_HDR_SIZE; ··· 622 614 fg_off = fwnet_get_hdr_fg_off(&hdr); 623 615 } 624 616 datagram_label = fwnet_get_hdr_dgl(&hdr); 625 - dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */ 617 + dg_size = fwnet_get_hdr_dg_size(&hdr); 618 + 619 + if (fg_off + len > dg_size) 620 + return 0; 626 621 627 622 spin_lock_irqsave(&dev->lock, flags); 628 623 ··· 733 722 fw_send_response(card, r, rcode); 734 723 } 735 724 725 + static int gasp_source_id(__be32 *p) 726 + { 727 + return be32_to_cpu(p[0]) >> 16; 728 + } 729 + 730 + static u32 gasp_specifier_id(__be32 *p) 731 + { 732 + return (be32_to_cpu(p[0]) & 0xffff) << 8 | 733 + (be32_to_cpu(p[1]) & 0xff000000) >> 24; 734 + } 735 + 736 + static u32 gasp_version(__be32 *p) 737 + { 738 + return be32_to_cpu(p[1]) & 0xffffff; 739 + } 740 + 736 741 static void fwnet_receive_broadcast(struct fw_iso_context *context, 737 742 u32 cycle, size_t header_length, void *header, void *data) 738 743 { ··· 758 731 __be32 *buf_ptr; 759 732 int retval; 760 733 u32 length; 761 - u16 source_node_id; 762 - u32 specifier_id; 763 - u32 ver; 764 734 unsigned long offset; 765 735 unsigned long flags; 766 736 ··· 774 750 775 751 spin_unlock_irqrestore(&dev->lock, flags); 776 752 777 - specifier_id = (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8 778 - | (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24; 779 - ver = be32_to_cpu(buf_ptr[1]) & 0xffffff; 780 - source_node_id = be32_to_cpu(buf_ptr[0]) >> 16; 781 - 782 - if (specifier_id == IANA_SPECIFIER_ID && 783 - (ver == RFC2734_SW_VERSION 753 + if (length > IEEE1394_GASP_HDR_SIZE && 754 + gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID && 755 + (gasp_version(buf_ptr) == RFC2734_SW_VERSION 784 756 #if IS_ENABLED(CONFIG_IPV6) 785 - || ver == RFC3146_SW_VERSION 757 + || gasp_version(buf_ptr) == RFC3146_SW_VERSION 786 758 #endif 787 - )) { 788 - buf_ptr += 2; 789 - length -= IEEE1394_GASP_HDR_SIZE; 790 - fwnet_incoming_packet(dev, buf_ptr, length, source_node_id, 759 + )) 760 + fwnet_incoming_packet(dev, buf_ptr + 2, 761 + length - IEEE1394_GASP_HDR_SIZE, 762 + gasp_source_id(buf_ptr), 791 763 context->card->generation, true); 792 - } 793 764 794 765 packet.payload_length = dev->rcv_buffer_size; 795 766 packet.interrupt = 1;