diff mbox series

[RFC,8/9] orangefs: use set/clear_fs_page_private

Message ID 20200426214925.10970-9-guoqing.jiang@cloud.ionos.com (mailing list archive)
State New, archived
Headers show
Series Introduce set/clear_fs_page_private to cleanup code | expand

Commit Message

Guoqing Jiang April 26, 2020, 9:49 p.m. UTC
Since the new pair function is introduced, we can call them to clean the
code in orangefs.

Cc: Mike Marshall <hubcap@omnibond.com>
Cc: Martin Brandenburg <martin@omnibond.com>
Cc: devel@lists.orangefs.org
Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com>
---
 fs/orangefs/inode.c | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

Comments

Dave Chinner April 26, 2020, 10:24 p.m. UTC | #1
On Sun, Apr 26, 2020 at 11:49:24PM +0200, Guoqing Jiang wrote:
> Since the new pair function is introduced, we can call them to clean the
> code in orangefs.
> 
> Cc: Mike Marshall <hubcap@omnibond.com>
> Cc: Martin Brandenburg <martin@omnibond.com>
> Cc: devel@lists.orangefs.org
> Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com>
> ---
>  fs/orangefs/inode.c | 24 ++++++------------------
>  1 file changed, 6 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
> index 12ae630fbed7..893099d36e20 100644
> --- a/fs/orangefs/inode.c
> +++ b/fs/orangefs/inode.c
> @@ -64,9 +64,7 @@ static int orangefs_writepage_locked(struct page *page,
>  	}
>  	if (wr) {
>  		kfree(wr);
> -		set_page_private(page, 0);
> -		ClearPagePrivate(page);
> -		put_page(page);
> +		clear_fs_page_private(page);

THis is a pre-existing potential use-after-free vector. The wr
pointer held in the page->private needs to be cleared from the page
before it is freed.

>  	}
>  	return ret;
>  }
> @@ -409,9 +407,7 @@ static int orangefs_write_begin(struct file *file,
>  	wr->len = len;
>  	wr->uid = current_fsuid();
>  	wr->gid = current_fsgid();
> -	SetPagePrivate(page);
> -	set_page_private(page, (unsigned long)wr);
> -	get_page(page);
> +	set_fs_page_private(page, wr);
>  okay:
>  	return 0;
>  }
> @@ -460,17 +456,13 @@ static void orangefs_invalidatepage(struct page *page,
>  
>  	if (offset == 0 && length == PAGE_SIZE) {
>  		kfree((struct orangefs_write_range *)page_private(page));
> -		set_page_private(page, 0);
> -		ClearPagePrivate(page);
> -		put_page(page);
> +		clear_fs_page_private(page);

Ditto:
		wr = clear_fs_page_private(page);
		kfree(wr);

>  		return;
>  	/* write range entirely within invalidate range (or equal) */
>  	} else if (page_offset(page) + offset <= wr->pos &&
>  	    wr->pos + wr->len <= page_offset(page) + offset + length) {
>  		kfree((struct orangefs_write_range *)page_private(page));
> -		set_page_private(page, 0);
> -		ClearPagePrivate(page);
> -		put_page(page);
> +		clear_fs_page_private(page);

And again.

>  		/* XXX is this right? only caller in fs */
>  		cancel_dirty_page(page);
>  		return;
> @@ -537,9 +529,7 @@ static void orangefs_freepage(struct page *page)
>  {
>  	if (PagePrivate(page)) {
>  		kfree((struct orangefs_write_range *)page_private(page));
> -		set_page_private(page, 0);
> -		ClearPagePrivate(page);
> -		put_page(page);
> +		clear_fs_page_private(page);

And again.

Cheers,

Dave.
Matthew Wilcox April 27, 2020, 12:12 a.m. UTC | #2
On Mon, Apr 27, 2020 at 08:24:55AM +1000, Dave Chinner wrote:
> > @@ -460,17 +456,13 @@ static void orangefs_invalidatepage(struct page *page,
> >  
> >  	if (offset == 0 && length == PAGE_SIZE) {
> >  		kfree((struct orangefs_write_range *)page_private(page));
> > -		set_page_private(page, 0);
> > -		ClearPagePrivate(page);
> > -		put_page(page);
> > +		clear_fs_page_private(page);
> 
> Ditto:
> 		wr = clear_fs_page_private(page);
> 		kfree(wr);

You don't want to be as succinct as the btrfs change you suggested?

		kfree(clear_fs_page_private(page));
Dave Chinner April 27, 2020, 2:27 a.m. UTC | #3
On Sun, Apr 26, 2020 at 05:12:34PM -0700, Matthew Wilcox wrote:
> On Mon, Apr 27, 2020 at 08:24:55AM +1000, Dave Chinner wrote:
> > > @@ -460,17 +456,13 @@ static void orangefs_invalidatepage(struct page *page,
> > >  
> > >  	if (offset == 0 && length == PAGE_SIZE) {
> > >  		kfree((struct orangefs_write_range *)page_private(page));
> > > -		set_page_private(page, 0);
> > > -		ClearPagePrivate(page);
> > > -		put_page(page);
> > > +		clear_fs_page_private(page);
> > 
> > Ditto:
> > 		wr = clear_fs_page_private(page);
> > 		kfree(wr);
> 
> You don't want to be as succinct as the btrfs change you suggested?
> 
> 		kfree(clear_fs_page_private(page));

That could be done, yes. I was really just trying to point out the
use after free that was occurring here rather than write compact
code...

Cheers,

Dave.
Gao Xiang April 27, 2020, 2:58 a.m. UTC | #4
On Mon, Apr 27, 2020 at 08:24:55AM +1000, Dave Chinner wrote:
> On Sun, Apr 26, 2020 at 11:49:24PM +0200, Guoqing Jiang wrote:
> > Since the new pair function is introduced, we can call them to clean the
> > code in orangefs.
> > 
> > Cc: Mike Marshall <hubcap@omnibond.com>
> > Cc: Martin Brandenburg <martin@omnibond.com>
> > Cc: devel@lists.orangefs.org
> > Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com>
> > ---
> >  fs/orangefs/inode.c | 24 ++++++------------------
> >  1 file changed, 6 insertions(+), 18 deletions(-)
> > 
> > diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
> > index 12ae630fbed7..893099d36e20 100644
> > --- a/fs/orangefs/inode.c
> > +++ b/fs/orangefs/inode.c
> > @@ -64,9 +64,7 @@ static int orangefs_writepage_locked(struct page *page,
> >  	}
> >  	if (wr) {
> >  		kfree(wr);
> > -		set_page_private(page, 0);
> > -		ClearPagePrivate(page);
> > -		put_page(page);
> > +		clear_fs_page_private(page);
> 
> THis is a pre-existing potential use-after-free vector. The wr
> pointer held in the page->private needs to be cleared from the page
> before it is freed.

I'm not familar with orangefs. In my opinion, generally all temporary
page->private access (r/w) should be properly protected by some locks,
most of time I think it could be at least page lock since .migratepage,
.invalidatepage, .releasepage, .. (such paths) are already called with
page locked (honestly I'm interested in this topic, please correct me
if I'm wrong).

I agree that the suggested modification is more clear and easy to read.

Thanks,
Gao Xiang
Gao Xiang April 27, 2020, 3:27 a.m. UTC | #5
On Mon, Apr 27, 2020 at 10:58:02AM +0800, Gao Xiang wrote:
> On Mon, Apr 27, 2020 at 08:24:55AM +1000, Dave Chinner wrote:
> > On Sun, Apr 26, 2020 at 11:49:24PM +0200, Guoqing Jiang wrote:
> > > Since the new pair function is introduced, we can call them to clean the
> > > code in orangefs.
> > > 
> > > Cc: Mike Marshall <hubcap@omnibond.com>
> > > Cc: Martin Brandenburg <martin@omnibond.com>
> > > Cc: devel@lists.orangefs.org
> > > Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com>
> > > ---
> > >  fs/orangefs/inode.c | 24 ++++++------------------
> > >  1 file changed, 6 insertions(+), 18 deletions(-)
> > > 
> > > diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
> > > index 12ae630fbed7..893099d36e20 100644
> > > --- a/fs/orangefs/inode.c
> > > +++ b/fs/orangefs/inode.c
> > > @@ -64,9 +64,7 @@ static int orangefs_writepage_locked(struct page *page,
> > >  	}
> > >  	if (wr) {
> > >  		kfree(wr);
> > > -		set_page_private(page, 0);
> > > -		ClearPagePrivate(page);
> > > -		put_page(page);
> > > +		clear_fs_page_private(page);
> > 
> > THis is a pre-existing potential use-after-free vector. The wr
> > pointer held in the page->private needs to be cleared from the page
> > before it is freed.
> 
> I'm not familar with orangefs. In my opinion, generally all temporary
> page->private access (r/w) should be properly protected by some locks,

... page->private pointers (there may be some other uses rather than
as references). sorry about that...

> most of time I think it could be at least page lock since .migratepage,
> .invalidatepage, .releasepage, .. (such paths) are already called with
> page locked (honestly I'm interested in this topic, please correct me
> if I'm wrong).
> 
> I agree that the suggested modification is more clear and easy to read.
> 
> Thanks,
> Gao Xiang
> 
>
Guoqing Jiang April 27, 2020, 8:18 a.m. UTC | #6
Hi Mattew and Dave,

On 4/27/20 4:27 AM, Dave Chinner wrote:
> On Sun, Apr 26, 2020 at 05:12:34PM -0700, Matthew Wilcox wrote:
>> On Mon, Apr 27, 2020 at 08:24:55AM +1000, Dave Chinner wrote:
>>>> @@ -460,17 +456,13 @@ static void orangefs_invalidatepage(struct page *page,
>>>>   
>>>>   	if (offset == 0 && length == PAGE_SIZE) {
>>>>   		kfree((struct orangefs_write_range *)page_private(page));
>>>> -		set_page_private(page, 0);
>>>> -		ClearPagePrivate(page);
>>>> -		put_page(page);
>>>> +		clear_fs_page_private(page);
>>> Ditto:
>>> 		wr = clear_fs_page_private(page);
>>> 		kfree(wr);
>> You don't want to be as succinct as the btrfs change you suggested?
>>
>> 		kfree(clear_fs_page_private(page));
> That could be done, yes. I was really just trying to point out the
> use after free that was occurring here rather than write compact
> code...

Really appreciate for your review, thanks.

Best Regards,
Guoqing
diff mbox series

Patch

diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index 12ae630fbed7..893099d36e20 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -64,9 +64,7 @@  static int orangefs_writepage_locked(struct page *page,
 	}
 	if (wr) {
 		kfree(wr);
-		set_page_private(page, 0);
-		ClearPagePrivate(page);
-		put_page(page);
+		clear_fs_page_private(page);
 	}
 	return ret;
 }
@@ -409,9 +407,7 @@  static int orangefs_write_begin(struct file *file,
 	wr->len = len;
 	wr->uid = current_fsuid();
 	wr->gid = current_fsgid();
-	SetPagePrivate(page);
-	set_page_private(page, (unsigned long)wr);
-	get_page(page);
+	set_fs_page_private(page, wr);
 okay:
 	return 0;
 }
@@ -460,17 +456,13 @@  static void orangefs_invalidatepage(struct page *page,
 
 	if (offset == 0 && length == PAGE_SIZE) {
 		kfree((struct orangefs_write_range *)page_private(page));
-		set_page_private(page, 0);
-		ClearPagePrivate(page);
-		put_page(page);
+		clear_fs_page_private(page);
 		return;
 	/* write range entirely within invalidate range (or equal) */
 	} else if (page_offset(page) + offset <= wr->pos &&
 	    wr->pos + wr->len <= page_offset(page) + offset + length) {
 		kfree((struct orangefs_write_range *)page_private(page));
-		set_page_private(page, 0);
-		ClearPagePrivate(page);
-		put_page(page);
+		clear_fs_page_private(page);
 		/* XXX is this right? only caller in fs */
 		cancel_dirty_page(page);
 		return;
@@ -537,9 +529,7 @@  static void orangefs_freepage(struct page *page)
 {
 	if (PagePrivate(page)) {
 		kfree((struct orangefs_write_range *)page_private(page));
-		set_page_private(page, 0);
-		ClearPagePrivate(page);
-		put_page(page);
+		clear_fs_page_private(page);
 	}
 }
 
@@ -740,9 +730,7 @@  vm_fault_t orangefs_page_mkwrite(struct vm_fault *vmf)
 	wr->len = PAGE_SIZE;
 	wr->uid = current_fsuid();
 	wr->gid = current_fsgid();
-	SetPagePrivate(page);
-	set_page_private(page, (unsigned long)wr);
-	get_page(page);
+	set_fs_page_private(page, wr);
 okay:
 
 	file_update_time(vmf->vma->vm_file);