From: Linus Torvalds <torvalds@linux-foundation.org>
To: David Hildenbrand <david@redhat.com>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
Andrew Morton <akpm@linux-foundation.org>,
Hugh Dickins <hughd@google.com>,
David Rientjes <rientjes@google.com>,
Shakeel Butt <shakeelb@google.com>,
John Hubbard <jhubbard@nvidia.com>,
Jason Gunthorpe <jgg@nvidia.com>,
Mike Kravetz <mike.kravetz@oracle.com>,
Mike Rapoport <rppt@linux.ibm.com>,
Yang Shi <shy828301@gmail.com>,
"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>,
Matthew Wilcox <willy@infradead.org>,
Vlastimil Babka <vbabka@suse.cz>, Jann Horn <jannh@google.com>,
Michal Hocko <mhocko@kernel.org>, Nadav Amit <namit@vmware.com>,
Rik van Riel <riel@surriel.com>, Roman Gushchin <guro@fb.com>,
Andrea Arcangeli <aarcange@redhat.com>,
Peter Xu <peterx@redhat.com>, Donald Dutile <ddutile@redhat.com>,
Christoph Hellwig <hch@lst.de>, Oleg Nesterov <oleg@redhat.com>,
Jan Kara <jack@suse.cz>, Linux-MM <linux-mm@kvack.org>,
"open list:KERNEL SELFTEST FRAMEWORK"
<linux-kselftest@vger.kernel.org>,
"open list:DOCUMENTATION" <linux-doc@vger.kernel.org>
Subject: Re: [PATCH v1 06/11] mm: support GUP-triggered unsharing via FAULT_FLAG_UNSHARE (!hugetlb)
Date: Sat, 18 Dec 2021 11:21:34 -0800 [thread overview]
Message-ID: <CAHk-=wg95CiyT45ZOxtnWQ7cdKmejXcOydEyJcTTNnp5-nd+xg@mail.gmail.com> (raw)
In-Reply-To: <40e7e0ab-0828-b2e7-339f-35f68a228b3d@redhat.com>
[ Cutting down ruthlessly to the core of the issue ]
On Sat, Dec 18, 2021 at 1:58 AM David Hildenbrand <david@redhat.com> wrote:
>
> 1) Missed COW
>
> 2) Unnecessary COW
>
> 3) Wrong COW
> Does that make sense? If we agree on the above, then here is how the
> currently discussed approaches differ:
>
> page_count != 1:
> * 1) cannot happen
> * 2) can happen easily (speculative references due to pagecache,
> migration, daemon, pagevec, ...)
> * 3) can happen in the current code
I claim that (1) "cannot happen" is a huge mother of a deal. It's
*LITERALLY* the bug you are chasing, and it's the security issue, so
on a bug scale, it's about the worst there is.
I further then claim that (2) "happen easily" is you just making
things up. Yes, it can happen. But no, it's not actually that common,
and since (2) is harmless from a correctness standpoint, it is purely
about performance.
And as mentioned, not using the mapcount actually makes *common*
operations much simpler and faster. You don't need the page lock to
serialize the mapcount.
So (2) is a performance argument, and you haven't actually shown it to
be a problem.
Which really only leaves (3). Which I've already explained what the
fix is: don't ever mark pages that shouldn't be COW'ed as being COW
pages.
(3) is really that simple, although it ended up depending on Jason and
John Hubbard and others doing that FOLL_PIN logic to distinguish "I
just want to see a random page, and I don't care about COW" from "I
want to get a page, and that page needs to be coherent with this VM
and not be COW'ed away"
So I'm not claiming (3) is "trivial", but at the same time it's
certainly not some fundamentally complicated thing, and it's easy to
explain what is going on.
> mapcount > 1:
> * 1) your concern is that this can happen due to concurrent swapin
> * 2) cannot happen.
> * 3) your concern is that this can happen due to concurrent swapin
No, my concern about (1) is that IT IS WRONG.
"mapcount" means nothing for COW. I even gave you an example of
exactly where it means nothing. It's crazy. It's illogical. And it's
complicated as hell.
The fact that only one user maps a page is simply not meaningful. That
page can have other users that you don't know anything about, and that
don't show up in the mapcount.
That page can be swapcached, in which case mapcount can change
radically in ways that you earlier indicated cannot happen. You were
wrong.
But even if you fix that - by taking the page lock in every single
place - there are still *other* users that for all you know may want
the old contents. You don't know.
The only thing that says "no other users" is the page count. Not the mapcount.
In other words, I claim that
(a) mapcount is fundamentally the wrong thing to test. You can be the
only mapper, without being the "owner" of the page.
(b) it's *LITERALLY* the direct and present source of that bug in the
testcase you added, where a page with a mapcount of 1 has other
concurrent users and needs to be COW'ed but isn't.
(c) it's complicated and expensive to calculate (where one big part
of the expense is the page lock synchronization requirements, but
there are others)
And this all happens for that "case (1)", which is the worst adn
scariest of them all.
In contrast to that, your argument that "(2) cannot happen" is a total
non-argument. (2) isn't the problem.
And I claim that (3) can happen because you're testing the wrong
counter, so who knows if the COW is wrong or not?
> I am completely missing how 2) or 3) could *ever* be handled properly
> for page_count != 1. 3) is obviously more important and gives me nightmares.
Ok, so if I tell you how (2) and (3) are handled properly, you will
just admit you were wrong?
Here's how they are handled properly with page counts. I have told you
this before, but I'll summarize:
(2) is handled semantically properly by definition - it may be
"unnecessary", but it has no semantic meaning
This is an IMPORTANT thing to realize. The fact is, (2) is not in the
same class as (1) or (3).
And honestly - we've been doing this for all the common cases already
since at least 5.9, and your performance argument simply has not
really reared its head. Which makes the whole argument moot. I claim
that it simplifies lots of common operations and avoids having to
serialize on a lock that has been a real and major problem. You claim
it's extra overhead and can cause extra COW events. Neither of has any
numbers worth anything, but at least I can point to the fact that all
the *normal* VM paths have been doing the thing I advocate for many
releases now, and the sky most definitely is NOT falling.
So that only leaves (3).
Handling (3) really is so conceptually simple that I feel silly for
repeating it: if you don't want a COW to happen, then you mark the
page as being not-COW.
That sounds so simple as to be stupid. But it really is the solution.
It's what that pinning logic does, and keeps that "page may be pinned"
state around, and then operations like fork() that would otherwise
create a COW mapping of it will just not do it.
So that incredibly simple approach does require actual code: it
requires that explicit "fork() needs to copy instead of COW" code, it
requires that "if it's pinned, we don't make a new swapcache entry out
of it". So it's real code, and it's a real issue, but it's
conceptually absolutely trivial, and the code is usualyl really simple
to understand too.
So you have a *trivial* concept, and you have simple code that could
be described to a slightly developmentally challenged waterfowl. If
you're one of the programmers doing the "explain your code to a rubber
ducky", you can look at code like this:
/*
* Anonymous process memory has backing store?
* Try to allocate it some swap space here.
* Lazyfree page could be freed directly
*/
if (PageAnon(page) && PageSwapBacked(page)) {
if (!PageSwapCache(page)) {
if (!(sc->gfp_mask & __GFP_IO))
goto keep_locked;
if (page_maybe_dma_pinned(page))
goto keep_locked;
and you can explain that page_maybe_dma_pinned() test to your rubber
ducky, and that rubber ducky will literally nod its head. It gets it.
To recap:
(1) is important, and page_count() is the only thing that guarantees
"you get full access to a page only when it's *obviously* exclusively
yours".
(2) is NOT important, but could be a performance issue, but we have
real data from the past year that it isn't.
(3) is important, and has a really spectacularly simple conceptual
fix with quite simple code too.
In contrast, with the "mapcount" games you can't even explain why they
should work, and the patches I see are actively buggy because
everything is so subtle.
Linus
next prev parent reply other threads:[~2021-12-18 19:22 UTC|newest]
Thread overview: 127+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-12-17 11:30 [PATCH v1 00/11] mm: COW fixes part 1: fix the COW security issue for THP and hugetlb David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 01/11] seqlock: provide lockdep-free raw_seqcount_t variant David Hildenbrand
2021-12-17 17:02 ` Nadav Amit
2021-12-17 17:29 ` David Hildenbrand
2021-12-17 17:49 ` David Hildenbrand
2021-12-17 18:01 ` Nadav Amit
2021-12-17 21:28 ` Thomas Gleixner
2021-12-17 22:02 ` David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 02/11] mm: thp: consolidate mapcount logic on THP split David Hildenbrand
2021-12-17 19:06 ` Yang Shi
2021-12-18 14:24 ` Kirill A. Shutemov
2021-12-17 11:30 ` [PATCH v1 03/11] mm: simplify hugetlb and file-THP handling in __page_mapcount() David Hildenbrand
2021-12-17 17:16 ` Nadav Amit
2021-12-17 17:30 ` David Hildenbrand
2021-12-17 18:06 ` Mike Kravetz
2021-12-17 18:11 ` David Hildenbrand
2021-12-17 19:07 ` Yang Shi
2021-12-18 14:31 ` Kirill A. Shutemov
2021-12-17 11:30 ` [PATCH v1 04/11] mm: thp: simlify total_mapcount() David Hildenbrand
2021-12-17 19:12 ` Yang Shi
2021-12-18 14:35 ` Kirill A. Shutemov
2021-12-17 11:30 ` [PATCH v1 05/11] mm: thp: allow for reading the THP mapcount atomically via a raw_seqlock_t David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 06/11] mm: support GUP-triggered unsharing via FAULT_FLAG_UNSHARE (!hugetlb) David Hildenbrand
2021-12-17 19:04 ` Linus Torvalds
2021-12-17 19:22 ` Linus Torvalds
2021-12-17 20:17 ` David Hildenbrand
2021-12-17 20:36 ` Linus Torvalds
2021-12-17 20:39 ` Linus Torvalds
2021-12-17 20:43 ` Linus Torvalds
2021-12-17 20:42 ` David Hildenbrand
2021-12-17 20:45 ` Linus Torvalds
2021-12-18 22:52 ` Kirill A. Shutemov
2021-12-18 23:05 ` Linus Torvalds
2021-12-17 20:47 ` Jason Gunthorpe
2021-12-17 20:56 ` Linus Torvalds
2021-12-17 21:17 ` David Hildenbrand
2021-12-17 21:04 ` David Hildenbrand
2021-12-18 0:50 ` Jason Gunthorpe
2021-12-17 21:15 ` Nadav Amit
2021-12-17 21:20 ` David Hildenbrand
2021-12-18 0:50 ` Jason Gunthorpe
2021-12-18 1:53 ` Linus Torvalds
2021-12-18 2:17 ` Linus Torvalds
2021-12-18 2:42 ` Linus Torvalds
2021-12-18 3:36 ` Linus Torvalds
2021-12-18 3:05 ` Jason Gunthorpe
2021-12-18 3:30 ` Nadav Amit
2021-12-18 3:38 ` Linus Torvalds
2021-12-18 18:42 ` Jason Gunthorpe
2021-12-18 21:48 ` Nadav Amit
2021-12-18 22:53 ` Linus Torvalds
2021-12-19 0:19 ` Nadav Amit
2021-12-19 0:35 ` Linus Torvalds
2021-12-19 6:02 ` Nadav Amit
2021-12-19 8:01 ` John Hubbard
2021-12-19 11:30 ` Matthew Wilcox
2021-12-19 17:27 ` Linus Torvalds
2021-12-19 17:44 ` David Hildenbrand
2021-12-19 17:44 ` Linus Torvalds
2021-12-19 17:59 ` David Hildenbrand
2021-12-19 21:12 ` Matthew Wilcox
2021-12-19 21:27 ` Linus Torvalds
2021-12-19 21:47 ` Matthew Wilcox
2021-12-19 21:53 ` Linus Torvalds
2021-12-19 22:02 ` Matthew Wilcox
2021-12-19 22:12 ` Linus Torvalds
2021-12-19 22:26 ` Matthew Wilcox
2021-12-20 18:37 ` Matthew Wilcox
2021-12-20 18:52 ` Matthew Wilcox
2021-12-20 19:38 ` Linus Torvalds
2021-12-20 19:15 ` Linus Torvalds
2021-12-20 21:02 ` Matthew Wilcox
2021-12-20 21:27 ` Linus Torvalds
2021-12-21 1:03 ` Jason Gunthorpe
2021-12-21 3:29 ` Matthew Wilcox
2021-12-21 8:58 ` David Hildenbrand
2021-12-21 14:28 ` Jason Gunthorpe
[not found] ` <303f21d3-42b4-2f11-3f22-28f89f819080@redhat.com>
2021-12-21 23:54 ` Jason Gunthorpe
2021-12-21 17:05 ` Linus Torvalds
2021-12-21 17:40 ` David Hildenbrand
2021-12-21 18:00 ` Linus Torvalds
[not found] ` <dda021c8-69ec-c660-46be-793ae345a5bb@redhat.com>
2021-12-21 21:11 ` John Hubbard
2021-12-21 18:07 ` Jan Kara
2021-12-21 18:30 ` Linus Torvalds
[not found] ` <d23ede12-5df7-2f28-00fd-ea58d85ae400@redhat.com>
2021-12-21 18:58 ` Linus Torvalds
2021-12-21 21:16 ` John Hubbard
2021-12-21 19:07 ` Jason Gunthorpe
[not found] ` <3e0868e6-c714-1bf8-163f-389989bf5189@redhat.com>
[not found] ` <dfe1c8d5-6fac-9040-0272-6d77bafa6a16@redhat.com>
2021-12-22 12:41 ` Jan Kara
[not found] ` <4a28e8a0-2efa-8b5e-10b5-38f1fc143a98@redhat.com>
2021-12-22 14:42 ` Jan Kara
[not found] ` <505d3d0f-23ee-0eec-0571-8058b8eedb97@redhat.com>
2021-12-22 16:08 ` Jan Kara
2021-12-22 16:44 ` Matthew Wilcox
2021-12-22 18:40 ` Linus Torvalds
2021-12-23 12:54 ` Jan Kara
2021-12-23 17:18 ` Linus Torvalds
2021-12-23 0:21 ` Matthew Wilcox
2021-12-24 2:53 ` Jason Gunthorpe
2021-12-24 4:53 ` Matthew Wilcox
2022-01-04 0:33 ` Jason Gunthorpe
2021-12-21 23:59 ` Jason Gunthorpe
2021-12-22 12:44 ` Jan Kara
2021-12-17 20:45 ` David Hildenbrand
2021-12-17 20:51 ` Linus Torvalds
2021-12-17 20:55 ` David Hildenbrand
2021-12-17 21:36 ` Linus Torvalds
2021-12-17 21:47 ` David Hildenbrand
2021-12-17 21:50 ` Linus Torvalds
2021-12-17 22:29 ` David Hildenbrand
2021-12-17 22:58 ` Linus Torvalds
2021-12-17 23:29 ` David Hildenbrand
2021-12-17 23:53 ` Nadav Amit
2021-12-18 4:02 ` Linus Torvalds
2021-12-18 4:52 ` Nadav Amit
2021-12-18 5:03 ` Matthew Wilcox
2021-12-18 5:23 ` Nadav Amit
2021-12-18 18:37 ` Linus Torvalds
2021-12-17 22:18 ` Linus Torvalds
2021-12-17 22:43 ` David Hildenbrand
2021-12-17 23:20 ` Linus Torvalds
2021-12-18 9:57 ` David Hildenbrand
2021-12-18 19:21 ` Linus Torvalds [this message]
2021-12-18 19:52 ` Linus Torvalds
2021-12-19 8:43 ` David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 07/11] mm: gup: trigger unsharing via FAULT_FLAG_UNSHARE when required (!hugetlb) David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 08/11] mm: hugetlb: support GUP-triggered unsharing via FAULT_FLAG_UNSHARE David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 09/11] mm: gup: trigger unsharing via FAULT_FLAG_UNSHARE when required (hugetlb) David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 10/11] mm: thp: introduce and use page_trans_huge_anon_shared() David Hildenbrand
2021-12-17 11:30 ` [PATCH v1 11/11] selftests/vm: add tests for the known COW security issues 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-=wg95CiyT45ZOxtnWQ7cdKmejXcOydEyJcTTNnp5-nd+xg@mail.gmail.com' \
--to=torvalds@linux-foundation.org \
--cc=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=david@redhat.com \
--cc=ddutile@redhat.com \
--cc=guro@fb.com \
--cc=hch@lst.de \
--cc=hughd@google.com \
--cc=jack@suse.cz \
--cc=jannh@google.com \
--cc=jgg@nvidia.com \
--cc=jhubbard@nvidia.com \
--cc=kirill.shutemov@linux.intel.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@kernel.org \
--cc=mike.kravetz@oracle.com \
--cc=namit@vmware.com \
--cc=oleg@redhat.com \
--cc=peterx@redhat.com \
--cc=riel@surriel.com \
--cc=rientjes@google.com \
--cc=rppt@linux.ibm.com \
--cc=shakeelb@google.com \
--cc=shy828301@gmail.com \
--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