diff options
author | Eric Dumazet <edumazet@google.com> | 2016-11-28 09:26:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-11-29 20:37:26 -0500 |
commit | 648f0c28df282636c0c8a7a19ca3ce5fc80a39c3 (patch) | |
tree | 21a521e1c65060e4ef3060e122915134c29aa931 /net | |
parent | ffac0e967f20b7637936dbaa21df08c55f672604 (diff) |
net/dccp: fix use-after-free in dccp_invalid_packet
pskb_may_pull() can reallocate skb->head, we need to reload dh pointer
in dccp_invalid_packet() or risk use after free.
Bug found by Andrey Konovalov using syzkaller.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Andrey Konovalov <andreyknvl@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/ipv4.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b567c8725aea..edbe59d203ef 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -700,6 +700,7 @@ int dccp_invalid_packet(struct sk_buff *skb) | |||
700 | { | 700 | { |
701 | const struct dccp_hdr *dh; | 701 | const struct dccp_hdr *dh; |
702 | unsigned int cscov; | 702 | unsigned int cscov; |
703 | u8 dccph_doff; | ||
703 | 704 | ||
704 | if (skb->pkt_type != PACKET_HOST) | 705 | if (skb->pkt_type != PACKET_HOST) |
705 | return 1; | 706 | return 1; |
@@ -721,18 +722,19 @@ int dccp_invalid_packet(struct sk_buff *skb) | |||
721 | /* | 722 | /* |
722 | * If P.Data Offset is too small for packet type, drop packet and return | 723 | * If P.Data Offset is too small for packet type, drop packet and return |
723 | */ | 724 | */ |
724 | if (dh->dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { | 725 | dccph_doff = dh->dccph_doff; |
725 | DCCP_WARN("P.Data Offset(%u) too small\n", dh->dccph_doff); | 726 | if (dccph_doff < dccp_hdr_len(skb) / sizeof(u32)) { |
727 | DCCP_WARN("P.Data Offset(%u) too small\n", dccph_doff); | ||
726 | return 1; | 728 | return 1; |
727 | } | 729 | } |
728 | /* | 730 | /* |
729 | * If P.Data Offset is too too large for packet, drop packet and return | 731 | * If P.Data Offset is too too large for packet, drop packet and return |
730 | */ | 732 | */ |
731 | if (!pskb_may_pull(skb, dh->dccph_doff * sizeof(u32))) { | 733 | if (!pskb_may_pull(skb, dccph_doff * sizeof(u32))) { |
732 | DCCP_WARN("P.Data Offset(%u) too large\n", dh->dccph_doff); | 734 | DCCP_WARN("P.Data Offset(%u) too large\n", dccph_doff); |
733 | return 1; | 735 | return 1; |
734 | } | 736 | } |
735 | 737 | dh = dccp_hdr(skb); | |
736 | /* | 738 | /* |
737 | * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet | 739 | * If P.type is not Data, Ack, or DataAck and P.X == 0 (the packet |
738 | * has short sequence numbers), drop packet and return | 740 | * has short sequence numbers), drop packet and return |