diff options
author | 2017-05-28 16:55:54 +0000 | |
---|---|---|
committer | 2017-05-28 16:55:54 +0000 | |
commit | 2e5bc81177c13bd263e1fd9c62cdf5a5a1bcad28 (patch) | |
tree | da72ba3634816a6c2b20e315caff8b3bf3a84a24 | |
parent | tweak previous; (diff) | |
download | wireguard-openbsd-2e5bc81177c13bd263e1fd9c62cdf5a5a1bcad28.tar.xz wireguard-openbsd-2e5bc81177c13bd263e1fd9c62cdf5a5a1bcad28.zip |
Limit the nested header chain for IPv6 extensions headers and for
authentication headers in the IPv4 case. This prevents spending
excessive cpu time on crafted packets.
OK henning@
-rw-r--r-- | sys/net/pf.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 8961849bae0..a0f3feac155 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.1029 2017/05/28 16:43:45 bluhm Exp $ */ +/* $OpenBSD: pf.c,v 1.1030 2017/05/28 16:55:54 bluhm Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -114,6 +114,8 @@ struct pf_queuehead *pf_queues_inactive; struct pf_status pf_status; +int pf_hdr_limit = 20; /* arbitrary limit, tune in ddb */ + SHA2_CTX pf_tcp_secret_ctx; u_char pf_tcp_secret[16]; int pf_tcp_secret_init; @@ -6119,6 +6121,7 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason) { struct ip6_ext ext; u_int32_t hlen, end; + int hdr_cnt; hlen = h->ip_hl << 2; if (hlen < sizeof(struct ip) || hlen > ntohs(h->ip_len)) { @@ -6131,7 +6134,8 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason) /* stop walking over non initial fragments */ if ((h->ip_off & htons(IP_OFFMASK)) != 0) return (PF_PASS); - for (;;) { + + for (hdr_cnt = 0; hdr_cnt < pf_hdr_limit; hdr_cnt++) { switch (pd->proto) { case IPPROTO_AH: /* fragments may be short */ @@ -6150,6 +6154,9 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason) return (PF_PASS); } } + DPFPRINTF(LOG_NOTICE, "IPv4 nested authentication header limit"); + REASON_SET(reason, PFRES_IPOPTIONS); + return (PF_DROP); } #ifdef INET6 @@ -6222,14 +6229,14 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason) struct ip6_ext ext; struct ip6_rthdr rthdr; u_int32_t end; - int hdr_cnt = 0, fraghdr_cnt = 0, rthdr_cnt = 0; + int hdr_cnt, fraghdr_cnt = 0, rthdr_cnt = 0; pd->off += sizeof(struct ip6_hdr); end = pd->off + ntohs(h->ip6_plen); pd->fragoff = pd->extoff = pd->jumbolen = 0; pd->proto = h->ip6_nxt; - for (;;) { - hdr_cnt++; + + for (hdr_cnt = 0; hdr_cnt < pf_hdr_limit; hdr_cnt++) { switch (pd->proto) { case IPPROTO_FRAGMENT: if (fraghdr_cnt++) { @@ -6284,7 +6291,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason) /* FALLTHROUGH */ case IPPROTO_HOPOPTS: /* RFC2460 4.1: Hop-by-Hop only after IPv6 header */ - if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 1) { + if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 0) { DPFPRINTF(LOG_NOTICE, "IPv6 hopopts not first"); REASON_SET(reason, PFRES_IPOPTIONS); return (PF_DROP); @@ -6342,6 +6349,9 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason) return (PF_PASS); } } + DPFPRINTF(LOG_NOTICE, "IPv6 nested extension header limit"); + REASON_SET(reason, PFRES_IPOPTIONS); + return (PF_DROP); } #endif /* INET6 */ |