On 6/3/20 7:58 PM, Alexander Mikhalitsyn wrote:
This patch adds OVERLAY_FS_DYNAMIC_RESOLVE_PATH_OPTIONS
compile-time option, and "dyn_path_opts" runtime module option.
These options corresponds "dynamic path resolving in lowerdir,
upperdir, workdir mount options" mode. If enabled, user may see
real full paths relatively to the mount namespace in lowerdir,
upperdir, workdir options (/proc/mounts, /proc/<fd>/mountinfo).

This patch is very helpful to checkpoint/restore functionality
of overlayfs mounts. With this patch and CRIU it's real to C/R
Docker containers with overlayfs storage driver.

Note: d_path function from dcache.c is used to resolve full path
in mount namespace. This function also adds "(deleted)" suffix
if dentry was deleted. So, If one of dentries in lowerdir, upperdir,
workdir options is deleted, we will see "(deleted)" suffix in
corresponding path.

https://jira.sw.ru/browse/PSBM-58614

Signed-off-by: Alexander Mikhalitsyn <[email protected]>
Reviewed-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>

v2: print_paths_option helper now uses only one additional page, code
refactored according review comments

v3: print_paths_option helper now correctly escapes special symbols in
paths, fixed ofs->lowerpaths[i] paths leak on error path in
ovl_get_lowerstack function

v4: fixed ofs->lowerpaths[i] paths double put on error path in
ovl_get_lowerstack function

v5: removed redundant path_put_init(&ofs->upperpath) in ovl_fill_super
function

v6: print_path_option, print_paths_option reworked using seq_path() helper

v7: make rw access to dyn_path_opts parameter,


add explicit
ofs->lowerpaths kfree and NULLify in ovl_get_lowerstack on error
path to make code more readable

It looks like this also introduces null pointer dereference, and crash. Imagine:

ovl_fill_super {
  ovl_get_lowerstack {
    ovl_lower_dir
    numlower++ # numlower == 1
    ovl_get_lower_layers
      ofs->numlower++ # ofs->numlower == 1
    ovl_alloc_entry # return error
    goto out_err

  out_err:
    path_put_init(&ofs->lowerpaths[0])
    kfree(ofs->lowerpaths)
    ofs->lowerpaths = NULL
  } # return error
  goto out_err
out_err:
  ovl_free_fs
    path_put(&ofs->lowerpaths[0]) # ofs->lowerpaths == NULL
      dput(path->dentry) # crash
}

If you reset lowerpaths to NULL, you should check for NULL somethere in ovl_free_fs. The thing we should remember ofs->numlower is a counter for ofs->lower_layers it can be inconsistent with the state of ofs->lowerpaths.

I would suggest:

--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -259,9 +259,11 @@ 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);
-       for (i = 0; i < ofs->numlower; i++)
-               path_put(&ofs->lowerpaths[i]);
-       kfree(ofs->lowerpaths);
+       if (ofs->lowerpaths) {
+               for (i = 0; i < ofs->numlower; i++)
+                       path_put(&ofs->lowerpaths[i]);
+               kfree(ofs->lowerpaths);
+       }
        for (i = 0; i < ofs->numlower; i++)
                mntput(ofs->lower_layers[i].mnt);
        for (i = 0; i < ofs->numlowerfs; i++)

---
  fs/overlayfs/Kconfig     | 31 ++++++++++++++++++
  fs/overlayfs/overlayfs.h |  4 +++
  fs/overlayfs/ovl_entry.h |  6 ++--
  fs/overlayfs/super.c     | 85 ++++++++++++++++++++++++++----------------------
  fs/overlayfs/util.c      | 21 ++++++++++++
  5 files changed, 107 insertions(+), 40 deletions(-)

@@ -245,11 +249,15 @@ static void ovl_free_fs(struct ovl_fs *ofs)
        dput(ofs->indexdir);
        dput(ofs->workdir);
        if (ofs->workdir_locked)
-               ovl_inuse_unlock(ofs->workbasedir);
-       dput(ofs->workbasedir);
+               ovl_inuse_unlock(ofs->workbasepath.dentry);
+       path_put(&ofs->workbasepath);
        if (ofs->upperdir_locked)
                ovl_inuse_unlock(ofs->upper_mnt->mnt_root);
        mntput(ofs->upper_mnt);
+       path_put(&ofs->upperpath);
+       for (i = 0; i < ofs->numlower; i++)
+               path_put(&ofs->lowerpaths[i]);
+       kfree(ofs->lowerpaths);
        for (i = 0; i < ofs->numlower; i++)
                mntput(ofs->lower_layers[i].mnt);
        for (i = 0; i < ofs->numlowerfs; i++
@@ -1358,21 +1369,21 @@ static struct ovl_entry *ovl_get_lowerstack(struct 
super_block *sb,
                sb->s_d_op = &ovl_dentry_operations.ops;
out:
-       for (i = 0; i < numlower; i++)
-               path_put(&stack[i]);
-       kfree(stack);
        kfree(lowertmp);
return oe; out_err:
+       for (i = 0; i < numlower; i++)
+               path_put_init(&ofs->lowerpaths[i]);
+       kfree(ofs->lowerpaths);
+       ofs->lowerpaths = NULL;
        oe = ERR_PTR(err);
        goto out;
  }
static int ovl_fill_super(struct super_block *sb, void *data, int silent)
  {
-       struct path upperpath = { };
        struct dentry *root_dentry;
        struct ovl_entry *oe;
        struct ovl_fs *ofs;


--
Best regards, Tikhomirov Pavel
Software Developer, Virtuozzo.
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to