[PATCH 1/3] firewire: net: guard against rx buffer overflows

2016-11-02 Thread Stefan Richter
Date: Sat, 29 Oct 2016 21:28:18 +0200

The IP-over-1394 driver firewire-net lacked input validation when
handling incoming fragmented datagrams.  A maliciously formed fragment
with a respectively large datagram_offset would cause a memcpy past the
datagram buffer.

So, drop any packets carrying a fragment with offset + length larger
than datagram_size.

In addition, ensure that
  - GASP header, unfragmented encapsulation header, or fragment
encapsulation header actually exists before we access it,
  - the encapsulated datagram or fragment is of nonzero size.

Reported-by: Eyal Itkin 
Cc: sta...@vger.kernel.org
Signed-off-by: Stefan Richter 
---
 drivers/firewire/net.c |   51 -
 1 file changed, 35 insertions(+), 16 deletions(-)

--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -578,6 +578,9 @@ static int fwnet_incoming_packet(struct
int retval;
u16 ether_type;
 
+   if (len <= RFC2374_UNFRAG_HDR_SIZE)
+   return 0;
+
hdr.w0 = be32_to_cpu(buf[0]);
lf = fwnet_get_hdr_lf();
if (lf == RFC2374_HDR_UNFRAG) {
@@ -602,7 +605,12 @@ static int fwnet_incoming_packet(struct
return fwnet_finish_incoming_packet(net, skb, source_node_id,
is_broadcast, ether_type);
}
+
/* A datagram fragment has been received, now the fun begins. */
+
+   if (len <= RFC2374_FRAG_HDR_SIZE)
+   return 0;
+
hdr.w1 = ntohl(buf[1]);
buf += 2;
len -= RFC2374_FRAG_HDR_SIZE;
@@ -616,6 +624,9 @@ static int fwnet_incoming_packet(struct
datagram_label = fwnet_get_hdr_dgl();
dg_size = fwnet_get_hdr_dg_size(); /* ??? + 1 */
 
+   if (fg_off + len > dg_size)
+   return 0;
+
spin_lock_irqsave(>lock, flags);
 
peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation);
@@ -722,6 +733,22 @@ static void fwnet_receive_packet(struct
fw_send_response(card, r, rcode);
 }
 
+static int gasp_source_id(__be32 *p)
+{
+   return be32_to_cpu(p[0]) >> 16;
+}
+
+static u32 gasp_specifier_id(__be32 *p)
+{
+   return (be32_to_cpu(p[0]) & 0x) << 8 |
+  (be32_to_cpu(p[1]) & 0xff00) >> 24;
+}
+
+static u32 gasp_version(__be32 *p)
+{
+   return be32_to_cpu(p[1]) & 0xff;
+}
+
 static void fwnet_receive_broadcast(struct fw_iso_context *context,
u32 cycle, size_t header_length, void *header, void *data)
 {
@@ -731,9 +758,6 @@ static void fwnet_receive_broadcast(stru
__be32 *buf_ptr;
int retval;
u32 length;
-   u16 source_node_id;
-   u32 specifier_id;
-   u32 ver;
unsigned long offset;
unsigned long flags;
 
@@ -750,22 +774,17 @@ static void fwnet_receive_broadcast(stru
 
spin_unlock_irqrestore(>lock, flags);
 
-   specifier_id =(be32_to_cpu(buf_ptr[0]) & 0x) << 8
-   | (be32_to_cpu(buf_ptr[1]) & 0xff00) >> 24;
-   ver = be32_to_cpu(buf_ptr[1]) & 0xff;
-   source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
-
-   if (specifier_id == IANA_SPECIFIER_ID &&
-   (ver == RFC2734_SW_VERSION
+   if (length > IEEE1394_GASP_HDR_SIZE &&
+   gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID &&
+   (gasp_version(buf_ptr) == RFC2734_SW_VERSION
 #if IS_ENABLED(CONFIG_IPV6)
-|| ver == RFC3146_SW_VERSION
+|| gasp_version(buf_ptr) == RFC3146_SW_VERSION
 #endif
-   )) {
-   buf_ptr += 2;
-   length -= IEEE1394_GASP_HDR_SIZE;
-   fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
+   ))
+   fwnet_incoming_packet(dev, buf_ptr + 2,
+ length - IEEE1394_GASP_HDR_SIZE,
+ gasp_source_id(buf_ptr),
  context->card->generation, true);
-   }
 
packet.payload_length = dev->rcv_buffer_size;
packet.interrupt = 1;


-- 
Stefan Richter
-==- =-== ---=-
http://arcgraph.de/sr/


[PATCH 1/3] firewire: net: guard against rx buffer overflows

2016-11-02 Thread Stefan Richter
Date: Sat, 29 Oct 2016 21:28:18 +0200

The IP-over-1394 driver firewire-net lacked input validation when
handling incoming fragmented datagrams.  A maliciously formed fragment
with a respectively large datagram_offset would cause a memcpy past the
datagram buffer.

So, drop any packets carrying a fragment with offset + length larger
than datagram_size.

In addition, ensure that
  - GASP header, unfragmented encapsulation header, or fragment
encapsulation header actually exists before we access it,
  - the encapsulated datagram or fragment is of nonzero size.

Reported-by: Eyal Itkin 
Cc: sta...@vger.kernel.org
Signed-off-by: Stefan Richter 
---
 drivers/firewire/net.c |   51 -
 1 file changed, 35 insertions(+), 16 deletions(-)

--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -578,6 +578,9 @@ static int fwnet_incoming_packet(struct
int retval;
u16 ether_type;
 
+   if (len <= RFC2374_UNFRAG_HDR_SIZE)
+   return 0;
+
hdr.w0 = be32_to_cpu(buf[0]);
lf = fwnet_get_hdr_lf();
if (lf == RFC2374_HDR_UNFRAG) {
@@ -602,7 +605,12 @@ static int fwnet_incoming_packet(struct
return fwnet_finish_incoming_packet(net, skb, source_node_id,
is_broadcast, ether_type);
}
+
/* A datagram fragment has been received, now the fun begins. */
+
+   if (len <= RFC2374_FRAG_HDR_SIZE)
+   return 0;
+
hdr.w1 = ntohl(buf[1]);
buf += 2;
len -= RFC2374_FRAG_HDR_SIZE;
@@ -616,6 +624,9 @@ static int fwnet_incoming_packet(struct
datagram_label = fwnet_get_hdr_dgl();
dg_size = fwnet_get_hdr_dg_size(); /* ??? + 1 */
 
+   if (fg_off + len > dg_size)
+   return 0;
+
spin_lock_irqsave(>lock, flags);
 
peer = fwnet_peer_find_by_node_id(dev, source_node_id, generation);
@@ -722,6 +733,22 @@ static void fwnet_receive_packet(struct
fw_send_response(card, r, rcode);
 }
 
+static int gasp_source_id(__be32 *p)
+{
+   return be32_to_cpu(p[0]) >> 16;
+}
+
+static u32 gasp_specifier_id(__be32 *p)
+{
+   return (be32_to_cpu(p[0]) & 0x) << 8 |
+  (be32_to_cpu(p[1]) & 0xff00) >> 24;
+}
+
+static u32 gasp_version(__be32 *p)
+{
+   return be32_to_cpu(p[1]) & 0xff;
+}
+
 static void fwnet_receive_broadcast(struct fw_iso_context *context,
u32 cycle, size_t header_length, void *header, void *data)
 {
@@ -731,9 +758,6 @@ static void fwnet_receive_broadcast(stru
__be32 *buf_ptr;
int retval;
u32 length;
-   u16 source_node_id;
-   u32 specifier_id;
-   u32 ver;
unsigned long offset;
unsigned long flags;
 
@@ -750,22 +774,17 @@ static void fwnet_receive_broadcast(stru
 
spin_unlock_irqrestore(>lock, flags);
 
-   specifier_id =(be32_to_cpu(buf_ptr[0]) & 0x) << 8
-   | (be32_to_cpu(buf_ptr[1]) & 0xff00) >> 24;
-   ver = be32_to_cpu(buf_ptr[1]) & 0xff;
-   source_node_id = be32_to_cpu(buf_ptr[0]) >> 16;
-
-   if (specifier_id == IANA_SPECIFIER_ID &&
-   (ver == RFC2734_SW_VERSION
+   if (length > IEEE1394_GASP_HDR_SIZE &&
+   gasp_specifier_id(buf_ptr) == IANA_SPECIFIER_ID &&
+   (gasp_version(buf_ptr) == RFC2734_SW_VERSION
 #if IS_ENABLED(CONFIG_IPV6)
-|| ver == RFC3146_SW_VERSION
+|| gasp_version(buf_ptr) == RFC3146_SW_VERSION
 #endif
-   )) {
-   buf_ptr += 2;
-   length -= IEEE1394_GASP_HDR_SIZE;
-   fwnet_incoming_packet(dev, buf_ptr, length, source_node_id,
+   ))
+   fwnet_incoming_packet(dev, buf_ptr + 2,
+ length - IEEE1394_GASP_HDR_SIZE,
+ gasp_source_id(buf_ptr),
  context->card->generation, true);
-   }
 
packet.payload_length = dev->rcv_buffer_size;
packet.interrupt = 1;


-- 
Stefan Richter
-==- =-== ---=-
http://arcgraph.de/sr/