diff options
author | Kirk McKusick <mckusick@FreeBSD.org> | 2003-10-16 02:00:12 +0000 |
---|---|---|
committer | Kirk McKusick <mckusick@FreeBSD.org> | 2003-10-16 02:00:12 +0000 |
commit | b03587f06a5e642694f36edcd61fbcac0c0d5bdb (patch) | |
tree | d0092517192f341403455cd4528a65e75e2a8ff3 /sys/netinet/ip_fw2.c | |
parent | 14d19990988ef7723878ab5eef541beaaba3c251 (diff) | |
download | src-b03587f06a5e642694f36edcd61fbcac0c0d5bdb.tar.gz src-b03587f06a5e642694f36edcd61fbcac0c0d5bdb.zip |
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
Notes
Notes:
svn path=/head/; revision=121123
Diffstat (limited to 'sys/netinet/ip_fw2.c')
-rw-r--r-- | sys/netinet/ip_fw2.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/sys/netinet/ip_fw2.c b/sys/netinet/ip_fw2.c index 0d3da1b01c08..10a2bc03d9a0 100644 --- a/sys/netinet/ip_fw2.c +++ b/sys/netinet/ip_fw2.c @@ -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 && |