summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbluhm <bluhm@openbsd.org>2017-05-28 16:55:54 +0000
committerbluhm <bluhm@openbsd.org>2017-05-28 16:55:54 +0000
commit2e5bc81177c13bd263e1fd9c62cdf5a5a1bcad28 (patch)
treeda72ba3634816a6c2b20e315caff8b3bf3a84a24
parenttweak previous; (diff)
downloadwireguard-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.c22
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 */