On 22.09.2016 03:15, Maxim Patlasov wrote:
> struct file holds references on its f_path.mnt and f_path.dentry by calling
> path_get(&f->f_path) from do_dentry_open(). Let's use the same technique
> for f->f_original_path. Otherwise, f_original_path.dentry can be deleted while
> file still references it leading to NULL-ptr-deref on 
> f->f_original_path.dentry->d_inode.
> 
> https://jira.sw.ru/browse/PSBM-52373
> 
> Signed-off-by: Maxim Patlasov <mpatla...@virtuozzo.com>

Reviewed-by: Kirill Tkhai <ktk...@virtuozzo.com>

> ---
>  fs/file_table.c |    6 ++++++
>  fs/open.c       |   18 +++++++++++++++---
>  2 files changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/fs/file_table.c b/fs/file_table.c
> index 957c476..b8982d8 100644
> --- a/fs/file_table.c
> +++ b/fs/file_table.c
> @@ -242,6 +242,8 @@ static void __fput(struct file *file)
>       struct dentry *dentry = file->f_path.dentry;
>       struct vfsmount *mnt = file->f_path.mnt;
>       struct inode *inode = dentry->d_inode;
> +     struct dentry *original_dentry = file->f_original_path.dentry;
> +     struct vfsmount *original_mnt = file->f_original_path.mnt;
>  
>       might_sleep();
>  
> @@ -273,10 +275,14 @@ static void __fput(struct file *file)
>               drop_file_write_access(file);
>       file->f_path.dentry = NULL;
>       file->f_path.mnt = NULL;
> +     file->f_original_path.dentry = NULL;
> +     file->f_original_path.mnt = NULL;
>       file->f_inode = NULL;
>       file_free(file);
>       dput(dentry);
>       mntput(mnt);
> +     dput(original_dentry);
> +     mntput(original_mnt);
>  }
>  
>  static DEFINE_SPINLOCK(delayed_fput_lock);
> diff --git a/fs/open.c b/fs/open.c
> index 8c066b1..25dbc85 100644
> --- a/fs/open.c
> +++ b/fs/open.c
> @@ -893,16 +893,28 @@ int vfs_open(const struct path *path, struct file *filp,
>  {
>       struct inode *inode = path->dentry->d_inode;
>       iop_dentry_open_t dentry_open = get_dentry_open_iop(inode);
> +     int do_cleanup = 0;
> +     int ret;
>  
> -     if (!filp->f_original_path.mnt)
> +     if (!filp->f_original_path.mnt) {
>               filp->f_original_path = *path;
> +             path_get(&filp->f_original_path);
> +             do_cleanup = 1;
> +     }
>  
>       if (dentry_open)
> -             return dentry_open(path->dentry, filp, cred);
> +             ret = dentry_open(path->dentry, filp, cred);
>       else {
>               filp->f_path = *path;
> -             return do_dentry_open(filp, NULL, cred);
> +             ret = do_dentry_open(filp, NULL, cred);
>       }
> +
> +     if (ret && do_cleanup) {
> +             path_put(&filp->f_original_path);
> +             filp->f_original_path.mnt = NULL;
> +             filp->f_original_path.dentry = NULL;
> +     }
> +     return ret;
>  }
>  EXPORT_SYMBOL(vfs_open);
>  
> 
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to