rn_walktree*() compute the next leaf before applying a function
to current leaves because function may vanish the current node. If parent RTA_GENMASK route has a clone (a "cloning clone"), an rn_walktree_from() starting from parent will cause another walk starting from clone. If a function is either rt_fixdelete() or rt_fixchange(), this recursive walk may vanish the leaf that is remembered by an outer walk (the "next leaf" above), panicing a system when it resumes with an outer walk. The following script paniced my single-user mode booted system: : sysctl net.inet.ip.forwarding=1 : ipfw add 1 allow ip from any to any : ifconfig lo0 127.1 : route add -net 10 -genmask 255.255.255.0 127.1 : telnet 10.1 # rt_fixchange() panic : telnet 10.2 : telnet 10.1 : route delete -net 10 # rt_fixdelete() panic For the time being, avoid these races by disallowing recursive walks in rt_fixchange() and rt_fixdelete(). Also, make a slight optimization in the rtrequest(RTM_RESOLVE) case: there is no reason to call rt_fixchange() in this case. PR: kern/37606 MFC after: 5 days
This commit is contained in:
parent
48096bb398
commit
36fea5de60
@ -741,7 +741,8 @@ rtrequest1(req, info, ret_nrt)
|
||||
* it doesn't fire when we call it there because the node
|
||||
* hasn't been added to the tree yet.
|
||||
*/
|
||||
if (!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
|
||||
if (req == RTM_ADD &&
|
||||
!(rt->rt_flags & RTF_HOST) && rt_mask(rt) != 0) {
|
||||
struct rtfc_arg arg;
|
||||
arg.rnh = rnh;
|
||||
arg.rt0 = rt;
|
||||
@ -787,7 +788,8 @@ rt_fixdelete(rn, vp)
|
||||
struct rtentry *rt = (struct rtentry *)rn;
|
||||
struct rtentry *rt0 = vp;
|
||||
|
||||
if (rt->rt_parent == rt0 && !(rt->rt_flags & RTF_PINNED)) {
|
||||
if (rt->rt_parent == rt0 &&
|
||||
!(rt->rt_flags & (RTF_PINNED | RTF_CLONING | RTF_PRCLONING))) {
|
||||
return rtrequest(RTM_DELETE, rt_key(rt),
|
||||
(struct sockaddr *)0, rt_mask(rt),
|
||||
rt->rt_flags, (struct rtentry **)0);
|
||||
@ -829,9 +831,10 @@ rt_fixchange(rn, vp)
|
||||
printf("rt_fixchange: rt %p, rt0 %p\n", rt, rt0);
|
||||
#endif
|
||||
|
||||
if (!rt->rt_parent || (rt->rt_flags & RTF_PINNED)) {
|
||||
if (!rt->rt_parent ||
|
||||
(rt->rt_flags & (RTF_PINNED | RTF_CLONING | RTF_PRCLONING))) {
|
||||
#ifdef DEBUG
|
||||
if(rtfcdebug) printf("no parent or pinned\n");
|
||||
if(rtfcdebug) printf("no parent, pinned or cloning\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user