FireWire (IEEE 1394) subsystem fixes:
- 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. -----BEGIN PGP SIGNATURE----- iQI3BAABCAAhBQJYHgSgGhxzdGVmYW5yQHM1cjYuaW4tYmVybGluLmRlAAoJEHnz b7JUXXnQFGIP/AvXrsLFgO8vOZd967145Jz0FydmwRBsX1F90xugFIxJI8kRQSN4 MQ/WHPaHl55LqX88VrxDTfN04TAtb243CDPXDnMN6rEzaSY4O7J6JO/zaUKMGyaW rocX3s3uufIqk/GXDk2+I0Ze6xHynbWEPaoDh0rHYkJcD0NHHi9SJPFZf8RnCx3g s7GAiU5V9o1SZydY9dCGo66Zl3JSujOsxpbVllT2ux+FWRReea5+O9ntWpPcW+E0 Elc9v7Nt3BcOEDXrVYg8UIIX6RCt8IBDCaF6D7n8JrhU/ag+OH8+KondktU5P+BI MXcsm92UbM+/739RC7V6JbDSodUn1DisoOTyNmH58ZZerKWWt+7E27WXWuRu9ch7 rBra6pcOhkhO9sHkrwf3DlP9nubAfVbznVxZFOI4O96fnpn284J0RX8brsMOeHcF iPAIpGc5PLyvyhczZSfokKj9S4kUvbwhNwCnHs32ttdrGSHRIVFKHsipsFFtcts2 K7QAN9mxWtBeP8i3gd5tJO8FT7tvg4Ixtt/BzpsFpxaYk9b/k2RnrSt4b4/0mC2q fQ6urSQalvffmbU9eMm78NbaFV26s217gZHqqD++tAVLLgkwRaC2k/MucOJJz4xb 5PYoGLDfCusReBP/MYdpqOhAUEBeeZ03IQT7gaGGDQ27x8k1UIpB57Sk =PxAL -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
03daa36f08
@ -73,13 +73,13 @@ struct rfc2734_header {
|
||||
|
||||
#define fwnet_get_hdr_lf(h) (((h)->w0 & 0xc0000000) >> 30)
|
||||
#define fwnet_get_hdr_ether_type(h) (((h)->w0 & 0x0000ffff))
|
||||
#define fwnet_get_hdr_dg_size(h) (((h)->w0 & 0x0fff0000) >> 16)
|
||||
#define fwnet_get_hdr_dg_size(h) ((((h)->w0 & 0x0fff0000) >> 16) + 1)
|
||||
#define fwnet_get_hdr_fg_off(h) (((h)->w0 & 0x00000fff))
|
||||
#define fwnet_get_hdr_dgl(h) (((h)->w1 & 0xffff0000) >> 16)
|
||||
|
||||
#define fwnet_set_hdr_lf(lf) ((lf) << 30)
|
||||
#define fwnet_set_hdr_lf(lf) ((lf) << 30)
|
||||
#define fwnet_set_hdr_ether_type(et) (et)
|
||||
#define fwnet_set_hdr_dg_size(dgs) ((dgs) << 16)
|
||||
#define fwnet_set_hdr_dg_size(dgs) (((dgs) - 1) << 16)
|
||||
#define fwnet_set_hdr_fg_off(fgo) (fgo)
|
||||
|
||||
#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,
|
||||
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(&hdr);
|
||||
if (lf == RFC2374_HDR_UNFRAG) {
|
||||
@ -602,7 +605,12 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
|
||||
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;
|
||||
@ -614,7 +622,10 @@ static int fwnet_incoming_packet(struct fwnet_device *dev, __be32 *buf, int len,
|
||||
fg_off = fwnet_get_hdr_fg_off(&hdr);
|
||||
}
|
||||
datagram_label = fwnet_get_hdr_dgl(&hdr);
|
||||
dg_size = fwnet_get_hdr_dg_size(&hdr); /* ??? + 1 */
|
||||
dg_size = fwnet_get_hdr_dg_size(&hdr);
|
||||
|
||||
if (fg_off + len > dg_size)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
@ -722,6 +733,22 @@ static void fwnet_receive_packet(struct fw_card *card, struct fw_request *r,
|
||||
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]) & 0xffff) << 8 |
|
||||
(be32_to_cpu(p[1]) & 0xff000000) >> 24;
|
||||
}
|
||||
|
||||
static u32 gasp_version(__be32 *p)
|
||||
{
|
||||
return be32_to_cpu(p[1]) & 0xffffff;
|
||||
}
|
||||
|
||||
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(struct fw_iso_context *context,
|
||||
__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(struct fw_iso_context *context,
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
specifier_id = (be32_to_cpu(buf_ptr[0]) & 0xffff) << 8
|
||||
| (be32_to_cpu(buf_ptr[1]) & 0xff000000) >> 24;
|
||||
ver = be32_to_cpu(buf_ptr[1]) & 0xffffff;
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user