[Devel] [PATCH v2 v2] fs/ovelayfs: Fix crash on overlayfs mount

2021-01-18 Thread Andrey Ryabinin
Kdump kernel fails to load because of crash on mount of overlayfs:

 BUG: unable to handle kernel NULL pointer dereference at 0060

 Call Trace:
  seq_path+0x64/0xb0
  print_paths_option+0x79/0xa0
  ovl_show_options+0x3a/0x320
  show_mountinfo+0x1ee/0x290
  seq_read+0x2f8/0x400
  vfs_read+0x9d/0x150
  ksys_read+0x4f/0xb0
  do_syscall_64+0x5b/0x1a0

This is cause by OOB access of ofs->lowerpaths.
We transfer to print_paths_option() ofs->numlayer as size of ->lowerpaths
array, but it's not.

The correct number of lowerpaths elements is ->numlower in 'struct ovl_entry'.
So move lowerpaths there and use oe->numlower as array size.

Fixes: 17fc61697f73 ("overlayfs: add dynamic path resolving in mount options")
Fixes: 2191d729083d ("overlayfs: add mnt_id paths options")

https://jira.sw.ru/browse/PSBM-123508
Signed-off-by: Andrey Ryabinin 
---
 fs/overlayfs/ovl_entry.h |  2 +-
 fs/overlayfs/super.c | 37 -
 2 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index ea1906448ec5..2315089a0211 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -54,7 +54,6 @@ struct ovl_fs {
unsigned int numlayer;
/* Number of unique fs among layers including upper fs */
unsigned int numfs;
-   struct path *lowerpaths;
const struct ovl_layer *layers;
struct ovl_sb *fs;
/* workbasepath is the path at workdir= mount option */
@@ -98,6 +97,7 @@ struct ovl_entry {
struct rcu_head rcu;
};
unsigned numlower;
+   struct path *lowerpaths;
struct ovl_path lowerstack[];
 };
 
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 3755f280036f..fb419617564c 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -70,8 +70,12 @@ static void ovl_entry_stack_free(struct ovl_entry *oe)
 {
unsigned int i;
 
-   for (i = 0; i < oe->numlower; i++)
+   for (i = 0; i < oe->numlower; i++) {
dput(oe->lowerstack[i].dentry);
+   if (oe->lowerpaths)
+   path_put(&oe->lowerpaths[i]);
+   }
+   kfree(oe->lowerpaths);
 }
 
 static bool ovl_metacopy_def = IS_ENABLED(CONFIG_OVERLAY_FS_METACOPY);
