Add mseal(2) wrapper.
Change-Id: I053b2d570cd5750285fc20e9e237e04d59778bf5
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 182de17..0899264 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -126,6 +126,7 @@
int mlock2(const void* addr, size_t len, int flags) all
int munlock(const void* addr, size_t len) all
int mlockall(int flags) all
+int mseal(void*, size_t, unsigned long) lp64
int munlockall() all
int mincore(void* start, size_t length, unsigned char* vec) all
int __ioctl:ioctl(int, int, void*) all
diff --git a/libc/bionic/legacy_32_bit_support.cpp b/libc/bionic/legacy_32_bit_support.cpp
index 4e19ebf..e66126b 100644
--- a/libc/bionic/legacy_32_bit_support.cpp
+++ b/libc/bionic/legacy_32_bit_support.cpp
@@ -161,3 +161,9 @@
}
return __mremap(old_address, old_size, new_size, flags, new_address);
}
+
+// mseal(2) is LP64-only.
+int mseal(void*, size_t, unsigned long) {
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/libc/include/sys/mman.h b/libc/include/sys/mman.h
index 823c9ba..26d08c3 100644
--- a/libc/include/sys/mman.h
+++ b/libc/include/sys/mman.h
@@ -222,4 +222,16 @@
*/
int posix_madvise(void* _Nonnull __addr, size_t __size, int __advice) __INTRODUCED_IN(23);
+/**
+ * [mseal(2)](https://man7.org/linux/man-pages/man2/mseal.2.html)
+ * seals the given range to prevent modifications such as mprotect() calls.
+ *
+ * Available since API level 36.
+ * Requires a Linux 6.10 or newer kernel.
+ * Always fails for 32-bit processes.
+ *
+ * Returns 0 on success, and returns -1 and sets `errno` on failure.
+ */
+int mseal(void* _Nonnull __addr, size_t __size, unsigned long __flags) __INTRODUCED_IN(36);
+
__END_DECLS
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index ffd5d1e..8bb84eb 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -670,6 +670,7 @@
mprotect;
mrand48;
mremap;
+ mseal; # introduced=36
msync;
munlock;
munlockall;
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index 40c85f2..54a0b64 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -320,3 +320,30 @@
close(fd);
#endif
}
+
+TEST(sys_mseal, mseal) {
+#if defined(__GLIBC__)
+ GTEST_SKIP() << "needs glibc 2.40";
+#else
+ void* map = mmap(nullptr, kPageSize, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, map);
+
+#if defined(__LP64__)
+ int rc = mseal(map, kPageSize, 0);
+ if (rc == -1) {
+ ASSERT_ERRNO(ENOSYS);
+ GTEST_SKIP() << "needs kernel with mseal(2)";
+ }
+ ASSERT_EQ(-1, mprotect(map, kPageSize, PROT_READ));
+ ASSERT_ERRNO(EPERM);
+#else
+ // No mseal() for ILP32.
+ errno = 0;
+ ASSERT_EQ(-1, mseal(map, kPageSize, 0));
+ ASSERT_ERRNO(ENOSYS);
+ GTEST_SKIP() << "mseal(2) is LP64-only";
+#endif
+
+ // We can't munmap() our test mapping if mseal() actually succeeded :-)
+#endif
+}