aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ipmr.c
diff options
context:
space:
mode:
authorAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>2006-07-25 19:45:12 -0400
committerDavid S. Miller <davem@davemloft.net>2006-07-25 19:45:12 -0400
commit722874909271a807b243a797c2958e0a12992964 (patch)
tree341d9c20eacdf8f452d8e2eea61fe2d40923179d /net/ipv4/ipmr.c
parentb6e77a5346d8a739227ed73c2269966a4fd652b4 (diff)
[IPV4] ipmr: ip multicast route bug fix.
IP multicast route code was reusing an skb which causes use after free and double free. From: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> Note, it is real skb_clone(), not alloc_skb(). Equeued skb contains the whole half-prepared netlink message plus room for the rest. It could be also skb_copy(), if we want to be puristic about mangling cloned data, but original copy is really not going to be used. Acked-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/ipmr.c')
-rw-r--r--net/ipv4/ipmr.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 9ccacf57f08b..85893eef6b16 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1578,6 +1578,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
1578 cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); 1578 cache = ipmr_cache_find(rt->rt_src, rt->rt_dst);
1579 1579
1580 if (cache==NULL) { 1580 if (cache==NULL) {
1581 struct sk_buff *skb2;
1581 struct net_device *dev; 1582 struct net_device *dev;
1582 int vif; 1583 int vif;
1583 1584
@@ -1591,12 +1592,18 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait)
1591 read_unlock(&mrt_lock); 1592 read_unlock(&mrt_lock);
1592 return -ENODEV; 1593 return -ENODEV;
1593 } 1594 }
1594 skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); 1595 skb2 = skb_clone(skb, GFP_ATOMIC);
1595 skb->nh.iph->ihl = sizeof(struct iphdr)>>2; 1596 if (!skb2) {
1596 skb->nh.iph->saddr = rt->rt_src; 1597 read_unlock(&mrt_lock);
1597 skb->nh.iph->daddr = rt->rt_dst; 1598 return -ENOMEM;
1598 skb->nh.iph->version = 0; 1599 }
1599 err = ipmr_cache_unresolved(vif, skb); 1600
1601 skb2->nh.raw = skb_push(skb2, sizeof(struct iphdr));
1602 skb2->nh.iph->ihl = sizeof(struct iphdr)>>2;
1603 skb2->nh.iph->saddr = rt->rt_src;
1604 skb2->nh.iph->daddr = rt->rt_dst;
1605 skb2->nh.iph->version = 0;
1606 err = ipmr_cache_unresolved(vif, skb2);
1600 read_unlock(&mrt_lock); 1607 read_unlock(&mrt_lock);
1601 return err; 1608 return err;
1602 } 1609 }