diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2016-11-17 13:17:33 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2016-11-17 13:17:33 +0000 |
commit | 9eb3c57197fbc8fe5b811335782ab02226f498fb (patch) | |
tree | 178d549f5c3d98645de91f0fb98eb94868e2f3d7 /sys | |
parent | 349160d834fb53059253a80a923d945eb4b0afb3 (diff) |
The pf fragment reassembly code accepted IPv6 hop-by-hop headers
after fragment headers. Add an extra check that the hop-by-hop
header is always the first extension header after the IPv6 header.
Found by Antonios Atlasis; OK sthen@ mpi@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/pf.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 7406c95c873..b8e2a6fb7bf 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.998 2016/11/14 13:25:00 bluhm Exp $ */ +/* $OpenBSD: pf.c,v 1.999 2016/11/17 13:17:32 bluhm Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -6207,13 +6207,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 fraghdr_cnt = 0, rthdr_cnt = 0; + int hdr_cnt = 0, 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++; switch (pd->proto) { case IPPROTO_FRAGMENT: if (fraghdr_cnt++) { @@ -6266,8 +6267,15 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason) return (PF_DROP); } /* FALLTHROUGH */ - case IPPROTO_AH: case IPPROTO_HOPOPTS: + /* RFC2460 4.1: Hop-by-Hop only after IPv6 header */ + if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 1) { + DPFPRINTF(LOG_NOTICE, "IPv6 hopopts not first"); + REASON_SET(reason, PFRES_IPOPTIONS); + return (PF_DROP); + } + /* FALLTHROUGH */ + case IPPROTO_AH: case IPPROTO_DSTOPTS: /* fragments may be short */ if (pd->fragoff != 0 && end < pd->off + sizeof(ext)) { |