2020-04-26 21:52:13

by Guoqing Jiang

[permalink] [raw]
Subject: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

Since the new pair function is introduced, we can call them to clean the
code in orangefs.

Cc: Mike Marshall <[email protected]>
Cc: Martin Brandenburg <[email protected]>
Cc: [email protected]
Signed-off-by: Guoqing Jiang <[email protected]>
---
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);
}
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);
--
2.17.1


2020-04-26 22:29:05

by Dave Chinner

[permalink] [raw]
Subject: Re: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

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 <[email protected]>
> Cc: Martin Brandenburg <[email protected]>
> Cc: [email protected]
> Signed-off-by: Guoqing Jiang <[email protected]>
> ---
> 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.
--
Dave Chinner
[email protected]

2020-04-27 00:14:25

by Matthew Wilcox

[permalink] [raw]
Subject: Re: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

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));

2020-04-27 02:28:59

by Dave Chinner

[permalink] [raw]
Subject: Re: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

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.
--
Dave Chinner
[email protected]

2020-04-27 03:02:09

by Gao Xiang

[permalink] [raw]
Subject: Re: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

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 <[email protected]>
> > Cc: Martin Brandenburg <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Guoqing Jiang <[email protected]>
> > ---
> > 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


2020-04-27 03:31:07

by Gao Xiang

[permalink] [raw]
Subject: Re: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

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 <[email protected]>
> > > Cc: Martin Brandenburg <[email protected]>
> > > Cc: [email protected]
> > > Signed-off-by: Guoqing Jiang <[email protected]>
> > > ---
> > > 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
>
>

2020-04-27 08:20:25

by Guoqing Jiang

[permalink] [raw]
Subject: Re: [RFC PATCH 8/9] orangefs: use set/clear_fs_page_private

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