netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop.
@ 2008-05-07  8:08 Pavel Emelyanov
  2008-05-07 15:33 ` Daniel Lezcano
  0 siblings, 1 reply; 5+ messages in thread
From: Pavel Emelyanov @ 2008-05-07  8:08 UTC (permalink / raw)
  To: David Miller; +Cc: Linux Netdev List

When a net namespace is destroyed, some devices (those, not killed
on ns stop explicitly) are moved back to init_net.

The problem, is that this net_ns change has one point of failure -
the __dev_alloc_name() may be called if a name collision occurs (and
this is easy to trigger). This allocator performs a likely-to-fail
GFP_ATOMIC allocation to find a suitable number. Other possible 
conditions that may cause error (for device being ns local or not
registered) are always false in this case.

So, when this call fails, the device is unregistered. But this is
*not* the right thing to do, since after this the device may be
released (and kfree-ed) improperly. E. g. bridges require more
actions (sysfs update, timer disarming, etc.), some other devices 
want to remove their private areas from lists, etc.

I. e. arbitrary use-after-free cases may occur.

The proposed fix is the following: since the only reason for the
dev_change_net_namespace to fail is the name generation, we may
give it a unique fall-back name w/o %d-s in it - the dev<ifindex>
one, since ifindexes are still unique.

So make this change, raise the failure-case printk loglevel to 
EMERG and replace the unregister_netdevice call with BUG().

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/net/core/dev.c b/net/core/dev.c
index d334446..86da6aa 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4480,17 +4480,19 @@ static void __net_exit default_device_exit(struct net *net)
 	rtnl_lock();
 	for_each_netdev_safe(net, dev, next) {
 		int err;
+		char fb_name[IFNAMSIZ];
 
 		/* Ignore unmoveable devices (i.e. loopback) */
 		if (dev->features & NETIF_F_NETNS_LOCAL)
 			continue;
 
 		/* Push remaing network devices to init_net */
-		err = dev_change_net_namespace(dev, &init_net, "dev%d");
+		sprintf(fb_name, "dev%d", dev->ifindex);
+		err = dev_change_net_namespace(dev, &init_net, fb_name);
 		if (err) {
-			printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n",
+			printk(KERN_EMERG "%s: failed to move %s to init_net: %d\n",
 				__func__, dev->name, err);
-			unregister_netdevice(dev);
+			BUG();
 		}
 	}
 	rtnl_unlock();

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop.
  2008-05-07  8:08 [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop Pavel Emelyanov
@ 2008-05-07 15:33 ` Daniel Lezcano
  2008-05-07 15:37   ` Pavel Emelyanov
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Lezcano @ 2008-05-07 15:33 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

Pavel Emelyanov wrote:
> When a net namespace is destroyed, some devices (those, not killed
> on ns stop explicitly) are moved back to init_net.
> 
> The problem, is that this net_ns change has one point of failure -
> the __dev_alloc_name() may be called if a name collision occurs (and
> this is easy to trigger). This allocator performs a likely-to-fail
> GFP_ATOMIC allocation to find a suitable number. Other possible 
> conditions that may cause error (for device being ns local or not
> registered) are always false in this case.
> 
> So, when this call fails, the device is unregistered. But this is
> *not* the right thing to do, since after this the device may be
> released (and kfree-ed) improperly. E. g. bridges require more
> actions (sysfs update, timer disarming, etc.), some other devices 
> want to remove their private areas from lists, etc.
> 
> I. e. arbitrary use-after-free cases may occur.
> 
> The proposed fix is the following: since the only reason for the
> dev_change_net_namespace to fail is the name generation, we may
> give it a unique fall-back name w/o %d-s in it - the dev<ifindex>
> one, since ifindexes are still unique.
> 
> So make this change, raise the failure-case printk loglevel to 
> EMERG and replace the unregister_netdevice call with BUG().
> 
> Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
> 
> ---

Good catch :)

> diff --git a/net/core/dev.c b/net/core/dev.c
> index d334446..86da6aa 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -4480,17 +4480,19 @@ static void __net_exit default_device_exit(struct net *net)
>  	rtnl_lock();
>  	for_each_netdev_safe(net, dev, next) {
>  		int err;
> +		char fb_name[IFNAMSIZ];
> 
>  		/* Ignore unmoveable devices (i.e. loopback) */
>  		if (dev->features & NETIF_F_NETNS_LOCAL)
>  			continue;
> 
>  		/* Push remaing network devices to init_net */
> -		err = dev_change_net_namespace(dev, &init_net, "dev%d");
> +		sprintf(fb_name, "dev%d", dev->ifindex);

The computed interface name can not exceed IFNAMSIZ, 3 ('dev') + 10 (max 
int) + 1 ('\0'). In this case there is no risk to corrupt the stack but 
may be it is more secure to change that to snprintf(fb_name, IFNAMSIZ, 
"dev%d", dev->ifindex), just in case, no ?

> +		err = dev_change_net_namespace(dev, &init_net, fb_name);
>  		if (err) {
> -			printk(KERN_WARNING "%s: failed to move %s to init_net: %d\n",
> +			printk(KERN_EMERG "%s: failed to move %s to init_net: %d\n",
>  				__func__, dev->name, err);
> -			unregister_netdevice(dev);
> +			BUG();
>  		}
>  	}
>  	rtnl_unlock();
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop.
  2008-05-07 15:33 ` Daniel Lezcano
