fix fragment cache security hole

This commit is contained in:
darrenr 2001-04-06 15:32:40 +00:00
parent ec984a04ad
commit 0b6031033d
5 changed files with 44 additions and 18 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_frag.c,v 1.22 2001/03/26 06:13:13 mike Exp $ */
/* $NetBSD: ip_frag.c,v 1.23 2001/04/06 15:32:40 darrenr Exp $ */
/*
* Copyright (C) 1993-2000 by Darren Reed.
@ -9,7 +9,7 @@
*/
#if !defined(lint)
#if defined(__NetBSD__)
static const char rcsid[] = "$NetBSD: ip_frag.c,v 1.22 2001/03/26 06:13:13 mike Exp $";
static const char rcsid[] = "$NetBSD: ip_frag.c,v 1.23 2001/04/06 15:32:40 darrenr Exp $";
#else
static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.10.2.7 2000/11/27 10:26:56 darrenr Exp";
@ -147,12 +147,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;
@ -206,7 +209,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;
@ -262,6 +268,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).
@ -289,6 +298,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
@ -301,7 +323,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

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_frag.h,v 1.15 2001/03/26 06:13:13 mike Exp $ */
/* $NetBSD: ip_frag.h,v 1.16 2001/04/06 15:32:40 darrenr Exp $ */
/*
* Copyright (C) 1993-2000 by Darren Reed.
@ -26,7 +26,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;
@ -42,7 +43,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;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_nat.c,v 1.38 2001/03/26 06:13:13 mike Exp $ */
/* $NetBSD: ip_nat.c,v 1.39 2001/04/06 15:32:41 darrenr Exp $ */
/*
* Copyright (C) 1995-2000 by Darren Reed.
@ -11,7 +11,7 @@
*/
#if !defined(lint)
#if defined(__NetBSD__)
static const char rcsid[] = "$NetBSD: ip_nat.c,v 1.38 2001/03/26 06:13:13 mike Exp $";
static const char rcsid[] = "$NetBSD: ip_nat.c,v 1.39 2001/04/06 15:32:41 darrenr Exp $";
#else
static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
static const char rcsid[] = "@(#)Id: ip_nat.c,v 2.37.2.32 2001/01/10 06:19:11 darrenr Exp";
@ -2282,7 +2282,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;
@ -2487,7 +2488,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))) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_nat.h,v 1.22 2001/03/26 06:13:13 mike Exp $ */
/* $NetBSD: ip_nat.h,v 1.23 2001/04/06 15:32:41 darrenr Exp $ */
/*
* Copyright (C) 1995-2000 by Darren Reed.
@ -228,6 +228,7 @@ typedef struct natstat {
#define IPN_ROUNDR 0x100
#define IPN_NOTSRC 0x080000
#define IPN_NOTDST 0x100000
#define IPN_FRAG 0x200000
typedef struct natlog {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_state.c,v 1.29 2001/03/26 06:13:14 mike Exp $ */
/* $NetBSD: ip_state.c,v 1.30 2001/04/06 15:32:41 darrenr Exp $ */
/*
* Copyright (C) 1995-2000 by Darren Reed.
@ -9,7 +9,7 @@
*/
#if !defined(lint)
#if defined(__NetBSD__)
static const char rcsid[] = "$NetBSD: ip_state.c,v 1.29 2001/03/26 06:13:14 mike Exp $";
static const char rcsid[] = "$NetBSD: ip_state.c,v 1.30 2001/04/06 15:32:41 darrenr Exp $";
#else
static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
static const char rcsid[] = "@(#)Id: ip_state.c,v 2.30.2.28 2001/01/08 14:04:46 darrenr Exp";
@ -690,7 +690,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;
}
@ -1347,7 +1347,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;
}