Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/net/npf Declare NPC_FMTERR, and use it to kick malformed...
details: https://anonhg.NetBSD.org/src/rev/772b2faa1190
branches: trunk
changeset: 360375:772b2faa1190
user: maxv <maxv%NetBSD.org@localhost>
date: Thu Mar 08 07:06:13 2018 +0000
description:
Declare NPC_FMTERR, and use it to kick malformed packets. Several sanity
checks are added in IPv6; after we see the first IPPROTO_FRAGMENT header,
we are allowed to fail to advance, otherwise we kick the packet.
Sent on tech-net@ a few days ago, no response, but I'm committing it now
anyway.
diffstat:
sys/net/npf/npf.h | 4 ++-
sys/net/npf/npf_handler.c | 17 ++++++++++---
sys/net/npf/npf_inet.c | 59 +++++++++++++++++++++++++++++++++++-----------
3 files changed, 60 insertions(+), 20 deletions(-)
diffs (213 lines):
diff -r bddbd2488e29 -r 772b2faa1190 sys/net/npf/npf.h
--- a/sys/net/npf/npf.h Thu Mar 08 06:48:23 2018 +0000
+++ b/sys/net/npf/npf.h Thu Mar 08 07:06:13 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: npf.h,v 1.55 2017/12/15 21:00:26 maxv Exp $ */
+/* $NetBSD: npf.h,v 1.56 2018/03/08 07:06:13 maxv Exp $ */
/*-
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -143,6 +143,8 @@
#define NPC_ALG_EXEC 0x100 /* ALG execution. */
+#define NPC_FMTERR 0x200 /* Format error. */
+
#define NPC_IP46 (NPC_IP4|NPC_IP6)
typedef struct {
diff -r bddbd2488e29 -r 772b2faa1190 sys/net/npf/npf_handler.c
--- a/sys/net/npf/npf_handler.c Thu Mar 08 06:48:23 2018 +0000
+++ b/sys/net/npf/npf_handler.c Thu Mar 08 07:06:13 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_handler.c,v 1.37 2017/02/19 20:27:22 christos Exp $ */
+/* $NetBSD: npf_handler.c,v 1.38 2018/03/08 07:06:13 maxv Exp $ */
/*-
* Copyright (c) 2009-2013 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.37 2017/02/19 20:27:22 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.38 2018/03/08 07:06:13 maxv Exp $");
#include <sys/types.h>
#include <sys/param.h>
@@ -109,7 +109,7 @@
nbuf_init(npf, nbuf, *mp, nbuf->nb_ifp);
npc->npc_info = 0;
- if (npf_cache_all(npc) & NPC_IPFRAG) {
+ if (npf_cache_all(npc) & (NPC_IPFRAG|NPC_FMTERR)) {
return EINVAL;
}
npf_stats_inc(npf, NPF_STAT_REASSEMBLY);
@@ -154,8 +154,16 @@
error = 0;
rp = NULL;
- /* Cache everything. Determine whether it is an IP fragment. */
+ /* Cache everything. */
flags = npf_cache_all(&npc);
+
+ /* If error on the format, leave quickly. */
+ if (flags & NPC_FMTERR) {
+ error = EINVAL;
+ goto fastout;
+ }
+
+ /* Determine whether it is an IP fragment. */
if (__predict_false(flags & NPC_IPFRAG)) {
/*
* We pass IPv6 fragments unconditionally
@@ -308,6 +316,7 @@
error = ENETUNREACH;
}
+fastout:
if (*mp) {
/* Free the mbuf chain. */
m_freem(*mp);
diff -r bddbd2488e29 -r 772b2faa1190 sys/net/npf/npf_inet.c
--- a/sys/net/npf/npf_inet.c Thu Mar 08 06:48:23 2018 +0000
+++ b/sys/net/npf/npf_inet.c Thu Mar 08 07:06:13 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: npf_inet.c,v 1.37 2017/02/19 20:27:22 christos Exp $ */
+/* $NetBSD: npf_inet.c,v 1.38 2018/03/08 07:06:13 maxv Exp $ */
/*-
* Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
@@ -40,7 +40,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.37 2017/02/19 20:27:22 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_inet.c,v 1.38 2018/03/08 07:06:13 maxv Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -328,12 +328,12 @@
ip = nbuf_ensure_contig(nbuf, sizeof(struct ip));
if (ip == NULL) {
- return 0;
+ return NPC_FMTERR;
}
/* Check header length and fragment offset. */
if ((u_int)(ip->ip_hl << 2) < sizeof(struct ip)) {
- return 0;
+ return NPC_FMTERR;
}
if (ip->ip_off & ~htons(IP_DF | IP_RF)) {
/* Note fragmentation. */
@@ -357,10 +357,14 @@
struct ip6_ext *ip6e;
struct ip6_frag *ip6f;
size_t off, hlen;
+ int frag_present;
+ bool is_frag;
+ uint8_t onxt;
+ int fragoff;
ip6 = nbuf_ensure_contig(nbuf, sizeof(struct ip6_hdr));
if (ip6 == NULL) {
- return 0;
+ return NPC_FMTERR;
}
/* Set initial next-protocol value. */
@@ -368,16 +372,14 @@
npc->npc_proto = ip6->ip6_nxt;
npc->npc_hlen = hlen;
+ frag_present = 0;
+ is_frag = false;
+
/*
* Advance by the length of the current header.
*/
off = nbuf_offset(nbuf);
- while (nbuf_advance(nbuf, hlen, 0) != NULL) {
- ip6e = nbuf_ensure_contig(nbuf, sizeof(*ip6e));
- if (ip6e == NULL) {
- return 0;
- }
-
+ while ((ip6e = nbuf_advance(nbuf, hlen, sizeof(*ip6e))) != NULL) {
/*
* Determine whether we are going to continue.
*/
@@ -388,9 +390,23 @@
hlen = (ip6e->ip6e_len + 1) << 3;
break;
case IPPROTO_FRAGMENT:
+ if (frag_present++)
+ return NPC_FMTERR;
ip6f = nbuf_ensure_contig(nbuf, sizeof(*ip6f));
if (ip6f == NULL)
- return 0;
+ return NPC_FMTERR;
+
+ hlen = sizeof(struct ip6_frag);
+
+ /* RFC6946: Skip dummy fragments. */
+ fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
+ if (fragoff == 0 &&
+ !(ip6f->ip6f_offlg & IP6F_MORE_FRAG)) {
+ break;
+ }
+
+ is_frag = true;
+
/*
* We treat the first fragment as a regular
* packet and then we pass the rest of the
@@ -399,10 +415,9 @@
* be able to reassembled, if not they will
* be ignored. We can do better later.
*/
- if (ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK) != 0)
+ if (fragoff != 0)
flags |= NPC_IPFRAG;
- hlen = sizeof(struct ip6_frag);
break;
case IPPROTO_AH:
hlen = (ip6e->ip6e_len + 2) << 2;
@@ -415,11 +430,24 @@
if (!hlen) {
break;
}
+ onxt = npc->npc_proto;
npc->npc_proto = ip6e->ip6e_nxt;
npc->npc_hlen += hlen;
}
/*
+ * We failed to advance. If we are not a fragment, that's
+ * a format error and we leave. Otherwise, restore npc_hlen
+ * and npc_proto to their previous (and correct) values.
+ */
+ if (ip6e == NULL) {
+ if (!is_frag)
+ return NPC_FMTERR;
+ npc->npc_proto = onxt;
+ npc->npc_hlen -= hlen;
+ }
+
+ /*
* Re-fetch the header pointers (nbufs might have been
* reallocated). Restore the original offset (if any).
*/
@@ -469,7 +497,8 @@
* fragmented, then we cannot look into L4.
*/
flags = npf_cache_ip(npc, nbuf);
- if ((flags & NPC_IP46) == 0 || (flags & NPC_IPFRAG) != 0) {
+ if ((flags & NPC_IP46) == 0 || (flags & NPC_IPFRAG) != 0 ||
+ (flags & NPC_FMTERR) != 0) {
nbuf_unset_flag(nbuf, NBUF_DATAREF_RESET);
npc->npc_info |= flags;
return flags;
Home |
Main Index |
Thread Index |
Old Index