[Devel] [PATCH v7 1/2] overlayfs: add dynamic path resolving in mount options
Pavel Tikhomirov
ptikhomirov at virtuozzo.com
Thu Jun 4 11:08:42 MSK 2020
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 <alexander.mikhalitsyn at virtuozzo.com>
> 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.
More information about the Devel
mailing list