lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 19 Oct 2018 18:35:50 +0100
From:   Alan Jenkins <alan.christopher.jenkins@...il.com>
To:     David Howells <dhowells@...hat.com>, viro@...iv.linux.org.uk
Cc:     torvalds@...ux-foundation.org, ebiederm@...ssion.com,
        linux-fsdevel@...r.kernel.org, linux-kernel@...r.kernel.org,
        mszeredi@...hat.com
Subject: Re: [PATCH 03/34] teach move_mount(2) to work with OPEN_TREE_CLONE
 [ver #12]

On 19/10/2018 14:37, David Howells wrote:
> Alan Jenkins <alan.christopher.jenkins@...il.com> wrote:
>
>> If I close() the mount FD "mfd", and then do "mount --move . /mnt", my
>> printk() shows MNT_UMOUNT has been set. ( I guess fchdir() works more like
>> openat(... , O_PATH) than dup() ). Then unmounting /mnt hangs, as I would
>> expect from my previous test.
> Okay, I think the attached should fix it.
>
> The issue being that do_move_mount() calls attach_recursive_mnt() with a NULL
> parent_path, which means that the moved-mount doesn't get its refcount
> incremented.
>
> David
> ---
> diff --git a/fs/namespace.c b/fs/namespace.c
> index 6370bfabec99..ce9fff980549 100644
> --- a/fs/namespace.c
> +++ b/fs/namespace.c
> @@ -1935,7 +1935,8 @@ int count_mounts(struct mnt_namespace *ns, struct mount *mnt)
>   static int attach_recursive_mnt(struct mount *source_mnt,
>   			struct mount *dest_mnt,
>   			struct mountpoint *dest_mp,
> -			struct path *parent_path)
> +			struct path *parent_path,
> +			bool moving)
>   {
>   	HLIST_HEAD(tree_list);
>   	struct mnt_namespace *ns = dest_mnt->mnt_ns;
> @@ -1976,6 +1977,8 @@ static int attach_recursive_mnt(struct mount *source_mnt,
>   		attach_mnt(source_mnt, dest_mnt, dest_mp);
>   		touch_mnt_namespace(source_mnt->mnt_ns);
>   	} else {
> +		if (moving)
> +			mnt_add_count(source_mnt, 1);
>   		mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt);
>   		commit_tree(source_mnt);
>   	}
> @@ -2062,7 +2065,7 @@ static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp)
>   	      d_is_dir(mnt->mnt.mnt_root))
>   		return -ENOTDIR;
>   
> -	return attach_recursive_mnt(mnt, p, mp, NULL);
> +	return attach_recursive_mnt(mnt, p, mp, NULL, false);
>   }
>   
>   /*
> @@ -2522,7 +2525,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
>   			goto out1;
>   
>   	err = attach_recursive_mnt(old, real_mount(new_path->mnt), mp,
> -				   attached ? &parent_path : NULL);
> +				   attached ? &parent_path : NULL, true);
>   	if (err)
>   		goto out1;
>   

I guess this tries to fix the second of the two sequences I mentioned - 
mount+unmount, then close the FD.  It doesn't seem to work.

# open_tree_clone 3</mnt 3 sh
# cd /proc/self/fd/3
# mount --move . /mnt
[   41.747831] mnt_flags=1020 umount=0
# cd /
# umount /mnt
umount: /mnt: target is busy

^ a newly introduced bug? I do not remember having this problem before.

# umount -l /mnt
# exec 3<&-  # close FD 3
[   95.984094] watchdog: BUG: soft lockup - CPU#1 stuck for 22s! [sh:1423]
...
[   96.000032] RIP: 0010:pin_kill+0x128/0x140

And the first sequence I mentioned - close the FD, then mount+unmount - 
seems to be unchanged.

# open_tree_clone 3</mnt 3 sh
# cd /proc/self/fd/3
# exec 3<&-  # close FD 3
# mount --move . /mnt
[   76.175127] mnt_flags=8000020 umount=1
# cd /
# umount /mnt
watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [umount:1472]
...
RIP: 0010:pin_kill+0x128/0x140

The close-then-mount test seemed to be solved by the diff you suggested 
earlier.

diff --git a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2469,7 +2469,7 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
  	if (old->mnt_ns && !attached)
  		goto out1;
  
-	if (old->mnt.mnt_flags & MNT_LOCKED)
+	if (old->mnt.mnt_flags & (MNT_LOCKED | MNT_UMOUNT))
  		goto out1;
  
  	if (old_path->dentry != old_path->mnt->mnt_root)

If we can do that, then is it possible to solve mount-unmount-close the 
same way?

@@ -1763,7 +1763,7 @@ void dissolve_on_fput(struct vfsmount *mnt)
  {
  	namespace_lock();
  	lock_mount_hash();
-	if (!real_mount(mnt)->mnt_ns) {
+	if (!real_mount(mnt)->mnt_ns && !(mnt->mnt_flags & MNT_UMOUNT)) {
  		mntget(mnt);
  		umount_tree(real_mount(mnt), UMOUNT_CONNECTED);
  	}

Regards

Alan

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