summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_frag.c
diff options
context:
space:
mode:
authordarrenr <darrenr@FreeBSD.org>2001-04-06 15:52:28 +0000
committerdarrenr <darrenr@FreeBSD.org>2001-04-06 15:52:28 +0000
commitdf2a765614b0751ef3c56c681930608d37287e9d (patch)
tree457d60b2d1166bfc3becb8341d6226ffcfc3ca21 /sys/netinet/ip_frag.c
parent49e5408725da3218a124fe80b74ff856b0091b24 (diff)
downloadFreeBSD-src-df2a765614b0751ef3c56c681930608d37287e9d.zip
FreeBSD-src-df2a765614b0751ef3c56c681930608d37287e9d.tar.gz
fix security hole created by fragment cache
Diffstat (limited to 'sys/netinet/ip_frag.c')
-rw-r--r--sys/netinet/ip_frag.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c
index 7e1b8be..f5548fc 100644
--- a/sys/netinet/ip_frag.c
+++ b/sys/netinet/ip_frag.c
@@ -141,12 +141,15 @@ fr_info_t *fin;
u_int pass;
ipfr_t *table[];
{
- ipfr_t **fp, *fra, frag;
- u_int idx;
+ ipfr_t **fp, *fra, frag;
+ u_int idx, off;
if (ipfr_inuse >= IPFT_SIZE)
return NULL;
+ if (!(fin->fin_fi.fi_fl & FI_FRAG))
+ return NULL;
+
frag.ipfr_p = ip->ip_p;
idx = ip->ip_p;
frag.ipfr_id = ip->ip_id;
@@ -200,7 +203,10 @@ ipfr_t *table[];
/*
* Compute the offset of the expected start of the next packet.
*/
- fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3);
+ off = ip->ip_off & IP_OFFMASK;
+ if (!off)
+ fra->ipfr_seen0 = 1;
+ fra->ipfr_off = off + (fin->fin_dlen >> 3);
ATOMIC_INCL(ipfr_stats.ifs_new);
ATOMIC_INC32(ipfr_inuse);
return fra;
@@ -256,6 +262,9 @@ ipfr_t *table[];
ipfr_t *f, frag;
u_int idx;
+ if (!(fin->fin_fi.fi_fl & FI_FRAG))
+ return NULL;
+
/*
* For fragments, we record protocol, packet id, TOS and both IP#'s
* (these should all be the same for all fragments of a packet).
@@ -283,6 +292,19 @@ ipfr_t *table[];
IPFR_CMPSZ)) {
u_short atoff, off;
+ /*
+ * XXX - We really need to be guarding against the
+ * retransmission of (src,dst,id,offset-range) here
+ * because a fragmented packet is never resent with
+ * the same IP ID#.
+ */
+ off = ip->ip_off & IP_OFFMASK;
+ if (f->ipfr_seen0) {
+ if (!off || (fin->fin_fi.fi_fl & FI_SHORT))
+ continue;
+ } else if (!off)
+ f->ipfr_seen0 = 1;
+
if (f != table[idx]) {
/*
* move fragment info. to the top of the list
@@ -295,7 +317,6 @@ ipfr_t *table[];
f->ipfr_prev = NULL;
table[idx] = f;
}
- off = ip->ip_off & IP_OFFMASK;
atoff = off + (fin->fin_dlen >> 3);
/*
* If we've follwed the fragments, and this is the
OpenPOWER on IntegriCloud