From: "Isaac J. Manjarres" <isaacmanjarres@google.com>
To: Andrew Morton <akpm@linux-foundation.org>,
Jeff Layton <jlayton@kernel.org>,
Chuck Lever <chuck.lever@oracle.com>,
Alexander Aring <alex.aring@gmail.com>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
Lorenzo Stoakes <lorenzo.stoakes@oracle.com>,
Vlastimil Babka <vbabka@suse.cz>, Jann Horn <jannh@google.com>,
Shuah Khan <shuah@kernel.org>
Cc: "Isaac J. Manjarres" <isaacmanjarres@google.com>,
kernel-team@android.com, linux-mm@kvack.org,
linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
linux-kselftest@vger.kernel.org,
Suren Baghdasaryan <surenb@google.com>,
Kalesh Singh <kaleshsingh@google.com>,
John Stultz <jstultz@google.com>
Subject: [RFC PATCH v1 1/2] mm/memfd: Add support for F_SEAL_FUTURE_EXEC to memfd
Date: Thu, 5 Dec 2024 17:09:22 -0800 [thread overview]
Message-ID: <20241206010930.3871336-2-isaacmanjarres@google.com> (raw)
In-Reply-To: <20241206010930.3871336-1-isaacmanjarres@google.com>
Android currently uses the ashmem driver [1] for creating shared memory
regions between processes. Ashmem buffers can initially be mapped with
PROT_READ, PROT_WRITE, and PROT_EXEC. Processes can then use the
ASHMEM_SET_PROT_MASK ioctl command to restrict--never add--the
permissions that the buffer can be mapped with.
Processes can remove the ability to map ashmem buffers as executable to
ensure that those buffers cannot be exploited to run unintended code.
We are currently trying to replace ashmem with memfd. However, memfd
does not have a provision to permanently remove the ability to map a
buffer as executable. Although, this should be something that can be
achieved via a new file seal.
There are known usecases (e.g. CursorWindow [2]) where a process
maps a buffer with read/write permissions before restricting the buffer
to being mapped as read-only for future mappings.
The resulting VMA from the writable mapping has VM_MAYEXEC set, meaning
that mprotect() can change the mapping to be executable. Therefore,
implementing the seal similar to F_SEAL_WRITE would not be appropriate,
since it would not work with the CursorWindow usecase. This is because
the CursorWindow process restricts the mapping permissions to read-only
after the writable mapping is created. So, adding a file seal for
executable mappings that operates like F_SEAL_WRITE would fail.
Therefore, add support for F_SEAL_FUTURE_EXEC, which is handled
similarly to F_SEAL_FUTURE_WRITE. This ensures that CursorWindow can
continue to create a writable mapping initially, and then restrict the
permissions on the buffer to be mappable as read-only by using both
F_SEAL_FUTURE_WRITE and F_SEAL_FUTURE_EXEC. After the seal is
applied, any calls to mmap() with PROT_EXEC will fail.
[1] https://cs.android.com/android/kernel/superproject/+/common-android-mainline:common/drivers/staging/android/ashmem.c
[2] https://developer.android.com/reference/android/database/CursorWindow
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: John Stultz <jstultz@google.com>
Signed-off-by: Isaac J. Manjarres <isaacmanjarres@google.com>
---
include/linux/mm.h | 5 +++++
include/uapi/linux/fcntl.h | 1 +
mm/memfd.c | 1 +
mm/mmap.c | 11 +++++++++++
4 files changed, 18 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4eb8e62d5c67..40c03a491e45 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -4096,6 +4096,11 @@ static inline bool is_write_sealed(int seals)
return seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE);
}
+static inline bool is_exec_sealed(int seals)
+{
+ return seals & F_SEAL_FUTURE_EXEC;
+}
+
/**
* is_readonly_sealed - Checks whether write-sealed but mapped read-only,
* in which case writes should be disallowing moving
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index 6e6907e63bfc..ef066e524777 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -49,6 +49,7 @@
#define F_SEAL_WRITE 0x0008 /* prevent writes */
#define F_SEAL_FUTURE_WRITE 0x0010 /* prevent future writes while mapped */
#define F_SEAL_EXEC 0x0020 /* prevent chmod modifying exec bits */
+#define F_SEAL_FUTURE_EXEC 0x0040 /* prevent future executable mappings */
/* (1U << 31) is reserved for signed error codes */
/*
diff --git a/mm/memfd.c b/mm/memfd.c
index 35a370d75c9a..77b49995a044 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -184,6 +184,7 @@ unsigned int *memfd_file_seals_ptr(struct file *file)
}
#define F_ALL_SEALS (F_SEAL_SEAL | \
+ F_SEAL_FUTURE_EXEC |\
F_SEAL_EXEC | \
F_SEAL_SHRINK | \
F_SEAL_GROW | \
diff --git a/mm/mmap.c b/mm/mmap.c
index b1b2a24ef82e..c7b96b057fda 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -375,6 +375,17 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
if (!file_mmap_ok(file, inode, pgoff, len))
return -EOVERFLOW;
+ if (is_exec_sealed(seals)) {
+ /* No new executable mappings if the file is exec sealed. */
+ if (prot & PROT_EXEC)
+ return -EACCES;
+ /*
+ * Prevent an initially non-executable mapping from
+ * later becoming executable via mprotect().
+ */
+ vm_flags &= ~VM_MAYEXEC;
+ }
+
flags_mask = LEGACY_MAP_MASK;
if (file->f_op->fop_flags & FOP_MMAP_SYNC)
flags_mask |= MAP_SYNC;
--
2.47.0.338.g60cca15819-goog
next prev parent reply other threads:[~2024-12-06 1:09 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-06 1:09 [RFC PATCH v1 0/2] Add file seal to prevent future exec mappings Isaac J. Manjarres
2024-12-06 1:09 ` Isaac J. Manjarres [this message]
2024-12-06 17:49 ` [RFC PATCH v1 1/2] mm/memfd: Add support for F_SEAL_FUTURE_EXEC to memfd Kalesh Singh
2024-12-06 20:50 ` Isaac Manjarres
2024-12-06 18:19 ` Lorenzo Stoakes
2024-12-06 20:48 ` Isaac Manjarres
2024-12-06 21:14 ` Lorenzo Stoakes
2024-12-11 20:56 ` Isaac Manjarres
2025-01-03 15:13 ` Jann Horn
2025-01-06 18:26 ` Jeff Xu
2025-01-07 0:44 ` Kees Cook
2025-01-08 19:06 ` Lorenzo Stoakes
2025-01-08 22:07 ` Kees Cook
2025-01-09 23:30 ` Jeff Xu
2025-01-14 20:02 ` Isaac Manjarres
2025-01-14 21:29 ` Kees Cook
2025-01-14 22:42 ` Isaac Manjarres
2025-01-14 23:41 ` Jeff Xu
2025-01-14 23:56 ` Jeff Xu
2024-12-06 1:09 ` [RFC PATCH v1 2/2] selftests/memfd: Add tests for F_SEAL_FUTURE_EXEC Isaac J. Manjarres
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241206010930.3871336-2-isaacmanjarres@google.com \
--to=isaacmanjarres@google.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=alex.aring@gmail.com \
--cc=chuck.lever@oracle.com \
--cc=jannh@google.com \
--cc=jlayton@kernel.org \
--cc=jstultz@google.com \
--cc=kaleshsingh@google.com \
--cc=kernel-team@android.com \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lorenzo.stoakes@oracle.com \
--cc=shuah@kernel.org \
--cc=surenb@google.com \
--cc=vbabka@suse.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox