linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Linus Torvalds <torvalds@linux-foundation.org>
To: David Hildenbrand <david@redhat.com>
Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	stable@vger.kernel.org,
	 Andrew Morton <akpm@linux-foundation.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	 Axel Rasmussen <axelrasmussen@google.com>,
	Peter Xu <peterx@redhat.com>,  Hugh Dickins <hughd@google.com>,
	Andrea Arcangeli <aarcange@redhat.com>,
	 Matthew Wilcox <willy@infradead.org>,
	Vlastimil Babka <vbabka@suse.cz>,
	John Hubbard <jhubbard@nvidia.com>,
	 Jason Gunthorpe <jgg@nvidia.com>
Subject: Re: [PATCH v1] mm/gup: fix FOLL_FORCE COW security issue and remove FOLL_COW
Date: Tue, 9 Aug 2022 13:00:34 -0700	[thread overview]
Message-ID: <CAHk-=wgsDOz5MfYYS9mE7PvFn4kLhTFdBwXvN6HCEsw1kvJnRQ@mail.gmail.com> (raw)
In-Reply-To: <20220808073232.8808-1-david@redhat.com>

On Mon, Aug 8, 2022 at 12:32 AM David Hildenbrand <david@redhat.com> wrote:
>

So I've read through the patch several times, and it seems fine, but
this function (and the pmd version of it) just read oddly to me.

> +static inline bool can_follow_write_pte(pte_t pte, struct page *page,
> +                                       struct vm_area_struct *vma,
> +                                       unsigned int flags)
> +{
> +       if (pte_write(pte))
> +               return true;
> +       if (!(flags & FOLL_FORCE))
> +               return false;
> +
> +       /*
> +        * See check_vma_flags(): only COW mappings need that special
> +        * "force" handling when they lack VM_WRITE.
> +        */
> +       if (vma->vm_flags & VM_WRITE)
> +               return false;
> +       VM_BUG_ON(!is_cow_mapping(vma->vm_flags));

So apart from the VM_BUG_ON(), this code just looks really strange -
even despite the comment. Just conceptually, the whole "if it's
writable, return that you cannot follow it for a write" just looks so
very very strange.

That doesn't make the code _wrong_, but considering how many times
this has had subtle bugs, let's not write code that looks strange.

So I would suggest that to protect against future bugs, we try to make
it be fairly clear and straightforward, and maybe even a bit overly
protective.

For example, let's kill the "shared mapping that you don't have write
permissions to" very explicitly and without any subtle code at all.
The vm_flags tests are cheap and easy, and we could very easily just
add some core ones to make any mistakes much less critical.

Now, making that 'is_cow_mapping()' check explicit at the very top of
this would already go a long way:

        /* FOLL_FORCE for writability only affects COW mappings */
        if (!is_cow_mapping(vma->vm_flags))
                return false;

but I'd actually go even further: in this case that "is_cow_mapping()"
helper to some degree actually hides what is going on.

So I'd actually prefer for that function to be written something like

        /* If the pte is writable, we can write to the page */
        if (pte_write(pte))
                return true;

        /* Maybe FOLL_FORCE is set to override it? */
        if (flags & FOLL_FORCE)
                return false;

        /* But FOLL_FORCE has no effect on shared mappings */
        if (vma->vm_flags & MAP_SHARED)
                return false;

        /* .. or read-only private ones */
        if (!(vma->vm_flags & MAP_MAYWRITE))
                return false;

        /* .. or already writable ones that just need to take a write fault */
        if (vma->vm_flags & MAP_WRITE)
                return false;

and the two first vm_flags tests above are basically doing tat
"is_cow_mapping()", and maybe we could even have a comment to that
effect, but wouldn't it be nice to just write it out that way?

And after you've written it out like the above, now that

        if (!page || !PageAnon(page) || !PageAnonExclusive(page))
                return false;

makes you pretty safe from a data sharing perspective: it's most
definitely not a shared page at that point.

So if you write it that way, the only remaining issues are the magic
special soft-dirty and uffd ones, but at that point it's purely about
the semantics of those features, no longer about any possible "oh, we
fooled some shared page to be writable".

And I think the above is fairly legible without any subtle cases, and
the one-liner comments make it all fairly clear that it's testing.

Is any of this in any _technical_ way different from what your patch
did? No. It's literally just rewriting it to be a bit more explicit in
what it is doing, I think, and it makes that odd "it's not writable if
VM_WRITE is set" case a bit more explicit.

Hmm?

                  Linus


  parent reply	other threads:[~2022-08-09 20:00 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-08  7:32 [PATCH v1] mm/gup: fix FOLL_FORCE COW security issue and remove FOLL_COW David Hildenbrand
2022-08-08 16:02 ` David Hildenbrand
2022-08-09 18:27 ` Linus Torvalds
2022-08-09 18:45   ` David Hildenbrand
2022-08-09 18:59     ` Linus Torvalds
2022-08-09 19:07       ` Jason Gunthorpe
2022-08-09 19:21         ` Linus Torvalds
2022-08-09 21:16         ` David Laight
2022-08-11  7:13       ` [PATCH] sched/all: Change BUG_ON() instances to WARN_ON() Ingo Molnar
2022-08-11 20:43         ` Linus Torvalds
2022-08-11 21:28           ` Matthew Wilcox
2022-08-11 23:22             ` Jason Gunthorpe
2022-08-14  1:10               ` John Hubbard
2022-08-12  9:29           ` [PATCH v2] sched/all: Change all BUG_ON() instances in the scheduler to WARN_ON_ONCE() Ingo Molnar
     [not found]             ` <20220815144143.zjsiamw5y22bvgki@suse.de>
2022-08-15 22:12               ` John Hubbard
2022-08-21 11:28               ` Ingo Molnar
2022-08-09 18:40 ` [PATCH v1] mm/gup: fix FOLL_FORCE COW security issue and remove FOLL_COW Linus Torvalds
2022-08-09 18:48   ` Jason Gunthorpe
2022-08-09 18:53     ` David Hildenbrand
2022-08-09 19:07     ` Linus Torvalds
2022-08-09 19:20       ` David Hildenbrand
2022-08-09 18:48 ` Linus Torvalds
2022-08-09 19:09   ` David Hildenbrand
2022-08-09 20:00 ` Linus Torvalds [this message]
2022-08-09 20:06   ` David Hildenbrand
2022-08-09 20:07   ` David Hildenbrand
2022-08-09 20:14     ` Linus Torvalds
2022-08-09 20:20       ` David Hildenbrand
2022-08-09 20:30         ` Linus Torvalds
2022-08-09 20:38           ` Linus Torvalds
2022-08-09 20:42           ` David Hildenbrand
2022-08-09 20:20       ` Linus Torvalds
2022-08-09 20:23         ` David Hildenbrand

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='CAHk-=wgsDOz5MfYYS9mE7PvFn4kLhTFdBwXvN6HCEsw1kvJnRQ@mail.gmail.com' \
    --to=torvalds@linux-foundation.org \
    --cc=aarcange@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=axelrasmussen@google.com \
    --cc=david@redhat.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hughd@google.com \
    --cc=jgg@nvidia.com \
    --cc=jhubbard@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=peterx@redhat.com \
    --cc=stable@vger.kernel.org \
    --cc=vbabka@suse.cz \
    --cc=willy@infradead.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 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).