On Fri, Jan 8, 2021 at 10:19 AM Jason Gunthorpe <jgg@xxxxxxxx> wrote: > > Sorry, I missed something, how does mmaping a fresh new page in the > child impact the parent? > > I guess the issue is not to mmap but to GUP a shared page No. It has nothing to do with a shared page. The problem with the COW in the child is that the parent now BELIEVES that it has a private copy (because page_mapcount() was 1), but it doesn't really. But because the parent *thought* it had a private copy of the page, when the _parent_ did a write, it would cause the page COW logic to go "you have exclusive access to the page, so I'll just make it writable". The parent then writes whatever private data to that page. That page is still in the system as a vmsplice'd page, and the child can now read that private data that was _supposed_ to be exclusive to the parent, but wasn't. And the thing is, blaming vmsplice() is entirely wrong. The exact same thing used to be able to happen with any GUP case, vmsplice() was just the simplest way to cause that non-mapped page access. But any GUP could do it, with the child basically fooling the parent into revealing data. Note that Zygote itself is in no way special from a technical standpoint, and this can happen after any random fork(). The only real difference is that in all *traditional* UNIX cases, this "child can see the parent's data with trickery before execve()" situation simply doesn't *matter*. In traditional fork() situations, the parent and the child are really the same program, and if you don't trust the child, then you don't trust the parent either. The Android Zygote case isn't _technically_ any different. But the difference is that because the whole idea with Zygote is to pre-map the JIT stuff for the child, you are in this special situation where the parent doesn't actually trust the child. See? No _technical_ difference. Exact same scenario as for any random fork() with GUP and COW going the wrong way. It just normally doesn't _matter_. And see above: because this is not really specific to vmsplice() (apart from that just being the easiest model), the _original_ fix for this was just "GUP will break COW early" commit: 17839856fd58 ("gup: document and work around "COW can break either way" issue") which is very straightforward: if you do a GUP lookup, you force that GUP to do the COW for you, so that nobody can then fool another process to think that it has a private page that can be re-used, but it really has a second reference to it. Because whoever took the "sneaky" GUP reference had to get their _own_ private copy first. But while that approach was very simple and very targeted (and I don't think it's wrong per se), it then caused other problems. In fact, it caused other problems for pretty much all the same cases that the current model causes problems for: all the odd special cases that do weird things to the VM. And because these problems were so odd, the alternate solution - and the thing I'm really pushing for - is to make the _core_ VM rules very simple and straightforward, and then the odd special cases have to live with those simple and straightforward rules. And the most core of those rules is that "page_mapcount()" fundamenally doesn't matter, because there are other references to pages that are all equally valid. Thinking that a page being "mapped" makes is special is wrong, as exemplified by any GUP case (but also as exemplified by the page cache or the swap cache, which were always a source of _other_ special cases for the COW code). So if you accept that notion of "page_mapcount()" is meaninfless being a truism (which Andrea obviously doesn't), then the logical extension of that is the set of rules I outlined in my reply to Andy: (a) COW can never happen "too much", and "page_count()" is the fundamental "somebody has a reference to this page" (b) page pinning and any other "this needs to be coherent" ends up being a special per-page "shared memory" case That special "shared memory page" thing in (b) is then that rule that when we pin a page, we make sure it's writable, and stays writable, so that COW never breaks the association. That's then the thing that causes problems for anybody who wants to write-protect stuff. Linus