On Thu, Jun 13, 2019 at 10:47:28AM +0200, Miklos Szeredi wrote:
> On Wed, Jun 12, 2019 at 11:43:13AM -0700, Eric Biggers wrote:
> > From: Eric Biggers <ebigg...@google.com>
> > 
> > sys_fsmount() needs to take a reference to the new mount when adding it
> > to the anonymous mount namespace.  Otherwise the filesystem can be
> > unmounted while it's still in use, as found by syzkaller.
> 
> So it needs one count for the file (which dentry_open() obtains) and one for 
> the
> attachment into the anonymous namespace.  The latter one is dropped at cleanup
> time, so your patch appears to be correct at getting that ref.
> 
> I wonder why such a blatant use-after-free was missed in normal testing.  RCU
> delayed freeing, I guess?
> 
> How about this additional sanity checking patch?
> 
> Thanks,
> Miklos
> 
> 
> diff --git a/fs/namespace.c b/fs/namespace.c
> index b26778bdc236..c638f220805a 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -153,10 +153,10 @@ static inline void mnt_add_count(struct mount *mnt, int 
> n)
>  /*
>   * vfsmount lock must be held for write
>   */
> -unsigned int mnt_get_count(struct mount *mnt)
> +int mnt_get_count(struct mount *mnt)
>  {
>  #ifdef CONFIG_SMP
> -     unsigned int count = 0;
> +     int count = 0;
>       int cpu;
>  
>       for_each_possible_cpu(cpu) {
> @@ -1140,6 +1140,8 @@ static DECLARE_DELAYED_WORK(delayed_mntput_work, 
> delayed_mntput);
>  
>  static void mntput_no_expire(struct mount *mnt)
>  {
> +     int count;
> +
>       rcu_read_lock();
>       if (likely(READ_ONCE(mnt->mnt_ns))) {
>               /*
> @@ -1162,11 +1164,13 @@ static void mntput_no_expire(struct mount *mnt)
>        */
>       smp_mb();
>       mnt_add_count(mnt, -1);
> -     if (mnt_get_count(mnt)) {
> +     count = mnt_get_count(mnt);
> +     if (count > 0) {
>               rcu_read_unlock();
>               unlock_mount_hash();
>               return;
>       }
> +     WARN_ON(count < 0);
>       if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) {
>               rcu_read_unlock();
>               unlock_mount_hash();
> diff --git a/fs/pnode.h b/fs/pnode.h
> index 49a058c73e4c..26f74e092bd9 100644
> --- a/fs/pnode.h
> +++ b/fs/pnode.h
> @@ -44,7 +44,7 @@ int propagate_mount_busy(struct mount *, int);
>  void propagate_mount_unlock(struct mount *);
>  void mnt_release_group_id(struct mount *);
>  int get_dominating_id(struct mount *mnt, const struct path *root);
> -unsigned int mnt_get_count(struct mount *mnt);
> +int mnt_get_count(struct mount *mnt);
>  void mnt_set_mountpoint(struct mount *, struct mountpoint *,
>                       struct mount *);
>  void mnt_change_mountpoint(struct mount *parent, struct mountpoint *mp,

Miklos, are you planning to send this as a formal patch?

- Eric

Reply via email to