summaryrefslogtreecommitdiffstats
path: root/sys/contrib
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/contrib
parent49e5408725da3218a124fe80b74ff856b0091b24 (diff)
downloadFreeBSD-src-df2a765614b0751ef3c56c681930608d37287e9d.zip
FreeBSD-src-df2a765614b0751ef3c56c681930608d37287e9d.tar.gz
fix security hole created by fragment cache
Diffstat (limited to 'sys/contrib')
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.c29
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.h6
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat.c6
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat.h1
-rw-r--r--sys/contrib/ipfilter/netinet/ip_state.c4
5 files changed, 36 insertions, 10 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c
index 7e1b8be..f5548fc 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.c
+++ b/sys/contrib/ipfilter/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
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h
index 92e3e23..2d0b9be 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.h
+++ b/sys/contrib/ipfilter/netinet/ip_frag.h
@@ -25,7 +25,8 @@ typedef struct ipfr {
u_char ipfr_p;
u_char ipfr_tos;
u_short ipfr_off;
- u_short ipfr_ttl;
+ u_char ipfr_ttl;
+ u_char ipfr_seen0;
frentry_t *ipfr_rule;
} ipfr_t;
@@ -41,7 +42,8 @@ typedef struct ipfrstat {
struct ipfr **ifs_nattab;
} ipfrstat_t;
-#define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1)
+#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_off) - \
+ offsetof(ipfr_t, ipfr_src))
extern int fr_ipfrttl;
extern int fr_frag_lock;
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c
index 6daafb6..816d8e7 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.c
+++ b/sys/contrib/ipfilter/netinet/ip_nat.c
@@ -2283,7 +2283,8 @@ maskloop:
*/
if (nat) {
np = nat->nat_ptr;
- if (natadd && fin->fin_fi.fi_fl & FI_FRAG)
+ if (natadd && (fin->fin_fi.fi_fl & FI_FRAG) &&
+ np && (np->in_flags & IPN_FRAG))
ipfr_nat_newfrag(ip, fin, 0, nat);
MUTEX_ENTER(&nat->nat_lock);
nat->nat_age = fr_defnatage;
@@ -2488,7 +2489,8 @@ maskloop:
if (nat) {
np = nat->nat_ptr;
fin->fin_fr = nat->nat_fr;
- if (natadd && fin->fin_fi.fi_fl & FI_FRAG)
+ if (natadd && (fin->fin_fi.fi_fl & FI_FRAG) &&
+ np && (np->in_flags & IPN_FRAG))
ipfr_nat_newfrag(ip, fin, 0, nat);
if ((np->in_apr != NULL) && (np->in_dport == 0 ||
(tcp != NULL && sport == np->in_dport))) {
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h
index 374a20b..afa7e14 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.h
+++ b/sys/contrib/ipfilter/netinet/ip_nat.h
@@ -227,6 +227,7 @@ typedef struct natstat {
#define IPN_ROUNDR 0x100
#define IPN_NOTSRC 0x080000
#define IPN_NOTDST 0x100000
+#define IPN_FRAG 0x200000
typedef struct natlog {
diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c
index c051c9e..8cfe62d 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.c
+++ b/sys/contrib/ipfilter/netinet/ip_state.c
@@ -688,7 +688,7 @@ u_int flags;
#endif
RWLOCK_EXIT(&ipf_state);
fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst);
- if (fin->fin_fi.fi_fl & FI_FRAG)
+ if ((fin->fin_fi.fi_fl & FI_FRAG) && (pass & FR_KEEPFRAG))
ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);
return is;
}
@@ -1345,7 +1345,7 @@ retry_tcpudp:
fr_delstate(is);
#endif
RWLOCK_EXIT(&ipf_state);
- if (fin->fin_fi.fi_fl & FI_FRAG)
+ if ((fin->fin_fi.fi_fl & FI_FRAG) && (pass & FR_KEEPFRAG))
ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE);
return fr;
}
OpenPOWER on IntegriCloud