On Wed, Aug 21, 2024 at 5:27 PM Jeff Xu jeffxu@chromium.org wrote:
On Wed, Aug 21, 2024 at 9:20 AM Pedro Falcato pedro.falcato@gmail.com wrote:
On Wed, Aug 21, 2024 at 4:56 PM Jeff Xu jeffxu@chromium.org wrote:
Hi Pedro
On Fri, Aug 16, 2024 at 5:18 PM Pedro Falcato pedro.falcato@gmail.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@gmail.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);
Yes, good catch, it appears to be harmless but ofc down to straight luck. I'll send a fixup for this and the other mistake down there.
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.
No, I'm leaving partial mprotect to be undefined. It doesn't make sense to constraint ourselves, since POSIX wording is already loose.
}
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.
I'm not testing partial unmap. Partial unmap does not happen. I have told you this before.
ok. Then this test should be as below ? (need to add PROT_NONE page before and after) size = get_vma_size(ptr, &prot); FAIL_TEST_IF_FALSE(size == 2 * page_size); FAIL_TEST_IF_FALSE(prot==0x4)
That doesn't work because this region spans two vmas. I'll write something similar for the fixup.
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."
This is still true, the comment was a copy-and-paste mindslip. Please read the email thread. It has been fixed up by Andrew.
Which thread/patch by Andrew ? Could you please send it to me ? (I might missed that)
This thread and this patch: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches...