Skip to content

Commit 03daa36

Browse files
committed
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
2 parents d8d1721 + e9300a4 commit 03daa36

File tree

1 file changed

+39
-20
lines changed

1 file changed

+39
-20
lines changed

drivers/firewire/net.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ struct rfc2734_header {
7373

7474
#define fwnet_get_hdr_lf(h) (((h)->w0 & 0xc0000000) >> 30)
7575
#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)
7777
#define fwnet_get_hdr_fg_off(h) (((h)->w0 & 0x00000fff))
7878
#define fwnet_get_hdr_dgl(h) (((h)->w1 & 0xffff0000) >> 16)
7979

80-
#define fwnet_set_hdr_lf(lf) ((lf) << 30)
80+
#define fwnet_set_hdr_lf(lf) ((lf) << 30)
8181
#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)
8383
#define fwnet_set_hdr_fg_off(fgo) (fgo)
8484

8585
#define fwnet_set_hdr_dgl(dgl) ((dgl) << 16)
@@ -578,6 +578,9 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
578578
int retval;
579579
u16 ether_type;
580580

581+
if (len <= RFC2374_UNFRAG_HDR_SIZE)
582+
return 0;
583+
581584
hdr.w0 = be32_to_cpu(buf[0]);
582585
lf = fwnet_get_hdr_lf(&hdr);
583586
if (lf == RFC2374_HDR_UNFRAG) {
@@ -602,7 +605,12 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
602605
return fwnet_finish_incoming_packet(net, skb, source_node_id,
603606
is_broadcast, ether_type);
604607
}
608+
605609
/* A datagram fragment has been received, now the fun begins. */
610+
611+
if (len <= RFC2374_FRAG_HDR_SIZE)
612+
return 0;
613+
606614
hdr.w1 = ntohl(buf[1]);
607615
buf += 2;
608616
len -= RFC2374_FRAG_HDR_SIZE;
@@ -614,7 +622,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
614622
fg_off = fwnet_get_hdr_fg_off(&hdr);
615623
}
616624
datagram_label = fwnet_get_hdr_dgl(&hdr);
617-
dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
625+
dg_size = fwnet_get_hdr_dg_size(&hdr);
626+
627+
if (fg_off + len > dg_size)
628+
return 0;
618629

619630
spin_lock_irqsave(&dev->lock, flags);
620631

@@ -722,6 +733,22 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
722733
fw_send_response(card, r, rcode);
723734
}
724735

736+
static int gasp_source_id(__be32 *p)
737+
{
738+
return be32_to_cpu(p[0]) >> 16;
739+
}
740+
741+
static u32 gasp_specifier_id(__be32 *p)
742+
{
743+
return (be32_to_cpu(p[0]) & 0xffff) << 8 |
744+
(be32_to_cpu(p[1]) & 0xff000000) >> 24;
745+
}
746+
747+
static u32 gasp_version(__be32 *p)
748+
{
749+
return be32_to_cpu(p[1]) & 0xffffff;
750+
}
751+
725752
static void fwnet_receive_broadcast(struct fw_iso_context *context,
726753
u32 cycle, size_t header_length, void *header, void *data)
727754
{
@@ -731,9 +758,6 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
731758
__be32 *buf_ptr;
732759
int retval;
733760
u32 length;
734-
u16 source_node_id;
735-
u32 specifier_id;
736-
u32 ver;
737761
unsigned long offset;
738762
unsigned long flags;
739763

@@ -750,22 +774,17 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
750774

751775
spin_unlock_irqrestore(&dev->lock, flags);
752776

753-
specifier_id = (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8
754-
| (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24;
755-
ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
756-
source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
757-
758-
if (specifier_id == IANA_SPECIFIER_ID &&
759-
(ver == RFC2734_SW_VERSION
777+
if (length > IEEE1394_GASP_HDR_SIZE &&
778+
gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID &&
779+
(gasp_version(buf_ptr) == RFC2734_SW_VERSION
760780
#if IS_ENABLED(CONFIG_IPV6)
761-
|| ver == RFC3146_SW_VERSION
781+
|| gasp_version(buf_ptr) == RFC3146_SW_VERSION
762782
#endif
763-
)) {
764-
buf_ptr += 2;
765-
length -= IEEE1394_GASP_HDR_SIZE;
766-
fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
783+
))
784+
fwnet_incoming_packet(dev, buf_ptr + 2,
785+
length - IEEE1394_GASP_HDR_SIZE,
786+
gasp_source_id(buf_ptr),
767787
context->card->generation, true);
768-
}
769788

770789
packet.payload_length = dev->rcv_buffer_size;
771790
packet.interrupt = 1;

0 commit comments

Comments
 (0)