@ 2008-05-07 15:37   ` Pavel Emelyanov
  2008-05-07 16:12     ` Daniel Lezcano
  0 siblings, 1 reply; 5+ messages in thread
From: Pavel Emelyanov @ 2008-05-07 15:37 UTC (permalink / raw)
  To: Daniel Lezcano; +Cc: David Miller, Linux Netdev List

>> +		sprintf(fb_name, "dev%d", dev->ifindex);
> 
> The computed interface name can not exceed IFNAMSIZ, 3 ('dev') + 10 (max 
> int) + 1 ('\0'). In this case there is no risk to corrupt the stack but 
> may be it is more secure to change that to snprintf(fb_name, IFNAMSIZ, 
> "dev%d", dev->ifindex), just in case, no ?

But you have just noticed, that "there is no risk to corrupt the stack"!
What else can be "more secure" then :) ?

Thanks,
Pavel

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop.
  2008-05-07 15:37   ` Pavel Emelyanov
@ 2008-05-07 16:12     ` Daniel Lezcano
  2008-05-08  8:25       ` David Miller
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Lezcano @ 2008-05-07 16:12 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

Pavel Emelyanov wrote:
>>> +		sprintf(fb_name, "dev%d", dev->ifindex);
>> The computed interface name can not exceed IFNAMSIZ, 3 ('dev') + 10 (max 
>> int) + 1 ('\0'). In this case there is no risk to corrupt the stack but 
>> may be it is more secure to change that to snprintf(fb_name, IFNAMSIZ, 
>> "dev%d", dev->ifindex), just in case, no ?
> 
> But you have just noticed, that "there is no risk to corrupt the stack"!
> What else can be "more secure" then :) ?

Just in case, for example, someone changes 'dev' by 'virtdev' or 
something else.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop.
  2008-05-07 16:12     ` Daniel Lezcano
@ 2008-05-08  8:25       ` David Miller
  0 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2008-05-08  8:25 UTC (permalink / raw)
  To: dlezcano; +Cc: xemul, netdev

From: Daniel Lezcano <dlezcano@fr.ibm.com>
Date: Wed, 07 May 2008 18:12:35 +0200

> Pavel Emelyanov wrote:
> >>> +		sprintf(fb_name, "dev%d", dev->ifindex);
> >> The computed interface name can not exceed IFNAMSIZ, 3 ('dev') + 10 (max 
> >> int) + 1 ('\0'). In this case there is no risk to corrupt the stack but 
> >> may be it is more secure to change that to snprintf(fb_name, IFNAMSIZ, 
> >> "dev%d", dev->ifindex), just in case, no ?
> > 
> > But you have just noticed, that "there is no risk to corrupt the stack"!
> > What else can be "more secure" then :) ?
> 
> Just in case, for example, someone changes 'dev' by 'virtdev' or 
> something else.

I've applied Pavel's patch, but I changed it to use snprintf() to
address Daniel's concerns.

And this matches the way this is done in the rest of this file too :-)

Thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-05-08  8:25 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-07  8:08 [PATCH][NETNS]: Fix arbitrary net_device-s corruptions on net_ns stop Pavel Emelyanov
2008-05-07 15:33 ` Daniel Lezcano
2008-05-07 15:37   ` Pavel Emelyanov
2008-05-07 16:12     ` Daniel Lezcano
2008-05-08  8:25       ` David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).