* [LTP] [PATCH v1] memfd_create01: Reject F_SEAL_EXEC over a writable mapping
@ 2026-11-05 21:55 Stephen Bertram via ltp
2026-11-05 22:22 ` [LTP] " linuxtestproject.agent
0 siblings, 1 reply; 2+ messages in thread
From: Stephen Bertram via ltp @ 2026-11-05 21:55 UTC (permalink / raw)
To: ltp; +Cc: Stephen Bertram, Cursor
From: Stephen Bertram <sbertram@redhat.com>
On an executable memfd, F_SEAL_EXEC implies the write and size seals.
Adding it while a writable shared mapping exists must fail with EBUSY.
With no mapping held, the implied seals must be set.
Assisted-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Stephen Bertram <sbertram@redhat.com>
---
include/lapi/fcntl.h | 6 +
.../syscalls/memfd_create/memfd_create01.c | 107 +++++++++++++++++-
2 files changed, 111 insertions(+), 2 deletions(-)
diff --git a/include/lapi/fcntl.h b/include/lapi/fcntl.h
index d70954ea7..d826acba5 100644
--- a/include/lapi/fcntl.h
+++ b/include/lapi/fcntl.h
@@ -65,6 +65,12 @@
#ifndef F_SEAL_WRITE
# define F_SEAL_WRITE 0x0008 /* prevent writes */
#endif
+#ifndef F_SEAL_FUTURE_WRITE
+# define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */
+#endif
+#ifndef F_SEAL_EXEC
+# define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */
+#endif
#ifndef F_OWNER_PGRP
# define F_OWNER_PGRP 2
diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create01.c b/testcases/kernel/syscalls/memfd_create/memfd_create01.c
index 28ad04a86..64e9daa77 100644
--- a/testcases/kernel/syscalls/memfd_create/memfd_create01.c
+++ b/testcases/kernel/syscalls/memfd_create/memfd_create01.c
@@ -1,12 +1,16 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Copyright (c) Linux Test Project, 2017-2020
+ * Copyright (c) Linux Test Project, 2017-2026
* Copyright (C) 2017 Red Hat, Inc.
* Port to LTP <jracek@redhat.com>
*/
/*\
* Test based on :kselftest:`memfd/memfd_test.c`.
+ *
+ * On an executable memfd, F_SEAL_EXEC implies F_SEAL_WRITE,
+ * F_SEAL_FUTURE_WRITE, F_SEAL_SHRINK and F_SEAL_GROW. F_SEAL_EXEC is
+ * rejected with EBUSY while a writable shared mapping exists.
*/
#define _GNU_SOURCE
@@ -15,6 +19,9 @@
#include "tst_test.h"
#include "memfd_create_common.h"
+#define SEAL_EXEC_IMPLIED (F_SEAL_EXEC | F_SEAL_SHRINK | F_SEAL_GROW | \
+ F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)
+
/*
* Do few basic sealing tests to see whether setting/retrieving seals works.
*/
@@ -68,6 +75,75 @@ static void test_seal_write(int fd)
CHECK_MFD_NON_GROWABLE_BY_WRITE(fd);
}
+/*
+ * F_SEAL_EXEC is only meaningful once the kernel knows the flag. Probe a
+ * separate memfd so a missing flag does not seal the caller's fd.
+ * Returns 1 when F_ADD_SEALS accepts F_SEAL_EXEC, 0 when the kernel rejects
+ * the flag with EINVAL.
+ */
+static int seal_exec_supported(void)
+{
+ static int supported = -1;
+ int fd;
+
+ if (supported >= 0)
+ return supported;
+
+ fd = sys_memfd_create("ltp_memfd_seal_exec", MFD_ALLOW_SEALING);
+ if (fd < 0)
+ tst_brk(TBROK | TERRNO, "memfd_create() for F_SEAL_EXEC probe");
+
+ TEST(fcntl(fd, F_ADD_SEALS, F_SEAL_EXEC));
+ SAFE_CLOSE(fd);
+
+ if (TST_RET == 0)
+ supported = 1;
+ else if (TST_ERR == EINVAL)
+ supported = 0;
+ else
+ tst_brk(TBROK | TTERRNO, "fcntl(F_ADD_SEALS, F_SEAL_EXEC)");
+
+ return supported;
+}
+
+/* F_SEAL_EXEC implies F_SEAL_WRITE only when the file mode is executable. */
+static int memfd_is_executable(int fd)
+{
+ struct stat st;
+
+ SAFE_FSTAT(fd, &st);
+
+ return !!(st.st_mode & 0111);
+}
+
+/*
+ * Test SEAL_EXEC
+ * On an executable memfd, F_SEAL_EXEC implies the write and size seals.
+ */
+static void test_seal_exec(int fd)
+{
+ if (!memfd_is_executable(fd)) {
+ tst_res(TCONF,
+ "no execute bit, F_SEAL_EXEC does not imply F_SEAL_WRITE");
+ return;
+ }
+
+ if (!seal_exec_supported()) {
+ tst_res(TCONF, "F_SEAL_EXEC is not supported");
+ return;
+ }
+
+ CHECK_MFD_HAS_SEALS(fd, 0);
+ CHECK_MFD_ADD_SEALS(fd, F_SEAL_EXEC);
+ CHECK_MFD_HAS_SEALS(fd, SEAL_EXEC_IMPLIED);
+
+ CHECK_MFD_READABLE(fd);
+ CHECK_MFD_NON_WRITEABLE(fd);
+ CHECK_MFD_NON_SHRINKABLE(fd);
+ CHECK_MFD_NON_GROWABLE(fd);
+ CHECK_MFD_NON_GROWABLE_BY_WRITE(fd);
+}
+
/*
* Test SEAL_SHRINK
* Test whether SEAL_SHRINK actually prevents shrinking
@@ -164,12 +240,34 @@ static void test_share_mmap(int fd)
CHECK_MFD_HAS_SEALS(fd, 0);
- /* shared/writable ref prevents sealing WRITE, but allows others */
+ /*
+ * A shared writable mapping blocks F_SEAL_WRITE. F_SEAL_EXEC is
+ * blocked too when it would imply F_SEAL_WRITE. Other seals, such
+ * as F_SEAL_SHRINK, are still allowed.
+ */
p = SAFE_MMAP(NULL, MFD_DEF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
fd, 0);
CHECK_MFD_FAIL_ADD_SEALS(fd, F_SEAL_WRITE);
CHECK_MFD_HAS_SEALS(fd, 0);
+
+ if (memfd_is_executable(fd) && seal_exec_supported()) {
+ TST_EXP_FAIL(fcntl(fd, F_ADD_SEALS, F_SEAL_EXEC), EBUSY,
+ "F_SEAL_EXEC while a writable mapping exists");
+ if (!TST_PASS) {
+ SAFE_MUNMAP(p, MFD_DEF_SIZE);
+ return;
+ }
+
+ CHECK_MFD_HAS_SEALS(fd, 0);
+
+ *(volatile char *)p = 'x';
+ if (*(volatile char *)p != 'x')
+ tst_res(TFAIL, "writable mapping did not retain the write");
+ else
+ tst_res(TPASS, "writable mapping remained writable");
+ }
+
CHECK_MFD_ADD_SEALS(fd, F_SEAL_SHRINK);
CHECK_MFD_HAS_SEALS(fd, F_SEAL_SHRINK);
SAFE_MUNMAP(p, MFD_DEF_SIZE);
@@ -221,6 +319,7 @@ static const struct tcase {
{0, &test_no_sealing_without_flag, "Disabled sealing"},
{MFD_ALLOW_SEALING, &test_seal_write, "Write seal"},
+ {MFD_ALLOW_SEALING, &test_seal_exec, "Exec seal implies write seals"},
{MFD_ALLOW_SEALING, &test_seal_shrink, "Shrink seal"},
{MFD_ALLOW_SEALING, &test_seal_grow, "Grow seal"},
{MFD_ALLOW_SEALING, &test_seal_resize, "Resize seal"},
@@ -264,4 +363,8 @@ static struct tst_test test = {
.test = verify_memfd_create,
.tcnt = ARRAY_SIZE(tcases),
.setup = setup,
+ .tags = (const struct tst_tag[]) {
+ {"linux-git", "3b041514cb6e"},
+ {}
+ },
};
--
2.55.0
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [LTP] memfd_create01: Reject F_SEAL_EXEC over a writable mapping
2026-11-05 21:55 [LTP] [PATCH v1] memfd_create01: Reject F_SEAL_EXEC over a writable mapping Stephen Bertram via ltp
@ 2026-11-05 22:22 ` linuxtestproject.agent
0 siblings, 0 replies; 2+ messages in thread
From: linuxtestproject.agent @ 2026-11-05 22:22 UTC (permalink / raw)
To: Stephen Bertram; +Cc: ltp
Hi Stephen,
On Thu Nov 5 16:55:02 2026 -0500, Stephen Bertram <sbertram@redhat.com> wrote:
> memfd_create01: Reject F_SEAL_EXEC over a writable mapping
Verdict - Reviewed
---
Note:
The agent can sometimes produce false positives although often its
findings are genuine. If you find issues with the review, please
comment this email or ignore the suggestions.
Regards,
LTP AI Reviewer
--
Mailing list info: https://lists.linux.it/listinfo/ltp
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-05 22:23 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-05 21:55 [LTP] [PATCH v1] memfd_create01: Reject F_SEAL_EXEC over a writable mapping Stephen Bertram via ltp
2026-11-05 22:22 ` [LTP] " linuxtestproject.agent
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.