[Devel] [PATCH RH8] ve/net: fix crash in ve_dev_can_rename
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Tue Oct 5 15:33:12 MSK 2021
On 05.10.2021 15:31, Pavel Tikhomirov wrote:
> Add ve_get_net_ns helper to get network namespace owned by ve. Using
> rcu_read_lock to protect ve->ve_ns nsproxy from being freed. Referencing
> netns also protects from any kind of netns reuse when comparing netns
> pointers.
>
> Previousely if we rename network device in netns owned by ve which is
> not in started state we get crash on dereferencing ve->ve_ns.
>
> https://jira.sw.ru/browse/PSBM-133993
Fixes: 0460650a21fa ("ve/net: allow to rename devices in non-ve namespaces")
> Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
> ---
> include/linux/ve.h | 2 ++
> kernel/ve/ve.c | 15 +++++++++++++++
> net/core/dev.c | 15 +++++++++------
> 3 files changed, 26 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/ve.h b/include/linux/ve.h
> index 46b18e1535b6..c75718017d9d 100644
> --- a/include/linux/ve.h
> +++ b/include/linux/ve.h
> @@ -221,6 +221,8 @@ extern int vz_security_protocol_check(struct net *net, int protocol);
>
> int ve_net_hide_sysctl(struct net *net);
>
> +extern struct net *ve_get_net_ns(struct ve_struct* ve);
> +
> #else /* CONFIG_VE */
> #define get_ve(ve) (NULL)
> #define put_ve(ve) do { } while (0)
> diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
> index 9bccdd90037d..56a535d840c0 100644
> --- a/kernel/ve/ve.c
> +++ b/kernel/ve/ve.c
> @@ -30,6 +30,7 @@
> #include <linux/task_work.h>
> #include <linux/ctype.h>
> #include <linux/tty.h>
> +#include <net/net_namespace.h>
> #include <linux/genhd.h>
> #include <linux/device.h>
>
> @@ -276,6 +277,20 @@ int ve_net_hide_sysctl(struct net *net)
> }
> EXPORT_SYMBOL(ve_net_hide_sysctl);
>
> +struct net *ve_get_net_ns(struct ve_struct* ve)
> +{
> + struct nsproxy *ve_ns;
> + struct net *net_ns;
> +
> + rcu_read_lock();
> + ve_ns = rcu_dereference(ve->ve_ns);
> + net_ns = ve_ns ? get_net(ve_ns->net_ns) : NULL;
> + rcu_read_unlock();
> +
> + return net_ns;
> +}
> +EXPORT_SYMBOL(ve_get_net_ns);
> +
> int nr_threads_ve(struct ve_struct *ve)
> {
> return cgroup_task_count(ve->css.cgroup);
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 01e773ff57c1..4f9849bac212 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -1167,19 +1167,19 @@ int dev_get_valid_name(struct net *net, struct net_device *dev,
> }
> EXPORT_SYMBOL(dev_get_valid_name);
>
> +#ifdef CONFIG_VE
> static bool ve_dev_can_rename(struct net_device *dev)
> {
> struct net *net;
> bool can;
>
> - /*
> - * rcu_read_lock()/unlock won't help here anyway:
> - * "can" value can change right after rcu lock is dropped.
> - */
> - net = rcu_dereference_check(dev_net(dev)->owner_ve->ve_ns, 1)->net_ns;
> + net = ve_get_net_ns(dev_net(dev)->owner_ve);
> can = !net || net == dev_net(dev);
> + if (net)
> + put_net(net);
> return can;
> }
> +#endif
>
> /**
> * dev_change_name - change name of a device
> @@ -1226,9 +1226,10 @@ int dev_change_name(struct net_device *dev, const char *newname)
> dev->name_assign_type = NET_NAME_RENAMED;
>
> rollback:
> -
> +#ifdef CONFIG_VE
> if (!ve_dev_can_rename(dev))
> goto skip_rename;
> +#endif
>
> ret = device_rename(&dev->dev, dev->name);
> if (ret) {
> @@ -1238,7 +1239,9 @@ int dev_change_name(struct net_device *dev, const char *newname)
> return ret;
> }
>
> +#ifdef CONFIG_VE
> skip_rename:
> +#endif
> up_write(&devnet_rename_sem);
>
> netdev_adjacent_rename_links(dev, oldname);
>
--
Best regards, Tikhomirov Pavel
Software Developer, Virtuozzo.
More information about the Devel
mailing list