linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] swap: fix set_blocksize race during swapon/swapoff
@ 2013-10-11  9:54 Krzysztof Kozlowski
  2013-10-11 18:55 ` Andrew Morton
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Krzysztof Kozlowski @ 2013-10-11  9:54 UTC (permalink / raw)
  To: Andrew Morton, linux-kernel, linux-mm
  Cc: Weijie Yang, Bob Liu, Konrad Rzeszutek Wilk, Shaohua Li,
	Minchan Kim, Krzysztof Kozlowski

Swapoff used old_block_size from swap_info which could be overwritten by
concurrent swapon.

Reported-by: Weijie Yang <weijie.yang.kh@gmail.com>
Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
---
 mm/swapfile.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/mm/swapfile.c b/mm/swapfile.c
index 3963fc2..de7c904 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
 	struct filename *pathname;
 	int i, type, prev;
 	int err;
+	unsigned int old_block_size;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
 	}
 
 	swap_file = p->swap_file;
+	old_block_size = p->old_block_size;
 	p->swap_file = NULL;
 	p->max = 0;
 	swap_map = p->swap_map;
@@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
 	inode = mapping->host;
 	if (S_ISBLK(inode->i_mode)) {
 		struct block_device *bdev = I_BDEV(inode);
-		set_blocksize(bdev, p->old_block_size);
+		set_blocksize(bdev, old_block_size);
 		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
 	} else {
 		mutex_lock(&inode->i_mutex);
-- 
1.7.9.5

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

* Re: [PATCH] swap: fix set_blocksize race during swapon/swapoff
  2013-10-11  9:54 [PATCH] swap: fix set_blocksize race during swapon/swapoff Krzysztof Kozlowski
@ 2013-10-11 18:55 ` Andrew Morton
  2013-10-14 10:19   ` Krzysztof Kozlowski
  2013-10-11 19:02 ` Andrew Morton
  2013-10-15  9:45 ` Hugh Dickins
  2 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2013-10-11 18:55 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-kernel, linux-mm, Weijie Yang, Bob Liu,
	Konrad Rzeszutek Wilk, Shaohua Li, Minchan Kim

On Fri, 11 Oct 2013 11:54:22 +0200 Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:

> Swapoff used old_block_size from swap_info which could be overwritten by
> concurrent swapon.

Better changelogs, please.  What were the user-visible effects of the
bug, and how is it triggered?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

* Re: [PATCH] swap: fix set_blocksize race during swapon/swapoff
  2013-10-11  9:54 [PATCH] swap: fix set_blocksize race during swapon/swapoff Krzysztof Kozlowski
  2013-10-11 18:55 ` Andrew Morton
@ 2013-10-11 19:02 ` Andrew Morton
  2013-10-14  9:47   ` Krzysztof Kozlowski
  2013-10-15  9:56   ` Hugh Dickins
  2013-10-15  9:45 ` Hugh Dickins
  2 siblings, 2 replies; 7+ messages in thread
From: Andrew Morton @ 2013-10-11 19:02 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-kernel, linux-mm, Weijie Yang, Bob Liu,
	Konrad Rzeszutek Wilk, Shaohua Li, Minchan Kim, Hugh Dickins

(cc Hugh)

On Fri, 11 Oct 2013 11:54:22 +0200 Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:

> Swapoff used old_block_size from swap_info which could be overwritten by
> concurrent swapon.
> 
> Reported-by: Weijie Yang <weijie.yang.kh@gmail.com>
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> ---
>  mm/swapfile.c |    4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 3963fc2..de7c904 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
>  	struct filename *pathname;
>  	int i, type, prev;
>  	int err;
> +	unsigned int old_block_size;
>  
>  	if (!capable(CAP_SYS_ADMIN))
>  		return -EPERM;
> @@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
>  	}
>  
>  	swap_file = p->swap_file;
> +	old_block_size = p->old_block_size;
>  	p->swap_file = NULL;
>  	p->max = 0;
>  	swap_map = p->swap_map;
> @@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
>  	inode = mapping->host;
>  	if (S_ISBLK(inode->i_mode)) {
>  		struct block_device *bdev = I_BDEV(inode);
> -		set_blocksize(bdev, p->old_block_size);
> +		set_blocksize(bdev, old_block_size);
>  		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
>  	} else {
>  		mutex_lock(&inode->i_mutex);

I find it worrying that a swapon can run concurrently with any of this
swapoff code.  It just seem to be asking for trouble and the code
really isn't set up for this and races here will be poorly tested for

I'm wondering if we should just extend swapon_mutex a lot and eliminate
the concurrency?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

* Re: [PATCH] swap: fix set_blocksize race during swapon/swapoff
  2013-10-11 19:02 ` Andrew Morton
@ 2013-10-14  9:47   ` Krzysztof Kozlowski
  2013-10-15  9:56   ` Hugh Dickins
  1 sibling, 0 replies; 7+ messages in thread
From: Krzysztof Kozlowski @ 2013-10-14  9:47 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, linux-mm, Weijie Yang, Bob Liu,
	Konrad Rzeszutek Wilk, Shaohua Li, Minchan Kim, Hugh Dickins

On Fri, 2013-10-11 at 12:02 -0700, Andrew Morton wrote:
> (cc Hugh)
> 
> On Fri, 11 Oct 2013 11:54:22 +0200 Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:
> 
> > Swapoff used old_block_size from swap_info which could be overwritten by
> > concurrent swapon.
> > 
> > Reported-by: Weijie Yang <weijie.yang.kh@gmail.com>
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> > ---
> >  mm/swapfile.c |    4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/mm/swapfile.c b/mm/swapfile.c
> > index 3963fc2..de7c904 100644
> > --- a/mm/swapfile.c
> > +++ b/mm/swapfile.c
> > @@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
> >  	struct filename *pathname;
> >  	int i, type, prev;
> >  	int err;
> > +	unsigned int old_block_size;
> >  
> >  	if (!capable(CAP_SYS_ADMIN))
> >  		return -EPERM;
> > @@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
> >  	}
> >  
> >  	swap_file = p->swap_file;
> > +	old_block_size = p->old_block_size;
> >  	p->swap_file = NULL;
> >  	p->max = 0;
> >  	swap_map = p->swap_map;
> > @@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
> >  	inode = mapping->host;
> >  	if (S_ISBLK(inode->i_mode)) {
> >  		struct block_device *bdev = I_BDEV(inode);
> > -		set_blocksize(bdev, p->old_block_size);
> > +		set_blocksize(bdev, old_block_size);
> >  		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
> >  	} else {
> >  		mutex_lock(&inode->i_mutex);
> 
> I find it worrying that a swapon can run concurrently with any of this
> swapoff code.  It just seem to be asking for trouble and the code
> really isn't set up for this and races here will be poorly tested for
> 
> I'm wondering if we should just extend swapon_mutex a lot and eliminate
> the concurrency?

It seems there are even more races here between swapoff & swapon (and
swapon with swapon). Simple script:
	for i in `seq 1000`
	do
		swapoff -a &
		swapon -a &
	done
causes frequent switches of block size of devices (jumping from 512 to 4096).


Best regards,
Krzysztof



--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

* Re: [PATCH] swap: fix set_blocksize race during swapon/swapoff
  2013-10-11 18:55 ` Andrew Morton
@ 2013-10-14 10:19   ` Krzysztof Kozlowski
  0 siblings, 0 replies; 7+ messages in thread
From: Krzysztof Kozlowski @ 2013-10-14 10:19 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-kernel, linux-mm, Weijie Yang, Bob Liu,
	Konrad Rzeszutek Wilk, Shaohua Li, Minchan Kim

On Fri, 2013-10-11 at 11:55 -0700, Andrew Morton wrote:
> On Fri, 11 Oct 2013 11:54:22 +0200 Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:
> 
> > Swapoff used old_block_size from swap_info which could be overwritten by
> > concurrent swapon.
> 
> Better changelogs, please.  What were the user-visible effects of the
> bug, and how is it triggered?
Let me update a little the changelog:
--------
Fix race between swapoff and swapon. Swapoff used old_block_size from
swap_info outside of swapon_mutex so it could be overwritten by
concurrent swapon.

The race has visible effect only if more than one swap block device
exists with different block sizes (e.g. /dev/sda1 with block size 4096
and /dev/sdb1 with 512). In such case it leads to setting the blocksize
of swapped off device with wrong blocksize.

The bug can be triggered with multiple concurrent swapoff and swapon:
0. Swap for some device is on.
1. swapoff:
First the swapoff is called on this device and "struct swap_info_struct
*p" is assigned. This is done under swap_lock however this lock is
released for the call try_to_unuse().

2. swapon:
After the assignment above (and before acquiring swapon_mutex &
swap_lock by swapoff) the swapon is called on the same device.
The p->old_block_size is assigned to the value of block_size the device.
This block size should be the same as previous but sometimes it is not.
The swapon ends successfully.

3. swapoff:
Swapoff resumes, grabs the locks and mutex and continues to disable this
swap device. Now it sets the block size to value taken from swap_info
which was overwritten by swapon in 2.
--------

Best regards,
Krzysztof

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

* Re: [PATCH] swap: fix set_blocksize race during swapon/swapoff
  2013-10-11  9:54 [PATCH] swap: fix set_blocksize race during swapon/swapoff Krzysztof Kozlowski
  2013-10-11 18:55 ` Andrew Morton
  2013-10-11 19:02 ` Andrew Morton
@ 2013-10-15  9:45 ` Hugh Dickins
  2 siblings, 0 replies; 7+ messages in thread
From: Hugh Dickins @ 2013-10-15  9:45 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Andrew Morton, linux-kernel, linux-mm, Weijie Yang, Bob Liu,
	Konrad Rzeszutek Wilk, Shaohua Li, Minchan Kim

On Fri, 11 Oct 2013, Krzysztof Kozlowski wrote:

> Swapoff used old_block_size from swap_info which could be overwritten by
> concurrent swapon.
> 
> Reported-by: Weijie Yang <weijie.yang.kh@gmail.com>
> Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Acked-by: Hugh Dickins <hughd@google.com>

Yes, this is straightforward: it was relying on p->old_block_size
after it had given up its hold on *p: a use-after-free (though
those slots are not freed back to a lower-level allocator).

What is not obvious is why swapon needs to use set_blocksize() at all:
if I knew once upon a time, I've forgotten now: because a bdev starts
out with blocksize 0 and someone needs to set it non-0??

> ---
>  mm/swapfile.c |    4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index 3963fc2..de7c904 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
>  	struct filename *pathname;
>  	int i, type, prev;
>  	int err;
> +	unsigned int old_block_size;
>  
>  	if (!capable(CAP_SYS_ADMIN))
>  		return -EPERM;
> @@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
>  	}
>  
>  	swap_file = p->swap_file;
> +	old_block_size = p->old_block_size;
>  	p->swap_file = NULL;
>  	p->max = 0;
>  	swap_map = p->swap_map;
> @@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
>  	inode = mapping->host;
>  	if (S_ISBLK(inode->i_mode)) {
>  		struct block_device *bdev = I_BDEV(inode);
> -		set_blocksize(bdev, p->old_block_size);
> +		set_blocksize(bdev, old_block_size);
>  		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
>  	} else {
>  		mutex_lock(&inode->i_mutex);
> -- 
> 1.7.9.5

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

* Re: [PATCH] swap: fix set_blocksize race during swapon/swapoff
  2013-10-11 19:02 ` Andrew Morton
  2013-10-14  9:47   ` Krzysztof Kozlowski
@ 2013-10-15  9:56   ` Hugh Dickins
  1 sibling, 0 replies; 7+ messages in thread
From: Hugh Dickins @ 2013-10-15  9:56 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Krzysztof Kozlowski, linux-kernel, linux-mm, Weijie Yang, Bob Liu,
	Konrad Rzeszutek Wilk, Shaohua Li, Minchan Kim, Hugh Dickins

On Fri, 11 Oct 2013, Andrew Morton wrote:
> (cc Hugh)

Thank you: I'm sorry, but I have difficulty finding a moment to look.

> 
> On Fri, 11 Oct 2013 11:54:22 +0200 Krzysztof Kozlowski <k.kozlowski@samsung.com> wrote:
> 
> > Swapoff used old_block_size from swap_info which could be overwritten by
> > concurrent swapon.
> > 
> > Reported-by: Weijie Yang <weijie.yang.kh@gmail.com>
> > Signed-off-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>
> > ---
> >  mm/swapfile.c |    4 +++-
> >  1 file changed, 3 insertions(+), 1 deletion(-)
> > 
> > diff --git a/mm/swapfile.c b/mm/swapfile.c
> > index 3963fc2..de7c904 100644
> > --- a/mm/swapfile.c
> > +++ b/mm/swapfile.c
> > @@ -1824,6 +1824,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
> >  	struct filename *pathname;
> >  	int i, type, prev;
> >  	int err;
> > +	unsigned int old_block_size;
> >  
> >  	if (!capable(CAP_SYS_ADMIN))
> >  		return -EPERM;
> > @@ -1914,6 +1915,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
> >  	}
> >  
> >  	swap_file = p->swap_file;
> > +	old_block_size = p->old_block_size;
> >  	p->swap_file = NULL;
> >  	p->max = 0;
> >  	swap_map = p->swap_map;
> > @@ -1938,7 +1940,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
> >  	inode = mapping->host;
> >  	if (S_ISBLK(inode->i_mode)) {
> >  		struct block_device *bdev = I_BDEV(inode);
> > -		set_blocksize(bdev, p->old_block_size);
> > +		set_blocksize(bdev, old_block_size);
> >  		blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
> >  	} else {
> >  		mutex_lock(&inode->i_mutex);
> 
> I find it worrying that a swapon can run concurrently with any of this
> swapoff code.  It just seem to be asking for trouble and the code
> really isn't set up for this and races here will be poorly tested for
> 
> I'm wondering if we should just extend swapon_mutex a lot and eliminate
> the concurrency?

I have to disagree with you on this.  We do not hold swapon_mutex from 
start to finish of usage of a swap_info_struct, and there's no call to
rearrange swapon_mutex usage for this case.  It's just a straightforward
use of p->old_block_size shortly after *p was freed, and Krzysztof's
original patch was the appropriate one.  As for more verbiage, well,
I'm not so sure that more is better in this case: whichever you find
easier to understand.

Hugh

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

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

end of thread, other threads:[~2013-10-15  9:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-11  9:54 [PATCH] swap: fix set_blocksize race during swapon/swapoff Krzysztof Kozlowski
2013-10-11 18:55 ` Andrew Morton
2013-10-14 10:19   ` Krzysztof Kozlowski
2013-10-11 19:02 ` Andrew Morton
2013-10-14  9:47   ` Krzysztof Kozlowski
2013-10-15  9:56   ` Hugh Dickins
2013-10-15  9:45 ` Hugh Dickins

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).