diff options
author | Wang Chen <wangchen@cn.fujitsu.com> | 2008-07-14 23:55:26 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-14 23:55:26 -0400 |
commit | d607032db0ccd7274bee348df3214f6f52b24816 (patch) | |
tree | 3870d689a346589604ff25e0c359debd3b0ca914 | |
parent | 7af3db78a99f47b9ff40b8cb0bb08160ad6a3d6b (diff) |
ipv4: Check return of dev_set_allmulti
allmulti might overflow.
Commit: "netdevice: Fix promiscuity and allmulti overflow" in net-next makes
dev_set_promiscuity/allmulti return error number if overflow happened.
Here, we check the positive increment for allmulti to get error return.
PS: For unwinding tunnel creating, we let ipip->ioctl() to handle it.
Signed-off-by: Wang Chen <wangchen@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/ipmr.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 438fab9c62a0..2f4d8afd067c 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -118,6 +118,31 @@ static struct timer_list ipmr_expire_timer; | |||
118 | 118 | ||
119 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ | 119 | /* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */ |
120 | 120 | ||
121 | static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) | ||
122 | { | ||
123 | dev_close(dev); | ||
124 | |||
125 | dev = __dev_get_by_name(&init_net, "tunl0"); | ||
126 | if (dev) { | ||
127 | struct ifreq ifr; | ||
128 | mm_segment_t oldfs; | ||
129 | struct ip_tunnel_parm p; | ||
130 | |||
131 | memset(&p, 0, sizeof(p)); | ||
132 | p.iph.daddr = v->vifc_rmt_addr.s_addr; | ||
133 | p.iph.saddr = v->vifc_lcl_addr.s_addr; | ||
134 | p.iph.version = 4; | ||
135 | p.iph.ihl = 5; | ||
136 | p.iph.protocol = IPPROTO_IPIP; | ||
137 | sprintf(p.name, "dvmrp%d", v->vifc_vifi); | ||
138 | ifr.ifr_ifru.ifru_data = (__force void __user *)&p; | ||
139 | |||
140 | oldfs = get_fs(); set_fs(KERNEL_DS); | ||
141 | dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL); | ||
142 | set_fs(oldfs); | ||
143 | } | ||
144 | } | ||
145 | |||
121 | static | 146 | static |
122 | struct net_device *ipmr_new_tunnel(struct vifctl *v) | 147 | struct net_device *ipmr_new_tunnel(struct vifctl *v) |
123 | { | 148 | { |
@@ -389,6 +414,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
389 | struct vif_device *v = &vif_table[vifi]; | 414 | struct vif_device *v = &vif_table[vifi]; |
390 | struct net_device *dev; | 415 | struct net_device *dev; |
391 | struct in_device *in_dev; | 416 | struct in_device *in_dev; |
417 | int err; | ||
392 | 418 | ||
393 | /* Is vif busy ? */ | 419 | /* Is vif busy ? */ |
394 | if (VIF_EXISTS(vifi)) | 420 | if (VIF_EXISTS(vifi)) |
@@ -406,18 +432,31 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
406 | dev = ipmr_reg_vif(); | 432 | dev = ipmr_reg_vif(); |
407 | if (!dev) | 433 | if (!dev) |
408 | return -ENOBUFS; | 434 | return -ENOBUFS; |
435 | err = dev_set_allmulti(dev, 1); | ||
436 | if (err) { | ||
437 | unregister_netdevice(dev); | ||
438 | return err; | ||
439 | } | ||
409 | break; | 440 | break; |
410 | #endif | 441 | #endif |
411 | case VIFF_TUNNEL: | 442 | case VIFF_TUNNEL: |
412 | dev = ipmr_new_tunnel(vifc); | 443 | dev = ipmr_new_tunnel(vifc); |
413 | if (!dev) | 444 | if (!dev) |
414 | return -ENOBUFS; | 445 | return -ENOBUFS; |
446 | err = dev_set_allmulti(dev, 1); | ||
447 | if (err) { | ||
448 | ipmr_del_tunnel(dev, vifc); | ||
449 | return err; | ||
450 | } | ||
415 | break; | 451 | break; |
416 | case 0: | 452 | case 0: |
417 | dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); | 453 | dev = ip_dev_find(&init_net, vifc->vifc_lcl_addr.s_addr); |
418 | if (!dev) | 454 | if (!dev) |
419 | return -EADDRNOTAVAIL; | 455 | return -EADDRNOTAVAIL; |
420 | dev_put(dev); | 456 | dev_put(dev); |
457 | err = dev_set_allmulti(dev, 1); | ||
458 | if (err) | ||
459 | return err; | ||
421 | break; | 460 | break; |
422 | default: | 461 | default: |
423 | return -EINVAL; | 462 | return -EINVAL; |
@@ -426,7 +465,6 @@ static int vif_add(struct vifctl *vifc, int mrtsock) | |||
426 | if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) | 465 | if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) |
427 | return -EADDRNOTAVAIL; | 466 | return -EADDRNOTAVAIL; |
428 | IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; | 467 | IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++; |
429 | dev_set_allmulti(dev, +1); | ||
430 | ip_rt_multicast_event(in_dev); | 468 | ip_rt_multicast_event(in_dev); |
431 | 469 | ||
432 | /* | 470 | /* |