@@ -241,11 +245,6 @@ static void ovl_free_fs(struct ovl_fs *ofs)
ovl_inuse_unlock(ofs->upper_mnt->mnt_root);
mntput(ofs->upper_mnt);
path_put(&ofs->upperpath);
-   if (ofs->lowerpaths) {
-   for (i = 0; i < ofs->numlayer; i++)
-   path_put(&ofs->lowerpaths[i]);
-   kfree(ofs->lowerpaths);
-   }
for (i = 1; i < ofs->numlayer; i++) {
iput(ofs->layers[i].trap);
mntput(ofs->layers[i].mnt);
@@ -359,9 +358,10 @@ static int ovl_show_options(struct seq_file *m, struct 
dentry *dentry)
 {
struct super_block *sb = dentry->d_sb;
struct ovl_fs *ofs = sb->s_fs_info;
+   struct ovl_entry *oe = OVL_E(dentry);
 
if (ovl_dyn_path_opts) {
-   print_paths_option(m, "lowerdir", ofs->lowerpaths, 
ofs->numlayer);
+   print_paths_option(m, "lowerdir", oe->lowerpaths, oe->numlower);
if (ofs->config.upperdir) {
print_path_option(m, "upperdir", &ofs->upperpath);
print_path_option(m, "workdir", &ofs->workbasepath);
@@ -375,7 +375,7 @@ static int ovl_show_options(struct seq_file *m, struct 
dentry *dentry)
}
 
if (ovl_mnt_id_path_opts) {
-   print_mnt_ids_option(m, "lowerdir_mnt_id", ofs->lowerpaths, 
ofs->numlayer);
+   print_mnt_ids_option(m, "lowerdir_mnt_id", oe->lowerpaths, 
oe->numlower);
/*
 * We don't need to show mnt_id for workdir because it
 * on the same mount as upperdir.
@@ -1626,6 +1626,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct 
super_block *sb,
int err;
char *lowertmp, *lower;
unsigned int stacklen, numlower = 0, i;
+   struct path *stack = NULL;
struct ovl_entry *oe;
 
err = -ENOMEM;
@@ -1649,14 +1650,14 @@ static struct ovl_entry *ovl_get_lowerstack(struct 
super_block *sb,
}
 
err = -ENOMEM;
-   ofs->lowerpaths = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
-   if (!ofs->lowerpaths)
+   stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL);
+   if (!stack)
goto out_err;
 
err = -EINVAL;
lower = lowertmp;
for (numlower = 0; numlower < stacklen; numlower++) {
-   err = ovl_lower_dir(lower, &ofs->lowerpaths[numlower], ofs,
+   err = ovl_lower_dir(lower, &stack[numlower], ofs,
&sb->s_stack_depth);
if (err)
goto out_err;
@@ -1671,7 +1672,7 @@ static struct ovl_entry *ovl_get_lowerstack(struct 
super_block *

[Devel] [VZ8 PATCH 1/3] ve/cgroup: unmark ve-root cgroups at container stop

2021-01-18 Thread Valeriy Vdovin
fixes: 915a1130c7ee4ffb6de3f69a5bd98c5ee42a723f

Signed-off-by: Valeriy Vdovin 
Reviewed-by: Kirill Tkhai 

Cherry-picked from 5dceccf5dd794673ebb1b0e6840d96aa654ec33e)
Signed-off-by: Valeriy Vdovin 
---
 include/linux/cgroup.h |  1 +
 kernel/cgroup/cgroup.c | 24 
 kernel/ve/ve.c |  3 +++
 3 files changed, 28 insertions(+)

diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 4f0dd51338bf..c0a42c3d43fa 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -867,6 +867,7 @@ int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t 
buflen,
 
 #ifdef CONFIG_VE
 extern void cgroup_mark_ve_root(struct ve_struct *ve);
+void cgroup_unmark_ve_roots(struct ve_struct *ve);
 #endif
 
 #else /* !CONFIG_CGROUPS */
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 0335a07f64e6..4488df184235 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -1908,6 +1908,30 @@ void cgroup_mark_ve_root(struct ve_struct *ve)
spin_unlock_irq(&css_set_lock);
 }
 
+void cgroup_unmark_ve_roots(struct ve_struct *ve)
+{
+   struct cgrp_cset_link *link;
+   struct css_set *cset;
+   struct cgroup *cgrp;
+
+   spin_lock_irq(&css_set_lock);
+
+   rcu_read_lock();
+   cset = rcu_dereference(ve->ve_ns)->cgroup_ns->root_cset;
+   if (WARN_ON(!cset))
+   goto unlock;
+
+   list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
+   cgrp = link->cgrp;
+   clear_bit(CGRP_VE_ROOT, &cgrp->flags);
+   }
+   link_ve_root_cpu_cgroup(cset->subsys[cpu_cgrp_id]);
+unlock:
+   rcu_read_unlock();
+
+   spin_unlock_irq(&css_set_lock);
+}
+
 struct cgroup *cgroup_get_ve_root1(struct cgroup *cgrp)
 {
struct cgroup *ve_root = NULL;
diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c
index 3f53641455ad..b922653acf49 100644
--- a/kernel/ve/ve.c
+++ b/kernel/ve/ve.c
@@ -519,6 +519,9 @@ void ve_exit_ns(struct pid_namespace *pid_ns)
 */
if (!ve_ns || ve_ns->pid_ns_for_children != pid_ns)
goto unlock;
+
+   cgroup_unmark_ve_roots(ve);
+
/*
 * At this point all userspace tasks in container are dead.
 */
-- 
2.27.0

___
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel


[Devel] [VZ8 PATCH 3/3] cgroup: port CGROUP_REMOVED flag from vz7

2021-01-18 Thread Valeriy Vdovin
The flag will be used in subsequent porting patches for release_agent
functionality
Signed-off-by: Valeriy Vdovin 
---
 include/linux/cgroup-defs.h | 2 ++
 include/linux/cgroup.h  | 5 +
 kernel/cgroup/cgroup.c  | 1 +
 3 files changed, 8 insertions(+)

diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index a3b309ab1a90..5ee5f10e3de7 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -57,6 +57,8 @@ enum {
 
 /* bits in struct cgroup flags field */
 enum {
+   /* Control Cgroup is dead */
+   CGRP_REMOVED,
/* Control Group requires release notifications to userspace */
CGRP_NOTIFY_ON_RELEASE,
/*
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index c0a42c3d43fa..dfd9460986ee 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -922,6 +922,11 @@ static inline bool cgroup_task_frozen(struct task_struct 
*task)
return task->frozen;
 }
 
+static inline int cgroup_is_removed(const struct cgroup *cgrp)
+{
+   return test_bit(CGRP_REMOVED, &cgrp->flags);
+}
+
 #else /* !CONFIG_CGROUPS */
 
 static inline void cgroup_enter_frozen(void) { }
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 797a3971ab46..447c8f003496 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -5562,6 +5562,7 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)
tcgrp->freezer.nr_frozen_descendants--;
}
spin_unlock_irq(&css_set_lock);
+   set_bit(CGRP_REMOVED, &cgrp->flags);
 
cgroup1_check_for_release(parent);
 
-- 
2.27.0

___
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel


[Devel] [VZ8 PATCH 2/3] cgroup/cfs: added 'activate' option to cgroup_add_file

2021-01-18 Thread Valeriy Vdovin
In kernfs files get created in 'deactivated' state, which means
they are not visible.
Add option to activate the file after creation immediately making it visible
in the parent directory.
Will be used in later patches.

Signed-off-by: Valeriy Vdovin 
---
 kernel/cgroup/cgroup.c | 6 --
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 4488df184235..797a3971ab46 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -3824,7 +3824,7 @@ static void cgroup_file_notify_timer(struct timer_list 
*timer)
 }
 
 static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup 
*cgrp,
-  struct cftype *cft)
+  struct cftype *cft, bool activate)
 {
char name[CGROUP_FILE_NAME_MAX];
struct kernfs_node *kn;
@@ -3866,6 +3866,8 @@ static int cgroup_add_file(struct cgroup_subsys_state 
*css, struct cgroup *cgrp,
if (IS_ERR(kn_link))
return PTR_ERR(kn_link);
}
+   if (activate)
+   kernfs_activate(kn);
 
return 0;
 }
@@ -3903,7 +3905,7 @@ static int cgroup_addrm_files(struct cgroup_subsys_state 
*css,
if ((cft->flags & CFTYPE_DEBUG) && !cgroup_debug)
continue;
if (is_add) {
-   ret = cgroup_add_file(css, cgrp, cft);
+   ret = cgroup_add_file(css, cgrp, cft, false);
if (ret) {
pr_warn("%s: failed to add %s, err=%d\n",
__func__, cft->name, ret);
-- 
2.27.0

___
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel