- implement lock around IPv6 reassembly, to avoid panic due to
frag6_drain (mutex version will come later). - limit number of fragments (not fragment queues) in kernel. Obtained from: KAME
This commit is contained in:
parent
1ab976cb03
commit
9888c40195
@ -68,12 +68,51 @@ static void frag6_insque __P((struct ip6q *, struct ip6q *));
|
||||
static void frag6_remque __P((struct ip6q *));
|
||||
static void frag6_freef __P((struct ip6q *));
|
||||
|
||||
/* XXX we eventually need splreass6, or some real semaphore */
|
||||
int frag6_doing_reass;
|
||||
static int ip6q_locked;
|
||||
u_int frag6_nfragpackets;
|
||||
u_int frag6_nfrags;
|
||||
struct ip6q ip6q; /* ip6 reassemble queue */
|
||||
|
||||
/* FreeBSD tweak */
|
||||
static __inline int ip6q_lock_try __P((void));
|
||||
static __inline void ip6q_unlock __P((void));
|
||||
|
||||
static __inline int
|
||||
ip6q_lock_try()
|
||||
{
|
||||
if (ip6q_locked)
|
||||
return (0);
|
||||
ip6q_locked = 1;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ip6q_unlock()
|
||||
{
|
||||
ip6q_locked = 0;
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
#define IP6Q_LOCK() \
|
||||
do { \
|
||||
if (ip6q_lock_try() == 0) { \
|
||||
printf("%s:%d: ip6q already locked\n", __FILE__, __LINE__); \
|
||||
panic("ip6q_lock"); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
#define IP6Q_LOCK_CHECK() \
|
||||
do { \
|
||||
if (ip6q_locked == 0) { \
|
||||
printf("%s:%d: ip6q lock not held\n", __FILE__, __LINE__); \
|
||||
panic("ip6q lock check"); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
#else
|
||||
#define IP6Q_LOCK() (void) ip6q_lock_try()
|
||||
#define IP6Q_LOCK_CHECK() /* nothing */
|
||||
#endif
|
||||
|
||||
#define IP6Q_UNLOCK() ip6q_unlock()
|
||||
|
||||
static MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header");
|
||||
|
||||
/*
|
||||
@ -84,6 +123,7 @@ frag6_init()
|
||||
{
|
||||
|
||||
ip6_maxfragpackets = nmbclusters / 4;
|
||||
ip6_maxfrags = nmbclusters / 4;
|
||||
|
||||
#ifndef RANDOM_IP_ID
|
||||
ip6_id = arc4random();
|
||||
@ -204,7 +244,17 @@ frag6_input(mp, offp, proto)
|
||||
/* offset now points to data portion */
|
||||
offset += sizeof(struct ip6_frag);
|
||||
|
||||
frag6_doing_reass = 1;
|
||||
IP6Q_LOCK();
|
||||
|
||||
/*
|
||||
* Enforce upper bound on number of fragments.
|
||||
* If maxfrag is 0, never accept fragments.
|
||||
* If maxfrag is -1, accept all fragments without limitation.
|
||||
*/
|
||||
if (ip6_maxfrags < 0)
|
||||
;
|
||||
else if (frag6_nfrags >= (u_int)ip6_maxfrags)
|
||||
goto dropfrag;
|
||||
|
||||
for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
|
||||
if (ip6f->ip6f_ident == q6->ip6q_ident &&
|
||||
@ -221,8 +271,9 @@ frag6_input(mp, offp, proto)
|
||||
/*
|
||||
* Enforce upper bound on number of fragmented packets
|
||||
* for which we attempt reassembly;
|
||||
* If maxfrag is 0, never accept fragments.
|
||||
* If maxfrag is -1, accept all fragments without limitation.
|
||||
* If maxfragpackets is 0, never accept fragments.
|
||||
* If maxfragpackets is -1, accept all fragments without
|
||||
* limitation.
|
||||
*/
|
||||
if (ip6_maxfragpackets < 0)
|
||||
;
|
||||
@ -248,6 +299,8 @@ frag6_input(mp, offp, proto)
|
||||
q6->ip6q_src = ip6->ip6_src;
|
||||
q6->ip6q_dst = ip6->ip6_dst;
|
||||
q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
|
||||
|
||||
q6->ip6q_nfrag = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -273,14 +326,14 @@ frag6_input(mp, offp, proto)
|
||||
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
|
||||
offset - sizeof(struct ip6_frag) +
|
||||
offsetof(struct ip6_frag, ip6f_offlg));
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
} else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
|
||||
icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
|
||||
offset - sizeof(struct ip6_frag) +
|
||||
offsetof(struct ip6_frag, ip6f_offlg));
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
/*
|
||||
@ -388,6 +441,8 @@ frag6_input(mp, offp, proto)
|
||||
* If the incoming framgent overlaps some existing fragments in
|
||||
* the reassembly queue, drop it, since it is dangerous to override
|
||||
* existing fragments from a security point of view.
|
||||
* We don't know which fragment is the bad guy - here we trust
|
||||
* fragment that came in earlier, with no real reason.
|
||||
*/
|
||||
if (af6->ip6af_up != (struct ip6asfrag *)q6) {
|
||||
i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
|
||||
@ -425,6 +480,8 @@ insert:
|
||||
* the most recently active fragmented packet.
|
||||
*/
|
||||
frag6_enq(ip6af, af6->ip6af_up);
|
||||
frag6_nfrags++;
|
||||
q6->ip6q_nfrag++;
|
||||
#if 0 /* xxx */
|
||||
if (q6 != ip6q.ip6q_next) {
|
||||
frag6_remque(q6);
|
||||
@ -435,13 +492,13 @@ insert:
|
||||
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
|
||||
af6 = af6->ip6af_down) {
|
||||
if (af6->ip6af_off != next) {
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
next += af6->ip6af_frglen;
|
||||
}
|
||||
if (af6->ip6af_up->ip6af_mff) {
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
|
||||
@ -487,6 +544,7 @@ insert:
|
||||
/* this comes with no copy if the boundary is on cluster */
|
||||
if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
|
||||
frag6_remque(q6);
|
||||
frag6_nfrags -= q6->ip6q_nfrag;
|
||||
free(q6, M_FTABLE);
|
||||
frag6_nfragpackets--;
|
||||
goto dropfrag;
|
||||
@ -504,6 +562,7 @@ insert:
|
||||
}
|
||||
|
||||
frag6_remque(q6);
|
||||
frag6_nfrags -= q6->ip6q_nfrag;
|
||||
free(q6, M_FTABLE);
|
||||
frag6_nfragpackets--;
|
||||
|
||||
@ -524,14 +583,14 @@ insert:
|
||||
*mp = m;
|
||||
*offp = offset;
|
||||
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
return nxt;
|
||||
|
||||
dropfrag:
|
||||
in6_ifstat_inc(dstifp, ifs6_reass_fail);
|
||||
ip6stat.ip6s_fragdropped++;
|
||||
m_freem(m);
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
return IPPROTO_DONE;
|
||||
}
|
||||
|
||||
@ -545,6 +604,8 @@ frag6_freef(q6)
|
||||
{
|
||||
struct ip6asfrag *af6, *down6;
|
||||
|
||||
IP6Q_LOCK_CHECK();
|
||||
|
||||
for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
|
||||
af6 = down6) {
|
||||
struct mbuf *m = IP6_REASS_MBUF(af6);
|
||||
@ -573,6 +634,7 @@ frag6_freef(q6)
|
||||
free(af6, M_FTABLE);
|
||||
}
|
||||
frag6_remque(q6);
|
||||
frag6_nfrags -= q6->ip6q_nfrag;
|
||||
free(q6, M_FTABLE);
|
||||
frag6_nfragpackets--;
|
||||
}
|
||||
@ -585,6 +647,9 @@ void
|
||||
frag6_enq(af6, up6)
|
||||
struct ip6asfrag *af6, *up6;
|
||||
{
|
||||
|
||||
IP6Q_LOCK_CHECK();
|
||||
|
||||
af6->ip6af_up = up6;
|
||||
af6->ip6af_down = up6->ip6af_down;
|
||||
up6->ip6af_down->ip6af_up = af6;
|
||||
@ -598,6 +663,9 @@ void
|
||||
frag6_deq(af6)
|
||||
struct ip6asfrag *af6;
|
||||
{
|
||||
|
||||
IP6Q_LOCK_CHECK();
|
||||
|
||||
af6->ip6af_up->ip6af_down = af6->ip6af_down;
|
||||
af6->ip6af_down->ip6af_up = af6->ip6af_up;
|
||||
}
|
||||
@ -606,6 +674,9 @@ void
|
||||
frag6_insque(new, old)
|
||||
struct ip6q *new, *old;
|
||||
{
|
||||
|
||||
IP6Q_LOCK_CHECK();
|
||||
|
||||
new->ip6q_prev = old;
|
||||
new->ip6q_next = old->ip6q_next;
|
||||
old->ip6q_next->ip6q_prev= new;
|
||||
@ -616,6 +687,9 @@ void
|
||||
frag6_remque(p6)
|
||||
struct ip6q *p6;
|
||||
{
|
||||
|
||||
IP6Q_LOCK_CHECK();
|
||||
|
||||
p6->ip6q_prev->ip6q_next = p6->ip6q_next;
|
||||
p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
|
||||
}
|
||||
@ -631,7 +705,7 @@ frag6_slowtimo()
|
||||
struct ip6q *q6;
|
||||
int s = splnet();
|
||||
|
||||
frag6_doing_reass = 1;
|
||||
IP6Q_LOCK();
|
||||
q6 = ip6q.ip6q_next;
|
||||
if (q6)
|
||||
while (q6 != &ip6q) {
|
||||
@ -654,7 +728,7 @@ frag6_slowtimo()
|
||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
|
||||
frag6_freef(ip6q.ip6q_prev);
|
||||
}
|
||||
frag6_doing_reass = 0;
|
||||
IP6Q_UNLOCK();
|
||||
|
||||
#if 0
|
||||
/*
|
||||
@ -681,11 +755,13 @@ frag6_slowtimo()
|
||||
void
|
||||
frag6_drain()
|
||||
{
|
||||
if (frag6_doing_reass)
|
||||
|
||||
if (ip6q_lock_try() == 0)
|
||||
return;
|
||||
while (ip6q.ip6q_next != &ip6q) {
|
||||
ip6stat.ip6s_fragdropped++;
|
||||
/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
|
||||
frag6_freef(ip6q.ip6q_next);
|
||||
}
|
||||
IP6Q_UNLOCK();
|
||||
}
|
||||
|
@ -539,9 +539,11 @@ struct in6_pktinfo {
|
||||
#define IPV6CTL_AUTO_LINKLOCAL 35 /* automatic link-local addr assign */
|
||||
#define IPV6CTL_RIP6STATS 36 /* raw_ip6 stats */
|
||||
|
||||
#define IPV6CTL_MAXFRAGS 41 /* max fragments */
|
||||
|
||||
/* New entries should be added here from current IPV6CTL_MAXID value. */
|
||||
/* to define items, should talk with KAME guys first, for *BSD compatibility */
|
||||
#define IPV6CTL_MAXID 37
|
||||
#define IPV6CTL_MAXID 42
|
||||
|
||||
/*
|
||||
* Redefinition of mbuf flags
|
||||
|
@ -290,6 +290,7 @@ int ip6_defhlim = IPV6_DEFHLIM;
|
||||
int ip6_defmcasthlim = IPV6_DEFAULT_MULTICAST_HOPS;
|
||||
int ip6_accept_rtadv = 0; /* "IPV6FORWARDING ? 0 : 1" is dangerous */
|
||||
int ip6_maxfragpackets; /* initialized in frag6.c:frag6_init() */
|
||||
int ip6_maxfrags; /* initialized in frag6.c:frag6_init() */
|
||||
int ip6_log_interval = 5;
|
||||
int ip6_hdrnestlimit = 50; /* appropriate? */
|
||||
int ip6_dad_count = 1; /* DupAddrDetectionTransmits */
|
||||
@ -438,6 +439,8 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_AUTO_LINKLOCAL,
|
||||
auto_linklocal, CTLFLAG_RW, &ip6_auto_linklocal, 0, "");
|
||||
SYSCTL_STRUCT(_net_inet6_ip6, IPV6CTL_RIP6STATS, rip6stats, CTLFLAG_RD,
|
||||
&rip6stat, rip6stat, "");
|
||||
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGS,
|
||||
maxfrags, CTLFLAG_RW, &ip6_maxfrags, 0, "");
|
||||
|
||||
/* net.inet6.icmp6 */
|
||||
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRACCEPT,
|
||||
|
@ -89,6 +89,7 @@ struct ip6q {
|
||||
#ifdef notyet
|
||||
u_char *ip6q_nxtp;
|
||||
#endif
|
||||
int ip6q_nfrag; /* # of fragments */
|
||||
};
|
||||
|
||||
struct ip6asfrag {
|
||||
@ -267,6 +268,7 @@ extern int ip6_v6only;
|
||||
extern struct socket *ip6_mrouter; /* multicast routing daemon */
|
||||
extern int ip6_sendredirects; /* send IP redirects when forwarding? */
|
||||
extern int ip6_maxfragpackets; /* Maximum packets in reassembly queue */
|
||||
extern int ip6_maxfrags; /* Maximum fragments in reassembly queue */
|
||||
extern int ip6_sourcecheck; /* Verify source interface */
|
||||
extern int ip6_sourcecheck_interval; /* Interval between log messages */
|
||||
extern int ip6_accept_rtadv; /* Acts as a host not a router */
|
||||
|
Loading…
x
Reference in New Issue
Block a user