Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tools/selftests: add file/shmem-backed mapping guard region tests

Extend the guard region self tests to explicitly assert that guard regions
work correctly for functionality specific to file-backed and shmem
mappings.

In addition to testing all of the existing guard region functionality that
is currently tested against anonymous mappings against file-backed and
shmem mappings (except those which are exclusive to anonymous mapping), we
now also:

* Test that MADV_SEQUENTIAL does not cause unexpected readahead behaviour.
* Test that MAP_PRIVATE behaves as expected with guard regions installed in
both a shared and private mapping of an fd.
* Test that a read-only file can correctly establish guard regions.
* Test a probable fault-around case does not interfere with guard regions
(or vice-versa).
* Test that truncation does not eliminate guard regions.
* Test that hole punching functions as expected in the presence of guard
regions.
* Test that a read-only mapping of a memfd write sealed mapping can have
guard regions established within it and function correctly without
violation of the seal.
* Test that guard regions installed into a mapping of the anonymous zero
page function correctly.

Link: https://lkml.kernel.org/r/90c16bec5fcaafcd1700dfa3e9988c3e1aa9ac1d.1739469950.git.lorenzo.stoakes@oracle.com
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Jann Horn <jannh@google.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: Liam Howlett <liam.howlett@oracle.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: "Paul E . McKenney" <paulmck@kernel.org>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Lorenzo Stoakes and committed by
Andrew Morton
0b6d4853 272f37d3

