diff options
author | darrenr <darrenr@FreeBSD.org> | 2001-04-06 15:52:28 +0000 |
---|---|---|
committer | darrenr <darrenr@FreeBSD.org> | 2001-04-06 15:52:28 +0000 |
commit | df2a765614b0751ef3c56c681930608d37287e9d (patch) | |
tree | 457d60b2d1166bfc3becb8341d6226ffcfc3ca21 /sys/contrib/ipfilter | |
parent | 49e5408725da3218a124fe80b74ff856b0091b24 (diff) | |
download | FreeBSD-src-df2a765614b0751ef3c56c681930608d37287e9d.zip FreeBSD-src-df2a765614b0751ef3c56c681930608d37287e9d.tar.gz |
fix security hole created by fragment cache
Diffstat (limited to 'sys/contrib/ipfilter')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_frag.c | 29 | ||||
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_frag.h | 6 | ||||
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_nat.c | 6 | ||||
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_nat.h | 1 | ||||
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_state.c | 4 |
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; } |