Malloc buckets of size 128 have been having their 64-byte offset

trashed after being freed. This has caused several panics including
kern/42277 related to soft updates. Jim Kuhn tracked the problem
down to ipfw limit rule processing.  In the expiry of dynamic rules,
it is possible for an O_LIMIT_PARENT rule to be removed when it still
has live children.  When the children eventually do expire, a pointer
to the (long gone) parent is dereferenced and a count decremented.
Since this memory can, and is, allocated for other purposes (in the
case of kern/42277 an inodedep structure), chaos ensues. The offset
in question in inodedep is the offset of the 16 bit count field in
the ipfw2 ipfw_dyn_rule.

Submitted by:	Jim Kuhn <jkuhn@sandvine.com>
Reviewed by:	"Evgueni V. Gavrilov" <aquatique@rusunix.org>
Reviewed by:	Ben Pfountz <netprince@vt.edu>
MFC after:	1 week
This commit is contained in:
mckusick 2003-10-16 02:00:12 +00:00
parent 8eb262a2d5
commit 0dd6703d54

View File

@ -768,8 +768,10 @@ next_pass:
!TIME_LEQ( q->expire, time_second ))
goto next;
}
UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
continue;
if (q->dyn_type != O_LIMIT_PARENT || !q->count) {
UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
continue;
}
next:
prev=q;
q=q->next;
@ -804,13 +806,14 @@ lookup_dyn_rule_locked(struct ipfw_flow_id *pkt, int *match_direction,
goto done; /* not found */
i = hash_packet( pkt );
for (prev=NULL, q = ipfw_dyn_v[i] ; q != NULL ; ) {
if (q->dyn_type == O_LIMIT_PARENT)
if (q->dyn_type == O_LIMIT_PARENT && q->count)
goto next;
if (TIME_LEQ( q->expire, time_second)) { /* expire entry */
UNLINK_DYN_RULE(prev, ipfw_dyn_v[i], q);
continue;
}
if ( pkt->proto == q->id.proto) {
if (pkt->proto == q->id.proto &&
q->dyn_type != O_LIMIT_PARENT) {
if (pkt->src_ip == q->id.src_ip &&
pkt->dst_ip == q->id.dst_ip &&
pkt->src_port == q->id.src_port &&