All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] vfs: Fix use-after-free of vfsmount by mnt_drop_write()
@ 2010-02-22 18:03 OGAWA Hirofumi
  2010-02-22 20:54 ` Valerie Aurora
  0 siblings, 1 reply; 3+ messages in thread
From: OGAWA Hirofumi @ 2010-02-22 18:03 UTC (permalink / raw)
  To: Al Viro; +Cc: linux-kernel, linux-fsdevel

Hi,

Please review this. (This originally was for #untested branch, so this is
not minimal change perfectly.)



Those might be assuming that the nd->path.mnt refcnt is keeped by
filp after nameidata_to_filp().

It's wrong if nameidata_to_filp() returned the error.  (nd->path and
filp are invalid)

Instead to use deep knowledge of nameidata_to_filp() internal, this
thinks the nd->path is invalid after nameidata_to_filp(). So, this
just take refcnt for mnt_want/drop_write().

Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
---

 fs/namei.c |   35 +++++++++++++++++++++++------------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff -puN fs/namei.c~nameidata_to_filp-mount-writer-fix fs/namei.c
--- linux-2.6/fs/namei.c~nameidata_to_filp-mount-writer-fix	2010-02-22 23:22:26.000000000 +0900
+++ linux-2.6-hirofumi/fs/namei.c	2010-02-22 23:59:34.000000000 +0900
@@ -1617,6 +1617,7 @@ struct file *do_filp_open(int dfd, const
 	struct path path;
 	struct dentry *dir;
 	int count = 0;
+	struct vfsmount *uninitialized_var(mnt_writer);
 	int will_truncate;
 	int flag = open_to_namei_flags(open_flag);
 	int force_reval = 0;
@@ -1733,16 +1734,20 @@ do_last:
 		 * a permanent write count is taken through
 		 * the 'struct file' in nameidata_to_filp().
 		 */
-		error = mnt_want_write(nd.path.mnt);
+		mnt_writer = nd.path.mnt;
+		error = mnt_want_write(mnt_writer);
 		if (error)
 			goto exit_mutex_unlock;
 		error = __open_namei_create(&nd, &path, flag, mode);
 		if (error) {
-			mnt_drop_write(nd.path.mnt);
+			mnt_drop_write(mnt_writer);
 			goto exit;
 		}
+		mntget(mnt_writer);
+		/* nd->path is invalid after this */
 		filp = nameidata_to_filp(&nd);
-		mnt_drop_write(nd.path.mnt);
+		mnt_drop_write(mnt_writer);
+		mntput(mnt_writer);
 		if (nd.root.mnt)
 			path_put(&nd.root);
 		if (!IS_ERR(filp)) {
@@ -1794,16 +1799,20 @@ ok:
 	 */
 	will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode);
 	if (will_truncate) {
-		error = mnt_want_write(nd.path.mnt);
+		mnt_writer = nd.path.mnt;
+		error = mnt_want_write(mnt_writer);
 		if (error)
 			goto exit;
 	}
 	error = may_open(&nd.path, acc_mode, flag);
 	if (error) {
 		if (will_truncate)
-			mnt_drop_write(nd.path.mnt);
+			mnt_drop_write(mnt_writer);
 		goto exit;
 	}
+	if (will_truncate)
+		mntget(mnt_writer);
+	/* nd->path is invalid after this */
 	filp = nameidata_to_filp(&nd);
 	if (!IS_ERR(filp)) {
 		error = ima_file_check(filp, acc_mode);
@@ -1814,10 +1823,10 @@ ok:
 	}
 	if (!IS_ERR(filp)) {
 		if (acc_mode & MAY_WRITE)
-			vfs_dq_init(nd.path.dentry->d_inode);
+			vfs_dq_init(filp->f_path.dentry->d_inode);
 
 		if (will_truncate) {
-			error = handle_truncate(&nd.path);
+			error = handle_truncate(&filp->f_path);
 			if (error) {
 				fput(filp);
 				filp = ERR_PTR(error);
@@ -1825,12 +1834,14 @@ ok:
 		}
 	}
 	/*
-	 * It is now safe to drop the mnt write
-	 * because the filp has had a write taken
-	 * on its behalf.
+	 * It is now safe to drop the mnt write because the filp has
+	 * had a write taken on its behalf. (NOTE: since O_TRUNC can
+	 * be used with O_RDONLY, this needs to cover truncate path)
 	 */
-	if (will_truncate)
-		mnt_drop_write(nd.path.mnt);
+	if (will_truncate) {
+		mnt_drop_write(mnt_writer);
+		mntput(mnt_writer);
+	}
 	if (nd.root.mnt)
 		path_put(&nd.root);
 	return filp;
_

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] vfs: Fix use-after-free of vfsmount by mnt_drop_write()
  2010-02-22 18:03 [PATCH] vfs: Fix use-after-free of vfsmount by mnt_drop_write() OGAWA Hirofumi
@ 2010-02-22 20:54 ` Valerie Aurora
  2010-02-22 21:13   ` OGAWA Hirofumi
  0 siblings, 1 reply; 3+ messages in thread
From: Valerie Aurora @ 2010-02-22 20:54 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: Al Viro, linux-kernel, linux-fsdevel

On Tue, Feb 23, 2010 at 03:03:28AM +0900, OGAWA Hirofumi wrote:
> Hi,
> 
> Please review this. (This originally was for #untested branch, so this is
> not minimal change perfectly.)
> 
> 
> 
> Those might be assuming that the nd->path.mnt refcnt is keeped by
> filp after nameidata_to_filp().
> 
> It's wrong if nameidata_to_filp() returned the error.  (nd->path and
> filp are invalid)
> 
> Instead to use deep knowledge of nameidata_to_filp() internal, this
> thinks the nd->path is invalid after nameidata_to_filp(). So, this
> just take refcnt for mnt_want/drop_write().

You might take a look at the patch I just posted:

Subject: [RFC PATCH] VFS: Simplify truncate logic in do_filp_open()

If that patch is correct, it will considerably simplify the second
part of your patch.

-VAL

> 
> Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
> ---
> 
>  fs/namei.c |   35 +++++++++++++++++++++++------------
>  1 file changed, 23 insertions(+), 12 deletions(-)
> 
> diff -puN fs/namei.c~nameidata_to_filp-mount-writer-fix fs/namei.c
> --- linux-2.6/fs/namei.c~nameidata_to_filp-mount-writer-fix	2010-02-22 23:22:26.000000000 +0900
> +++ linux-2.6-hirofumi/fs/namei.c	2010-02-22 23:59:34.000000000 +0900
> @@ -1617,6 +1617,7 @@ struct file *do_filp_open(int dfd, const
>  	struct path path;
>  	struct dentry *dir;
>  	int count = 0;
> +	struct vfsmount *uninitialized_var(mnt_writer);
>  	int will_truncate;
>  	int flag = open_to_namei_flags(open_flag);
>  	int force_reval = 0;
> @@ -1733,16 +1734,20 @@ do_last:
>  		 * a permanent write count is taken through
>  		 * the 'struct file' in nameidata_to_filp().
>  		 */
> -		error = mnt_want_write(nd.path.mnt);
> +		mnt_writer = nd.path.mnt;
> +		error = mnt_want_write(mnt_writer);
>  		if (error)
>  			goto exit_mutex_unlock;
>  		error = __open_namei_create(&nd, &path, flag, mode);
>  		if (error) {
> -			mnt_drop_write(nd.path.mnt);
> +			mnt_drop_write(mnt_writer);
>  			goto exit;
>  		}
> +		mntget(mnt_writer);
> +		/* nd->path is invalid after this */
>  		filp = nameidata_to_filp(&nd);
> -		mnt_drop_write(nd.path.mnt);
> +		mnt_drop_write(mnt_writer);
> +		mntput(mnt_writer);
>  		if (nd.root.mnt)
>  			path_put(&nd.root);
>  		if (!IS_ERR(filp)) {
> @@ -1794,16 +1799,20 @@ ok:
>  	 */
>  	will_truncate = open_will_truncate(flag, nd.path.dentry->d_inode);
>  	if (will_truncate) {
> -		error = mnt_want_write(nd.path.mnt);
> +		mnt_writer = nd.path.mnt;
> +		error = mnt_want_write(mnt_writer);
>  		if (error)
>  			goto exit;
>  	}
>  	error = may_open(&nd.path, acc_mode, flag);
>  	if (error) {
>  		if (will_truncate)
> -			mnt_drop_write(nd.path.mnt);
> +			mnt_drop_write(mnt_writer);
>  		goto exit;
>  	}
> +	if (will_truncate)
> +		mntget(mnt_writer);
> +	/* nd->path is invalid after this */
>  	filp = nameidata_to_filp(&nd);
>  	if (!IS_ERR(filp)) {
>  		error = ima_file_check(filp, acc_mode);
> @@ -1814,10 +1823,10 @@ ok:
>  	}
>  	if (!IS_ERR(filp)) {
>  		if (acc_mode & MAY_WRITE)
> -			vfs_dq_init(nd.path.dentry->d_inode);
> +			vfs_dq_init(filp->f_path.dentry->d_inode);
>  
>  		if (will_truncate) {
> -			error = handle_truncate(&nd.path);
> +			error = handle_truncate(&filp->f_path);
>  			if (error) {
>  				fput(filp);
>  				filp = ERR_PTR(error);
> @@ -1825,12 +1834,14 @@ ok:
>  		}
>  	}
>  	/*
> -	 * It is now safe to drop the mnt write
> -	 * because the filp has had a write taken
> -	 * on its behalf.
> +	 * It is now safe to drop the mnt write because the filp has
> +	 * had a write taken on its behalf. (NOTE: since O_TRUNC can
> +	 * be used with O_RDONLY, this needs to cover truncate path)
>  	 */
> -	if (will_truncate)
> -		mnt_drop_write(nd.path.mnt);
> +	if (will_truncate) {
> +		mnt_drop_write(mnt_writer);
> +		mntput(mnt_writer);
> +	}
>  	if (nd.root.mnt)
>  		path_put(&nd.root);
>  	return filp;
> _
> 
> -- 
> OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] vfs: Fix use-after-free of vfsmount by mnt_drop_write()
  2010-02-22 20:54 ` Valerie Aurora
