All of lore.kernel.org
 help / color / mirror / Atom feed
From: Liu Bo <bo.li.liu@oracle.com>
To: Filipe Manana <fdmanana@gmail.com>
Cc: "linux-btrfs@vger.kernel.org" <linux-btrfs@vger.kernel.org>
Subject: Re: [PATCH] Btrfs: fix out of bounds array access while reading extent buffer
Date: Tue, 8 Aug 2017 11:05:15 -0600	[thread overview]
Message-ID: <20170808170515.GA3700@localhost.localdomain> (raw)
In-Reply-To: <CAL3q7H7sSpOo6JFjztSUzZX9CP30C4jMJrnQBec7od8skN5BYw@mail.gmail.com>

Hi Filipe,

On Tue, Aug 08, 2017 at 09:47:21AM +0100, Filipe Manana wrote:
> On Mon, Aug 7, 2017 at 8:39 PM, Liu Bo <bo.li.liu@oracle.com> wrote:
> > There is a cornel case that slip through the checkers in functions
> > reading extent buffer, ie.
> >
> > if (start < eb->len) and (start + len > eb->len),
> > then
> >
> > a) map_private_extent_buffer() returns immediately because
> > it's thinking the range spans across two pages,
> >
> > b) and the checkers in read_extent_buffer(), WARN_ON(start > eb->len)
> > and WARN_ON(start + len > eb->start + eb->len), both are OK in this
> > corner case, but it'd actually try to access the eb->pages out of
> > bounds because of (start + len > eb->len).
> >
> > The case is found by switching extent inline ref type from shared data
> > ref to non-shared data ref.
> >
> > This is adding proper checks in order to avoid invalid memory access,
> > ie. 'general protection', before it's too late.
> 
> Hi Bo,
> 
> I don't understand these 2 last paragraphs.
> How do you fix the invalid memory access? All the change does is make
> sure that attempts to read from invalid regions of an extent buffer
> result in a warning and returning an error code. Those paragraphs give
> the idea that the problem is that some caller is passing a wrong
> offset/length pair, however you aren't fixing any caller. can you
> clarify?
>

I see your doubt, that wrong offset/length pair comes from one of
btrfs_setget helpers, eg. btrfs_extent_data_ref_root.

The invalid memory access happens when the pointer it's using to
access fields in "struct btrfs_extent_data_ref" is actually a "struct
btrfs_shared_data_ref", this is caused by switching those types.

So the offset/length pair is correct from btrfs_setget helper's point
of view, but it's just using the wrong helper due to a wrong ref type
(in v2 this'll be added to the commit log to clarity).

> Also when you say " The case is found by switching extent inline ref
> type from shared data ref to non-shared data ref", it gives the idea
> this is a deterministic problem that always happens when doing that
> switch. If so, can we have a test case?
>

It is deterministic, but it depends on patching btrfs-corrupt-block
and last time I posted a corrupt-block related case, I was told that
tool is gonna change a lot and maybe get deleted in the near future,
so it's not yet suitable for fstests cases.

> Also missing the word "fault" after 'general protection'.
>

Yeah, there is a 'fault', the full text is
"general protection fault: 0000 [#1] SMP KASAN",
will update.

Thanks,

-liubo

> Thanks.
> 
> >
> > Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
> > ---
> >  fs/btrfs/extent_io.c | 22 ++++++++++++++--------
> >  1 file changed, 14 insertions(+), 8 deletions(-)
> >
> > diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> > index 0aff9b2..d198e87 100644
> > --- a/fs/btrfs/extent_io.c
> > +++ b/fs/btrfs/extent_io.c
> > @@ -5416,13 +5416,19 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
> >         char *dst = (char *)dstv;
> >         size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1);
> >         unsigned long i = (start_offset + start) >> PAGE_SHIFT;
> > +       unsigned long num_pages = num_extent_pages(eb->start, eb->len);
> >
> > -       WARN_ON(start > eb->len);
> > -       WARN_ON(start + len > eb->start + eb->len);
> > +       if (start + len > eb->len) {
> > +               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n",
> > +                    eb->start, eb->len, start, len);
> > +               memset(dst, 0, len);
> > +               return;
> > +       }
> >
> >         offset = (start_offset + start) & (PAGE_SIZE - 1);
> >
> >         while (len > 0) {
> > +               ASSERT(i < num_pages);
> >                 page = eb->pages[i];
> >
> >                 cur = min(len, (PAGE_SIZE - offset));
> > @@ -5491,6 +5497,12 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
> >         unsigned long end_i = (start_offset + start + min_len - 1) >>
> >                 PAGE_SHIFT;
> >
> > +       if (start + min_len > eb->len) {
> > +               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n",
> > +                      eb->start, eb->len, start, min_len);
> > +               return -EINVAL;
> > +       }
> > +
> >         if (i != end_i)
> >                 return 1;
> >
> > @@ -5502,12 +5514,6 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
> >                 *map_start = ((u64)i << PAGE_SHIFT) - start_offset;
> >         }
> >
> > -       if (start + min_len > eb->len) {
> > -               WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n",
> > -                      eb->start, eb->len, start, min_len);
> > -               return -EINVAL;
> > -       }
> > -
> >         p = eb->pages[i];
> >         kaddr = page_address(p);
> >         *map = kaddr + offset;
> > --
> > 2.9.4
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 
> -- 
> Filipe David Manana,
> 
> “Whether you think you can, or you think you can't — you're right.”
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2017-08-08 18:06 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-07 19:39 [PATCH] Btrfs: fix out of bounds array access while reading extent buffer Liu Bo
2017-08-08  8:47 ` Filipe Manana
2017-08-08 17:05   ` Liu Bo [this message]
2017-08-09 15:03     ` Filipe Manana
2017-08-09 16:31 ` [PATCH v2] " Liu Bo
2017-08-09 17:35   ` Filipe Manana
2017-08-09 17:40   ` Filipe Manana
2017-08-09 18:03     ` Liu Bo
2017-08-09 17:10 ` [PATCH v3] " Liu Bo
2017-08-09 18:15   ` Hugo Mills
2017-08-11  0:47     ` Duncan
2017-08-11 21:26 ` [PATCH] " kbuild test robot
  -- strict thread matches above, loose matches on Subject: below --
2019-06-14 11:51 [PATCH] btrfs: " Young Xiao
2019-06-14 13:52 ` Qu Wenruo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170808170515.GA3700@localhost.localdomain \
    --to=bo.li.liu@oracle.com \
    --cc=fdmanana@gmail.com \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.