Currently, any UDP-encapsulated packet of 8 bytes or less will be
passed to userspace, whether it starts with the non-ESP prefix or
not (except keepalives). This includes:
 - messages of 1, 2, 3 bytes
 - messages of 4 to 8 bytes not starting with 00 00 00 00

This patch changes that behavior, so that only properly-formed non-ESP
messages are passed to userspace. Messages of 8 bytes or less that
don't contain a full non-ESP prefix followed by some data (at least
one byte) will be dropped and counted as XfrmInHdrError.

Signed-off-by: Sabrina Dubroca <s...@queasysnail.net>
---
 net/ipv4/xfrm4_input.c | 9 +++++++--
 net/ipv6/xfrm6_input.c | 9 +++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index ad2afeef4f10..2a2bb38ac798 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -114,9 +114,14 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff 
*skb)
                } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 
0) {
                        /* ESP Packet without Non-ESP header */
                        len = sizeof(struct udphdr);
-               } else
-                       /* Must be an IKE packet.. pass it through */
+               } else if (len > 4 && udpdata32[0] == 0) {
+                       /* IKE packet: pass it through */
                        return 1;
+               } else {
+                       /* incomplete packet, drop */
+                       XFRM_INC_STATS(dev_net(skb->dev), 
LINUX_MIB_XFRMINHDRERROR);
+                       goto drop;
+               }
                break;
        case UDP_ENCAP_ESPINUDP_NON_IKE:
                /* Check if this is a keepalive packet.  If so, eat it. */
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 04cbeefd8982..7e14d59d55cb 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -110,9 +110,14 @@ int xfrm6_udp_encap_rcv(struct sock *sk, struct sk_buff 
*skb)
                } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 
0) {
                        /* ESP Packet without Non-ESP header */
                        len = sizeof(struct udphdr);
-               } else
-                       /* Must be an IKE packet.. pass it through */
+               } else if (len > 4 && udpdata32[0] == 0) {
+                       /* IKE packet: pass it through */
                        return 1;
+               } else {
+                       /* incomplete packet, drop */
+                       XFRM_INC_STATS(dev_net(skb->dev), 
LINUX_MIB_XFRMINHDRERROR);
+                       goto drop;
+               }
                break;
        case UDP_ENCAP_ESPINUDP_NON_IKE:
                /* Check if this is a keepalive packet.  If so, eat it. */
-- 
2.27.0

Reply via email to