lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CABi2SkWPiGJTv3FEPxD1OJYUAoePab8jG+CSd58UHqEsBeOYbA@mail.gmail.com>
Date: Wed, 21 Aug 2024 08:56:28 -0700
From: Jeff Xu <jeffxu@...omium.org>
To: Pedro Falcato <pedro.falcato@...il.com>
Cc: Andrew Morton <akpm@...ux-foundation.org>, "Liam R. Howlett" <Liam.Howlett@...cle.com>, 
	Vlastimil Babka <vbabka@...e.cz>, Lorenzo Stoakes <lorenzo.stoakes@...cle.com>, 
	Shuah Khan <shuah@...nel.org>, linux-mm@...ck.org, linux-kernel@...r.kernel.org, 
	linux-kselftest@...r.kernel.org, oliver.sang@...el.com, 
	torvalds@...ux-foundation.org, Michael Ellerman <mpe@...erman.id.au>, 
	Kees Cook <kees@...nel.org>
Subject: Re: [PATCH v3 7/7] selftests/mm: add more mseal traversal tests

Hi Pedro

On Fri, Aug 16, 2024 at 5:18 PM Pedro Falcato <pedro.falcato@...il.com> wrote:
>
> Add more mseal traversal tests across VMAs, where we could possibly
> screw up sealing checks. These test more across-vma traversal for
> mprotect, munmap and madvise. Particularly, we test for the case where a
> regular VMA is followed by a sealed VMA.
>
> Signed-off-by: Pedro Falcato <pedro.falcato@...il.com>
> ---
>  tools/testing/selftests/mm/mseal_test.c | 111 +++++++++++++++++++++++++++++++-
>  1 file changed, 110 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/mm/mseal_test.c b/tools/testing/selftests/mm/mseal_test.c
> index 259bef4945e9..0d4d40fb0f88 100644
> --- a/tools/testing/selftests/mm/mseal_test.c
> +++ b/tools/testing/selftests/mm/mseal_test.c
> @@ -766,6 +766,42 @@ static void test_seal_mprotect_partial_mprotect(bool seal)
>         REPORT_TEST_PASS();
>  }
>
> +static void test_seal_mprotect_partial_mprotect_tail(bool seal)
> +{
> +       void *ptr;
> +       unsigned long page_size = getpagesize();
> +       unsigned long size = 2 * page_size;
> +       int ret;
> +       int prot;
> +
> +       /*
> +        * Check if a partial mseal (that results in two vmas) works correctly.
> +        * It might mprotect the first, but it'll never touch the second (msealed) vma.
> +        */
> +
> +       setup_single_address(size, &ptr);
> +       FAIL_TEST_IF_FALSE(ptr != (void *)-1);
> +
> +       if (seal) {
> +               ret = sys_mseal(ptr + page_size, size);
you are allocating 2 pages , and I assume you are sealing the second
page, so the size should be page_size.
ret = sys_mseal(ptr + page_size, page_size);

> +               FAIL_TEST_IF_FALSE(!ret);
> +       }
> +
> +       ret = sys_mprotect(ptr, size, PROT_EXEC);
> +       if (seal)
> +               FAIL_TEST_IF_FALSE(ret < 0);
> +       else
> +               FAIL_TEST_IF_FALSE(!ret);
> +
> +       if (seal) {
> +               FAIL_TEST_IF_FALSE(get_vma_size(ptr + page_size, &prot) > 0);
> +               FAIL_TEST_IF_FALSE(prot == 0x4);
To test partial mprotect, the test needs to add the check for the
first page to be changed, Also to avoid the merge,  a PROT_NONE page
can to be added in front.

> +       }
> +
> +       REPORT_TEST_PASS();
> +}
> +
> +
>  static void test_seal_mprotect_two_vma_with_gap(bool seal)
>  {
>         void *ptr;
> @@ -983,6 +1019,41 @@ static void test_seal_munmap_vma_with_gap(bool seal)
>         REPORT_TEST_PASS();
>  }
>
> +static void test_seal_munmap_partial_across_vmas(bool seal)
> +{
> +       void *ptr;
> +       unsigned long page_size = getpagesize();
> +       unsigned long size = 2 * page_size;
> +       int ret;
> +       int prot;
> +
> +       /*
> +        * Check if a partial mseal (that results in two vmas) works correctly.
> +        * It might unmap the first, but it'll never unmap the second (msealed) vma.
> +        */
> +
> +       setup_single_address(size, &ptr);
> +       FAIL_TEST_IF_FALSE(ptr != (void *)-1);
> +
> +       if (seal) {
> +               ret = sys_mseal(ptr + page_size, size);
ret = sys_mseal(ptr + page_size, page_size);

> +               FAIL_TEST_IF_FALSE(!ret);
> +       }
> +
> +       ret = sys_munmap(ptr, size);
> +       if (seal)
> +               FAIL_TEST_IF_FALSE(ret < 0);
> +       else
> +               FAIL_TEST_IF_FALSE(!ret);
> +
> +       if (seal) {
> +               FAIL_TEST_IF_FALSE(get_vma_size(ptr + page_size, &prot) > 0);
> +               FAIL_TEST_IF_FALSE(prot == 0x4);
To test partial unmap, the test needs to add the check for the first
page to be freed, Also to avoid the merge,  a PROT_NONE page needs to
be in front.

The test_seal_munmap_partial_across_vmas  shows the behavior
difference with in-loop approach and out-loop approach. Previously,
both VMAs will not be freed, now the first VMA will be freed, and the
second VMA (sealed) won't.

This brings to the line you previously mentioned: [1] and I quote:
"munmap is atomic and always has been. It's required by POSIX."

So this is no longer true for the current series.  Linux doesn't need
to be POSIX compliant, from previous conversation on this topic with
Linus [2], so I'm open to that. If this is accepted by Linus, it would
be better to add comments on munmap code or tests, for future readers
(in case they are curious about reasoning. )

[1] https://lore.kernel.org/linux-mm/CAKbZUD3_3KN4fAyQsD+=p3PV8svAvVyS278umX40Ehsa+zkz3w@mail.gmail.com/
[2] https://lore.kernel.org/linux-mm/CAHk-=wgDv5vPx2xoxNQh+kbvLsskWubGGGK69cqF_i4FkM-GCw@mail.gmail.com/

> +       }
> +
> +       REPORT_TEST_PASS();
> +}
> +
>  static void test_munmap_start_freed(bool seal)
>  {
>         void *ptr;
> @@ -1735,6 +1806,37 @@ static void test_seal_discard_ro_anon(bool seal)
>         REPORT_TEST_PASS();
>  }
>
> +static void test_seal_discard_across_vmas(bool seal)
> +{
> +       void *ptr;
> +       unsigned long page_size = getpagesize();
> +       unsigned long size = 2 * page_size;
> +       int ret;
> +
> +       setup_single_address(size, &ptr);
> +       FAIL_TEST_IF_FALSE(ptr != (void *)-1);
> +
> +       if (seal) {
> +               ret = seal_single_address(ptr + page_size, page_size);
> +               FAIL_TEST_IF_FALSE(!ret);
> +       }
> +
> +       ret = sys_madvise(ptr, size, MADV_DONTNEED);
> +       if (seal)
> +               FAIL_TEST_IF_FALSE(ret < 0);
> +       else
> +               FAIL_TEST_IF_FALSE(!ret);
> +
> +       ret = sys_munmap(ptr, size);
> +       if (seal)
> +               FAIL_TEST_IF_FALSE(ret < 0);
> +       else
> +               FAIL_TEST_IF_FALSE(!ret);
> +
> +       REPORT_TEST_PASS();
> +}
> +
> +
>  static void test_seal_madvise_nodiscard(bool seal)
>  {
>         void *ptr;
> @@ -1779,7 +1881,7 @@ int main(int argc, char **argv)
>         if (!pkey_supported())
>                 ksft_print_msg("PKEY not supported\n");
>
> -       ksft_set_plan(82);
> +       ksft_set_plan(88);
>
>         test_seal_addseal();
>         test_seal_unmapped_start();
> @@ -1825,12 +1927,17 @@ int main(int argc, char **argv)
>         test_seal_mprotect_split(false);
>         test_seal_mprotect_split(true);
>
> +       test_seal_mprotect_partial_mprotect_tail(false);
> +       test_seal_mprotect_partial_mprotect_tail(true);
> +
>         test_seal_munmap(false);
>         test_seal_munmap(true);
>         test_seal_munmap_two_vma(false);
>         test_seal_munmap_two_vma(true);
>         test_seal_munmap_vma_with_gap(false);
>         test_seal_munmap_vma_with_gap(true);
> +       test_seal_munmap_partial_across_vmas(false);
> +       test_seal_munmap_partial_across_vmas(true);
>
>         test_munmap_start_freed(false);
>         test_munmap_start_freed(true);
> @@ -1862,6 +1969,8 @@ int main(int argc, char **argv)
>         test_seal_madvise_nodiscard(true);
>         test_seal_discard_ro_anon(false);
>         test_seal_discard_ro_anon(true);
> +       test_seal_discard_across_vmas(false);
> +       test_seal_discard_across_vmas(true);
>         test_seal_discard_ro_anon_on_rw(false);
>         test_seal_discard_ro_anon_on_rw(true);
>         test_seal_discard_ro_anon_on_shared(false);
>
> --
> 2.46.0
>
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