@ 2010-02-22 21:13   ` OGAWA Hirofumi
  0 siblings, 0 replies; 3+ messages in thread
From: OGAWA Hirofumi @ 2010-02-22 21:13 UTC (permalink / raw)
  To: Valerie Aurora; +Cc: Al Viro, linux-kernel, linux-fsdevel

Valerie Aurora <vaurora@redhat.com> writes:

>> Those might be assuming that the nd->path.mnt refcnt is keeped by
>> filp after nameidata_to_filp().
>> 
>> It's wrong if nameidata_to_filp() returned the error.  (nd->path and
>> filp are invalid)
>> 
>> Instead to use deep knowledge of nameidata_to_filp() internal, this
>> thinks the nd->path is invalid after nameidata_to_filp(). So, this
>> just take refcnt for mnt_want/drop_write().
>
> You might take a look at the patch I just posted:
>
> Subject: [RFC PATCH] VFS: Simplify truncate logic in do_filp_open()
>
> If that patch is correct, it will considerably simplify the second
> part of your patch.

[...]
>>  	/*
>> -	 * It is now safe to drop the mnt write
>> -	 * because the filp has had a write taken
>> -	 * on its behalf.
>> +	 * It is now safe to drop the mnt write because the filp has
>> +	 * had a write taken on its behalf. (NOTE: since O_TRUNC can
>> +	 * be used with O_RDONLY, this needs to cover truncate path)
>>  	 */
>> -	if (will_truncate)
>> -		mnt_drop_write(nd.path.mnt);
>> +	if (will_truncate) {
>> +		mnt_drop_write(mnt_writer);
>> +		mntput(mnt_writer);
>> +	}

Unfortunately, no. I already noted that we can't it simply. ;)

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-02-22 21:14 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-22 18:03 [PATCH] vfs: Fix use-after-free of vfsmount by mnt_drop_write() OGAWA Hirofumi
2010-02-22 20:54 ` Valerie Aurora
2010-02-22 21:13   ` OGAWA Hirofumi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.