diff options
author | David Hildenbrand <david@redhat.com> | 2022-11-08 18:46:52 +0100 |
---|---|---|
committer | Andrew Morton <akpm@linux-foundation.org> | 2022-11-30 15:58:49 -0800 |
commit | 07f8bac4982f98fc4b5ae05679d76fccc15079ea (patch) | |
tree | 4d180889ab9fe471d23ff203a7d9f8bca9c02da7 /tools | |
parent | d6379159f47630813f06f97535cc82ce7b9eed49 (diff) | |
download | linux-stable-07f8bac4982f98fc4b5ae05679d76fccc15079ea.tar.gz linux-stable-07f8bac4982f98fc4b5ae05679d76fccc15079ea.tar.bz2 linux-stable-07f8bac4982f98fc4b5ae05679d76fccc15079ea.zip |
selftests/vm: anon_cow: add mprotect() optimization tests
Let's extend the test to cover the possible mprotect() optimization when
removing write-protection. mprotect() must not allow write-access to a
COW-shared page by accident.
Link: https://lkml.kernel.org/r/20221108174652.198904-8-david@redhat.com
Signed-off-by: David Hildenbrand <david@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Nadav Amit <namit@vmware.com>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/selftests/vm/anon_cow.c | 49 |
1 files changed, 46 insertions, 3 deletions
diff --git a/tools/testing/selftests/vm/anon_cow.c b/tools/testing/selftests/vm/anon_cow.c index 705bd0b3db11..bbb251eb5025 100644 --- a/tools/testing/selftests/vm/anon_cow.c +++ b/tools/testing/selftests/vm/anon_cow.c @@ -190,7 +190,8 @@ static int child_vmsplice_memcmp_fn(char *mem, size_t size, typedef int (*child_fn)(char *mem, size_t size, struct comm_pipes *comm_pipes); -static void do_test_cow_in_parent(char *mem, size_t size, child_fn fn) +static void do_test_cow_in_parent(char *mem, size_t size, bool do_mprotect, + child_fn fn) { struct comm_pipes comm_pipes; char buf; @@ -212,6 +213,22 @@ static void do_test_cow_in_parent(char *mem, size_t size, child_fn fn) while (read(comm_pipes.child_ready[0], &buf, 1) != 1) ; + + if (do_mprotect) { + /* + * mprotect() optimizations might try avoiding + * write-faults by directly mapping pages writable. + */ + ret = mprotect(mem, size, PROT_READ); + ret |= mprotect(mem, size, PROT_READ|PROT_WRITE); + if (ret) { + ksft_test_result_fail("mprotect() failed\n"); + write(comm_pipes.parent_ready[1], "0", 1); + wait(&ret); + goto close_comm_pipes; + } + } + /* Modify the page. */ memset(mem, 0xff, size); write(comm_pipes.parent_ready[1], "0", 1); @@ -229,12 +246,22 @@ close_comm_pipes: static void test_cow_in_parent(char *mem, size_t size) { - do_test_cow_in_parent(mem, size, child_memcmp_fn); + do_test_cow_in_parent(mem, size, false, child_memcmp_fn); +} + +static void test_cow_in_parent_mprotect(char *mem, size_t size) +{ + do_test_cow_in_parent(mem, size, true, child_memcmp_fn); } static void test_vmsplice_in_child(char *mem, size_t size) { - do_test_cow_in_parent(mem, size, child_vmsplice_memcmp_fn); + do_test_cow_in_parent(mem, size, false, child_vmsplice_memcmp_fn); +} + +static void test_vmsplice_in_child_mprotect(char *mem, size_t size) +{ + do_test_cow_in_parent(mem, size, true, child_vmsplice_memcmp_fn); } static void do_test_vmsplice_in_parent(char *mem, size_t size, @@ -970,6 +997,14 @@ static const struct test_case test_cases[] = { test_cow_in_parent, }, /* + * Basic test, but do an additional mprotect(PROT_READ)+ + * mprotect(PROT_READ|PROT_WRITE) in the parent before write access. + */ + { + "Basic COW after fork() with mprotect() optimization", + test_cow_in_parent_mprotect, + }, + /* * vmsplice() [R/O GUP] + unmap in the child; modify in the parent. If * we miss to break COW, the child observes modifications by the parent. * This is CVE-2020-29374 reported by Jann Horn. @@ -979,6 +1014,14 @@ static const struct test_case test_cases[] = { test_vmsplice_in_child }, /* + * vmsplice() test, but do an additional mprotect(PROT_READ)+ + * mprotect(PROT_READ|PROT_WRITE) in the parent before write access. + */ + { + "vmsplice() + unmap in child with mprotect() optimization", + test_vmsplice_in_child_mprotect + }, + /* * vmsplice() [R/O GUP] in parent before fork(), unmap in parent after * fork(); modify in the child. If we miss to break COW, the parent * observes modifications by the child. |