+595
+595
tools/testing/selftests/mm/guard-regions.c
··· 216 216 return fd; 217 217 } 218 218 219 + /* Establish a varying pattern in a buffer. */ 220 + static void set_pattern(char *ptr, size_t num_pages, size_t page_size) 221 + { 222 + size_t i; 223 + 224 + for (i = 0; i < num_pages; i++) { 225 + char *ptr2 = &ptr[i * page_size]; 226 + 227 + memset(ptr2, 'a' + (i % 26), page_size); 228 + } 229 + } 230 + 231 + /* 232 + * Check that a buffer contains the pattern set by set_pattern(), starting at a 233 + * page offset of pgoff within the buffer. 234 + */ 235 + static bool check_pattern_offset(char *ptr, size_t num_pages, size_t page_size, 236 + size_t pgoff) 237 + { 238 + size_t i; 239 + 240 + for (i = 0; i < num_pages * page_size; i++) { 241 + size_t offset = pgoff * page_size + i; 242 + char actual = ptr[offset]; 243 + char expected = 'a' + ((offset / page_size) % 26); 244 + 245 + if (actual != expected) 246 + return false; 247 + } 248 + 249 + return true; 250 + } 251 + 252 + /* Check that a buffer contains the pattern set by set_pattern(). */ 253 + static bool check_pattern(char *ptr, size_t num_pages, size_t page_size) 254 + { 255 + return check_pattern_offset(ptr, num_pages, page_size, 0); 256 + } 257 + 258 + /* Determine if a buffer contains only repetitions of a specified char. */ 259 + static bool is_buf_eq(char *buf, size_t size, char chr) 260 + { 261 + size_t i; 262 + 263 + for (i = 0; i < size; i++) { 264 + if (buf[i] != chr) 265 + return false; 266 + } 267 + 268 + return true; 269 + } 270 + 219 271 FIXTURE_SETUP(guard_regions) 220 272 { 221 273 self->page_size = (unsigned long)sysconf(_SC_PAGESIZE); ··· 1486 1434 /* Cleanup. */ 1487 1435 ASSERT_EQ(ioctl(uffd, UFFDIO_UNREGISTER, &range), 0); 1488 1436 close(uffd); 1437 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1438 + } 1439 + 1440 + /* 1441 + * Mark a region within a file-backed mapping using MADV_SEQUENTIAL so we 1442 + * aggressively read-ahead, then install guard regions and assert that it 1443 + * behaves correctly. 1444 + * 1445 + * We page out using MADV_PAGEOUT before checking guard regions so we drop page 1446 + * cache folios, meaning we maximise the possibility of some broken readahead. 1447 + */ 1448 + TEST_F(guard_regions, madvise_sequential) 1449 + { 1450 + char *ptr; 1451 + int i; 1452 + const unsigned long page_size = self->page_size; 1453 + 1454 + if (variant->backing == ANON_BACKED) 1455 + SKIP(return, "MADV_SEQUENTIAL meaningful only for file-backed"); 1456 + 1457 + ptr = mmap_(self, variant, NULL, 10 * page_size, 1458 + PROT_READ | PROT_WRITE, 0, 0); 1459 + ASSERT_NE(ptr, MAP_FAILED); 1460 + 1461 + /* Establish a pattern of data in the file. */ 1462 + set_pattern(ptr, 10, page_size); 1463 + ASSERT_TRUE(check_pattern(ptr, 10, page_size)); 1464 + 1465 + /* Mark it as being accessed sequentially. */ 1466 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_SEQUENTIAL), 0); 1467 + 1468 + /* Mark every other page a guard page. */ 1469 + for (i = 0; i < 10; i += 2) { 1470 + char *ptr2 = &ptr[i * page_size]; 1471 + 1472 + ASSERT_EQ(madvise(ptr2, page_size, MADV_GUARD_INSTALL), 0); 1473 + } 1474 + 1475 + /* Now page it out. */ 1476 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0); 1477 + 1478 + /* Now make sure pages are as expected. */ 1479 + for (i = 0; i < 10; i++) { 1480 + char *chrp = &ptr[i * page_size]; 1481 + 1482 + if (i % 2 == 0) { 1483 + bool result = try_read_write_buf(chrp); 1484 + 1485 + ASSERT_FALSE(result); 1486 + } else { 1487 + ASSERT_EQ(*chrp, 'a' + i); 1488 + } 1489 + } 1490 + 1491 + /* Now remove guard pages. */ 1492 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0); 1493 + 1494 + /* Now make sure all data is as expected. */ 1495 + if (!check_pattern(ptr, 10, page_size)) 1496 + ASSERT_TRUE(false); 1497 + 1498 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1499 + } 1500 + 1501 + /* 1502 + * Check that file-backed mappings implement guard regions with MAP_PRIVATE 1503 + * correctly. 1504 + */ 1505 + TEST_F(guard_regions, map_private) 1506 + { 1507 + const unsigned long page_size = self->page_size; 1508 + char *ptr_shared, *ptr_private; 1509 + int i; 1510 + 1511 + if (variant->backing == ANON_BACKED) 1512 + SKIP(return, "MAP_PRIVATE test specific to file-backed"); 1513 + 1514 + ptr_shared = mmap_(self, variant, NULL, 10 * page_size, PROT_READ | PROT_WRITE, 0, 0); 1515 + ASSERT_NE(ptr_shared, MAP_FAILED); 1516 + 1517 + /* Manually mmap(), do not use mmap_() wrapper so we can force MAP_PRIVATE. */ 1518 + ptr_private = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, self->fd, 0); 1519 + ASSERT_NE(ptr_private, MAP_FAILED); 1520 + 1521 + /* Set pattern in shared mapping. */ 1522 + set_pattern(ptr_shared, 10, page_size); 1523 + 1524 + /* Install guard regions in every other page in the shared mapping. */ 1525 + for (i = 0; i < 10; i += 2) { 1526 + char *ptr = &ptr_shared[i * page_size]; 1527 + 1528 + ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0); 1529 + } 1530 + 1531 + for (i = 0; i < 10; i++) { 1532 + /* Every even shared page should be guarded. */ 1533 + ASSERT_EQ(try_read_buf(&ptr_shared[i * page_size]), i % 2 != 0); 1534 + /* Private mappings should always be readable. */ 1535 + ASSERT_TRUE(try_read_buf(&ptr_private[i * page_size])); 1536 + } 1537 + 1538 + /* Install guard regions in every other page in the private mapping. */ 1539 + for (i = 0; i < 10; i += 2) { 1540 + char *ptr = &ptr_private[i * page_size]; 1541 + 1542 + ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0); 1543 + } 1544 + 1545 + for (i = 0; i < 10; i++) { 1546 + /* Every even shared page should be guarded. */ 1547 + ASSERT_EQ(try_read_buf(&ptr_shared[i * page_size]), i % 2 != 0); 1548 + /* Every odd private page should be guarded. */ 1549 + ASSERT_EQ(try_read_buf(&ptr_private[i * page_size]), i % 2 != 0); 1550 + } 1551 + 1552 + /* Remove guard regions from shared mapping. */ 1553 + ASSERT_EQ(madvise(ptr_shared, 10 * page_size, MADV_GUARD_REMOVE), 0); 1554 + 1555 + for (i = 0; i < 10; i++) { 1556 + /* Shared mappings should always be readable. */ 1557 + ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size])); 1558 + /* Every even private page should be guarded. */ 1559 + ASSERT_EQ(try_read_buf(&ptr_private[i * page_size]), i % 2 != 0); 1560 + } 1561 + 1562 + /* Remove guard regions from private mapping. */ 1563 + ASSERT_EQ(madvise(ptr_private, 10 * page_size, MADV_GUARD_REMOVE), 0); 1564 + 1565 + for (i = 0; i < 10; i++) { 1566 + /* Shared mappings should always be readable. */ 1567 + ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size])); 1568 + /* Private mappings should always be readable. */ 1569 + ASSERT_TRUE(try_read_buf(&ptr_private[i * page_size])); 1570 + } 1571 + 1572 + /* Ensure patterns are intact. */ 1573 + ASSERT_TRUE(check_pattern(ptr_shared, 10, page_size)); 1574 + ASSERT_TRUE(check_pattern(ptr_private, 10, page_size)); 1575 + 1576 + /* Now write out every other page to MAP_PRIVATE. */ 1577 + for (i = 0; i < 10; i += 2) { 1578 + char *ptr = &ptr_private[i * page_size]; 1579 + 1580 + memset(ptr, 'a' + i, page_size); 1581 + } 1582 + 1583 + /* 1584 + * At this point the mapping is: 1585 + * 1586 + * 0123456789 1587 + * SPSPSPSPSP 1588 + * 1589 + * Where S = shared, P = private mappings. 1590 + */ 1591 + 1592 + /* Now mark the beginning of the mapping guarded. */ 1593 + ASSERT_EQ(madvise(ptr_private, 5 * page_size, MADV_GUARD_INSTALL), 0); 1594 + 1595 + /* 1596 + * This renders the mapping: 1597 + * 1598 + * 0123456789 1599 + * xxxxxPSPSP 1600 + */ 1601 + 1602 + for (i = 0; i < 10; i++) { 1603 + char *ptr = &ptr_private[i * page_size]; 1604 + 1605 + /* Ensure guard regions as expected. */ 1606 + ASSERT_EQ(try_read_buf(ptr), i >= 5); 1607 + /* The shared mapping should always succeed. */ 1608 + ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size])); 1609 + } 1610 + 1611 + /* Remove the guard regions altogether. */ 1612 + ASSERT_EQ(madvise(ptr_private, 10 * page_size, MADV_GUARD_REMOVE), 0); 1613 + 1614 + /* 1615 + * 1616 + * We now expect the mapping to be: 1617 + * 1618 + * 0123456789 1619 + * SSSSSPSPSP 1620 + * 1621 + * As we removed guard regions, the private pages from the first 5 will 1622 + * have been zapped, so on fault will reestablish the shared mapping. 1623 + */ 1624 + 1625 + for (i = 0; i < 10; i++) { 1626 + char *ptr = &ptr_private[i * page_size]; 1627 + 1628 + /* 1629 + * Assert that shared mappings in the MAP_PRIVATE mapping match 1630 + * the shared mapping. 1631 + */ 1632 + if (i < 5 || i % 2 == 0) { 1633 + char *ptr_s = &ptr_shared[i * page_size]; 1634 + 1635 + ASSERT_EQ(memcmp(ptr, ptr_s, page_size), 0); 1636 + continue; 1637 + } 1638 + 1639 + /* Everything else is a private mapping. */ 1640 + ASSERT_TRUE(is_buf_eq(ptr, page_size, 'a' + i)); 1641 + } 1642 + 1643 + ASSERT_EQ(munmap(ptr_shared, 10 * page_size), 0); 1644 + ASSERT_EQ(munmap(ptr_private, 10 * page_size), 0); 1645 + } 1646 + 1647 + /* Test that guard regions established over a read-only mapping function correctly. */ 1648 + TEST_F(guard_regions, readonly_file) 1649 + { 1650 + const unsigned long page_size = self->page_size; 1651 + char *ptr; 1652 + int i; 1653 + 1654 + if (variant->backing == ANON_BACKED) 1655 + SKIP(return, "Read-only test specific to file-backed"); 1656 + 1657 + /* Map shared so we can populate with pattern, populate it, unmap. */ 1658 + ptr = mmap_(self, variant, NULL, 10 * page_size, 1659 + PROT_READ | PROT_WRITE, 0, 0); 1660 + ASSERT_NE(ptr, MAP_FAILED); 1661 + set_pattern(ptr, 10, page_size); 1662 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1663 + /* Close the fd so we can re-open read-only. */ 1664 + ASSERT_EQ(close(self->fd), 0); 1665 + 1666 + /* Re-open read-only. */ 1667 + self->fd = open(self->path, O_RDONLY); 1668 + ASSERT_NE(self->fd, -1); 1669 + /* Re-map read-only. */ 1670 + ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0); 1671 + ASSERT_NE(ptr, MAP_FAILED); 1672 + 1673 + /* Mark every other page guarded. */ 1674 + for (i = 0; i < 10; i += 2) { 1675 + char *ptr_pg = &ptr[i * page_size]; 1676 + 1677 + ASSERT_EQ(madvise(ptr_pg, page_size, MADV_GUARD_INSTALL), 0); 1678 + } 1679 + 1680 + /* Assert that the guard regions are in place.*/ 1681 + for (i = 0; i < 10; i++) { 1682 + char *ptr_pg = &ptr[i * page_size]; 1683 + 1684 + ASSERT_EQ(try_read_buf(ptr_pg), i % 2 != 0); 1685 + } 1686 + 1687 + /* Remove guard regions. */ 1688 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0); 1689 + 1690 + /* Ensure the data is as expected. */ 1691 + ASSERT_TRUE(check_pattern(ptr, 10, page_size)); 1692 + 1693 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1694 + } 1695 + 1696 + TEST_F(guard_regions, fault_around) 1697 + { 1698 + const unsigned long page_size = self->page_size; 1699 + char *ptr; 1700 + int i; 1701 + 1702 + if (variant->backing == ANON_BACKED) 1703 + SKIP(return, "Fault-around test specific to file-backed"); 1704 + 1705 + ptr = mmap_(self, variant, NULL, 10 * page_size, 1706 + PROT_READ | PROT_WRITE, 0, 0); 1707 + ASSERT_NE(ptr, MAP_FAILED); 1708 + 1709 + /* Establish a pattern in the backing file. */ 1710 + set_pattern(ptr, 10, page_size); 1711 + 1712 + /* 1713 + * Now drop it from the page cache so we get major faults when next we 1714 + * map it. 1715 + */ 1716 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0); 1717 + 1718 + /* Unmap and remap 'to be sure'. */ 1719 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1720 + ptr = mmap_(self, variant, NULL, 10 * page_size, 1721 + PROT_READ | PROT_WRITE, 0, 0); 1722 + ASSERT_NE(ptr, MAP_FAILED); 1723 + 1724 + /* Now make every even page guarded. */ 1725 + for (i = 0; i < 10; i += 2) { 1726 + char *ptr_p = &ptr[i * page_size]; 1727 + 1728 + ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0); 1729 + } 1730 + 1731 + /* Now fault in every odd page. This should trigger fault-around. */ 1732 + for (i = 1; i < 10; i += 2) { 1733 + char *ptr_p = &ptr[i * page_size]; 1734 + 1735 + ASSERT_TRUE(try_read_buf(ptr_p)); 1736 + } 1737 + 1738 + /* Finally, ensure that guard regions are intact as expected. */ 1739 + for (i = 0; i < 10; i++) { 1740 + char *ptr_p = &ptr[i * page_size]; 1741 + 1742 + ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0); 1743 + } 1744 + 1745 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1746 + } 1747 + 1748 + TEST_F(guard_regions, truncation) 1749 + { 1750 + const unsigned long page_size = self->page_size; 1751 + char *ptr; 1752 + int i; 1753 + 1754 + if (variant->backing == ANON_BACKED) 1755 + SKIP(return, "Truncation test specific to file-backed"); 1756 + 1757 + ptr = mmap_(self, variant, NULL, 10 * page_size, 1758 + PROT_READ | PROT_WRITE, 0, 0); 1759 + ASSERT_NE(ptr, MAP_FAILED); 1760 + 1761 + /* 1762 + * Establish a pattern in the backing file, just so there is data 1763 + * there. 1764 + */ 1765 + set_pattern(ptr, 10, page_size); 1766 + 1767 + /* Now make every even page guarded. */ 1768 + for (i = 0; i < 10; i += 2) { 1769 + char *ptr_p = &ptr[i * page_size]; 1770 + 1771 + ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0); 1772 + } 1773 + 1774 + /* Now assert things are as expected. */ 1775 + for (i = 0; i < 10; i++) { 1776 + char *ptr_p = &ptr[i * page_size]; 1777 + 1778 + ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0); 1779 + } 1780 + 1781 + /* Now truncate to actually used size (initialised to 100). */ 1782 + ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0); 1783 + 1784 + /* Here the guard regions will remain intact. */ 1785 + for (i = 0; i < 10; i++) { 1786 + char *ptr_p = &ptr[i * page_size]; 1787 + 1788 + ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0); 1789 + } 1790 + 1791 + /* Now truncate to half the size, then truncate again to the full size. */ 1792 + ASSERT_EQ(ftruncate(self->fd, 5 * page_size), 0); 1793 + ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0); 1794 + 1795 + /* Again, guard pages will remain intact. */ 1796 + for (i = 0; i < 10; i++) { 1797 + char *ptr_p = &ptr[i * page_size]; 1798 + 1799 + ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0); 1800 + } 1801 + 1802 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1803 + } 1804 + 1805 + TEST_F(guard_regions, hole_punch) 1806 + { 1807 + const unsigned long page_size = self->page_size; 1808 + char *ptr; 1809 + int i; 1810 + 1811 + if (variant->backing == ANON_BACKED) 1812 + SKIP(return, "Truncation test specific to file-backed"); 1813 + 1814 + /* Establish pattern in mapping. */ 1815 + ptr = mmap_(self, variant, NULL, 10 * page_size, 1816 + PROT_READ | PROT_WRITE, 0, 0); 1817 + ASSERT_NE(ptr, MAP_FAILED); 1818 + set_pattern(ptr, 10, page_size); 1819 + 1820 + /* Install a guard region in the middle of the mapping. */ 1821 + ASSERT_EQ(madvise(&ptr[3 * page_size], 4 * page_size, 1822 + MADV_GUARD_INSTALL), 0); 1823 + 1824 + /* 1825 + * The buffer will now be: 1826 + * 1827 + * 0123456789 1828 + * ***xxxx*** 1829 + * 1830 + * Where * is data and x is the guard region. 1831 + */ 1832 + 1833 + /* Ensure established. */ 1834 + for (i = 0; i < 10; i++) { 1835 + char *ptr_p = &ptr[i * page_size]; 1836 + 1837 + ASSERT_EQ(try_read_buf(ptr_p), i < 3 || i >= 7); 1838 + } 1839 + 1840 + /* Now hole punch the guarded region. */ 1841 + ASSERT_EQ(madvise(&ptr[3 * page_size], 4 * page_size, 1842 + MADV_REMOVE), 0); 1843 + 1844 + /* Ensure guard regions remain. */ 1845 + for (i = 0; i < 10; i++) { 1846 + char *ptr_p = &ptr[i * page_size]; 1847 + 1848 + ASSERT_EQ(try_read_buf(ptr_p), i < 3 || i >= 7); 1849 + } 1850 + 1851 + /* Now remove guard region throughout. */ 1852 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0); 1853 + 1854 + /* Check that the pattern exists in non-hole punched region. */ 1855 + ASSERT_TRUE(check_pattern(ptr, 3, page_size)); 1856 + /* Check that hole punched region is zeroed. */ 1857 + ASSERT_TRUE(is_buf_eq(&ptr[3 * page_size], 4 * page_size, '\0')); 1858 + /* Check that the pattern exists in the remainder of the file. */ 1859 + ASSERT_TRUE(check_pattern_offset(ptr, 3, page_size, 7)); 1860 + 1861 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1862 + } 1863 + 1864 + /* 1865 + * Ensure that a memfd works correctly with guard regions, that we can write 1866 + * seal it then open the mapping read-only and still establish guard regions 1867 + * within, remove those guard regions and have everything work correctly. 1868 + */ 1869 + TEST_F(guard_regions, memfd_write_seal) 1870 + { 1871 + const unsigned long page_size = self->page_size; 1872 + char *ptr; 1873 + int i; 1874 + 1875 + if (variant->backing != SHMEM_BACKED) 1876 + SKIP(return, "memfd write seal test specific to shmem"); 1877 + 1878 + /* OK, we need a memfd, so close existing one. */ 1879 + ASSERT_EQ(close(self->fd), 0); 1880 + 1881 + /* Create and truncate memfd. */ 1882 + self->fd = memfd_create("guard_regions_memfd_seals_test", 1883 + MFD_ALLOW_SEALING); 1884 + ASSERT_NE(self->fd, -1); 1885 + ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0); 1886 + 1887 + /* Map, set pattern, unmap. */ 1888 + ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ | PROT_WRITE, 0, 0); 1889 + ASSERT_NE(ptr, MAP_FAILED); 1890 + set_pattern(ptr, 10, page_size); 1891 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1892 + 1893 + /* Write-seal the memfd. */ 1894 + ASSERT_EQ(fcntl(self->fd, F_ADD_SEALS, F_SEAL_WRITE), 0); 1895 + 1896 + /* Now map the memfd readonly. */ 1897 + ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0); 1898 + ASSERT_NE(ptr, MAP_FAILED); 1899 + 1900 + /* Ensure pattern is as expected. */ 1901 + ASSERT_TRUE(check_pattern(ptr, 10, page_size)); 1902 + 1903 + /* Now make every even page guarded. */ 1904 + for (i = 0; i < 10; i += 2) { 1905 + char *ptr_p = &ptr[i * page_size]; 1906 + 1907 + ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0); 1908 + } 1909 + 1910 + /* Now assert things are as expected. */ 1911 + for (i = 0; i < 10; i++) { 1912 + char *ptr_p = &ptr[i * page_size]; 1913 + 1914 + ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0); 1915 + } 1916 + 1917 + /* Now remove guard regions. */ 1918 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0); 1919 + 1920 + /* Ensure pattern is as expected. */ 1921 + ASSERT_TRUE(check_pattern(ptr, 10, page_size)); 1922 + 1923 + /* Ensure write seal intact. */ 1924 + for (i = 0; i < 10; i++) { 1925 + char *ptr_p = &ptr[i * page_size]; 1926 + 1927 + ASSERT_FALSE(try_write_buf(ptr_p)); 1928 + } 1929 + 1930 + ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1931 + } 1932 + 1933 + 1934 + /* 1935 + * Since we are now permitted to establish guard regions in read-only anonymous 1936 + * mappings, for the sake of thoroughness, though it probably has no practical 1937 + * use, test that guard regions function with a mapping to the anonymous zero 1938 + * page. 1939 + */ 1940 + TEST_F(guard_regions, anon_zeropage) 1941 + { 1942 + const unsigned long page_size = self->page_size; 1943 + char *ptr; 1944 + int i; 1945 + 1946 + if (!is_anon_backed(variant)) 1947 + SKIP(return, "anon zero page test specific to anon/shmem"); 1948 + 1949 + /* Obtain a read-only i.e. anon zero page mapping. */ 1950 + ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0); 1951 + ASSERT_NE(ptr, MAP_FAILED); 1952 + 1953 + /* Now make every even page guarded. */ 1954 + for (i = 0; i < 10; i += 2) { 1955 + char *ptr_p = &ptr[i * page_size]; 1956 + 1957 + ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0); 1958 + } 1959 + 1960 + /* Now assert things are as expected. */ 1961 + for (i = 0; i < 10; i++) { 1962 + char *ptr_p = &ptr[i * page_size]; 1963 + 1964 + ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0); 1965 + } 1966 + 1967 + /* Now remove all guard regions. */ 1968 + ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0); 1969 + 1970 + /* Now assert things are as expected. */ 1971 + for (i = 0; i < 10; i++) { 1972 + char *ptr_p = &ptr[i * page_size]; 1973 + 1974 + ASSERT_TRUE(try_read_buf(ptr_p)); 1975 + } 1976 + 1977 + /* Ensure zero page...*/ 1978 + ASSERT_TRUE(is_buf_eq(ptr, 10 * page_size, '\0')); 1979 + 1489 1980 ASSERT_EQ(munmap(ptr, 10 * page_size), 0); 1490 1981 } 1491 1982