gmcnutt
2011-02-24 17:25:37 UTC
if_detach() calls rt_walktree with if_rt_walktree as the visiting callback,
which calls rtrequest(RTM_DELETE, ...) from within the tree iteration in
rn_walktree. Although rn_walktree protects itself from deletion of the current
node while iterating, there is no protection if the *next* node is deleted
during the callback. This can happen if the called node is a route and there is
a clone of it following it in the iteration sequence. That is because
rtrequest1, in the RTM_DELETE case, will call rtflushclone, and this will
delete the cloned route. Upon return to rn_walktree, the next node may be
deleted, but rn_walktree will dereference it.
Here's the call sequence:
if_detach
`-rt_walktree
+-rn_walktree /* rt2 is next */
| `-rn_walktree_visitor(rt1)
| `-if_rt_detach(rt1)
| `-rtrequest1(rt1)
| +-rtflushclone(rt1)
| | `-rt_walktree(rt1)
| | `-rn_walktree_visitor(rt2)
| | `-rtflushclone1(rt2)
| | `-rtdeletemsg(rt2)
| | `-rtfree(rt2)
| `-rtfree(rt1)
`- /* crash on deref of rt2 (next) */
The cloned route in this case (labeled rt2 above) was created as a consequence
of if_arp.c setting the RTF_CLONING flag, presumably on rt1, but I haven't dug
into how route.c and radix.c determine their ordering yet to satisfy myself
that this is the case.
It seems the fundamental problem is that rn_walktree is defenseless against
this kind of radix tree mutation while it is iterating. Am I right, or is my
system somehow abusing some assumption about how those radix trees are supposed
to be ordered?
--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
which calls rtrequest(RTM_DELETE, ...) from within the tree iteration in
rn_walktree. Although rn_walktree protects itself from deletion of the current
node while iterating, there is no protection if the *next* node is deleted
during the callback. This can happen if the called node is a route and there is
a clone of it following it in the iteration sequence. That is because
rtrequest1, in the RTM_DELETE case, will call rtflushclone, and this will
delete the cloned route. Upon return to rn_walktree, the next node may be
deleted, but rn_walktree will dereference it.
Here's the call sequence:
if_detach
`-rt_walktree
+-rn_walktree /* rt2 is next */
| `-rn_walktree_visitor(rt1)
| `-if_rt_detach(rt1)
| `-rtrequest1(rt1)
| +-rtflushclone(rt1)
| | `-rt_walktree(rt1)
| | `-rn_walktree_visitor(rt2)
| | `-rtflushclone1(rt2)
| | `-rtdeletemsg(rt2)
| | `-rtfree(rt2)
| `-rtfree(rt1)
`- /* crash on deref of rt2 (next) */
The cloned route in this case (labeled rt2 above) was created as a consequence
of if_arp.c setting the RTF_CLONING flag, presumably on rt1, but I haven't dug
into how route.c and radix.c determine their ordering yet to satisfy myself
that this is the case.
It seems the fundamental problem is that rn_walktree is defenseless against
this kind of radix tree mutation while it is iterating. Am I right, or is my
system somehow abusing some assumption about how those radix trees are supposed
to be ordered?
--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de