mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-12 09:58:36 +00:00
fix security hole created by fragment cache
This commit is contained in:
parent
207ef320ab
commit
454a43c1f1
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=75262
@ -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
|
||||
|
@ -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;
|
||||
|
@ -2283,7 +2283,8 @@ fr_info_t *fin;
|
||||
*/
|
||||
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 @@ fr_info_t *fin;
|
||||
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))) {
|
||||
|
@ -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 {
|
||||
|
@ -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 @@ fr_info_t *fin;
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user