include/linux/memfd.h | 2 ++ mm/memfd.c | 14 ++++++++++-- security/selinux/hooks.c | 26 +++++++++++++++++----- security/selinux/include/classmap.h | 2 ++ security/selinux/include/policycap.h | 1 + security/selinux/include/policycap_names.h | 1 + security/selinux/include/security.h | 5 +++++ 7 files changed, 44 insertions(+), 7 deletions(-)
Prior to this change, no security hooks were called at the creation of a
memfd file. It means that, for SELinux as an example, it will receive
the default type of the filesystem that backs the in-memory inode. In
most cases, that would be tmpfs, but if MFD_HUGETLB is passed, it will
be hugetlbfs. Both can be considered implementation details of memfd.
It also means that it is not possible to differentiate between a file
coming from memfd_create and a file coming from a standard tmpfs mount
point.
Additionally, no permission is validated at creation, which differs from
the similar memfd_secret syscall.
Call security_inode_init_security_anon during creation. This ensures
that the file is setup similarly to other anonymous inodes. On SELinux,
it means that the file will receive the security context of its task.
The ability to limit fexecve on memfd has been of interest to avoid
potential pitfalls where /proc/self/exe or similar would be executed
[1][2]. Reuse the "execute_no_trans" and "entrypoint" access vectors,
similarly to the file class. These access vectors may not make sense for
the existing "anon_inode" class. Therefore, define and assign a new
class "memfd_file" to support such access vectors.
Guard these changes behind a new policy capability named "memfd_class".
[1] https://crbug.com/1305267
[2] https://lore.kernel.org/lkml/20221215001205.51969-1-jeffxu@google.com/
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
---
Changes since v2:
- Add WARN_ON when using unexpected class. Return -EACCES instead
of -EPERM
- Remove extra new line
- Rebase on selinux/dev
Changes since v1:
- Move test of class earlier in selinux_bprm_creds_for_exec
- Remove duplicate call to security_transition_sid
Changes since RFC:
- Remove enum argument, simply compare the anon inode name
- Introduce a policy capability for compatility
- Add validation of class in selinux_bprm_creds_for_exec
include/linux/memfd.h | 2 ++
mm/memfd.c | 14 ++++++++++--
security/selinux/hooks.c | 26 +++++++++++++++++-----
security/selinux/include/classmap.h | 2 ++
security/selinux/include/policycap.h | 1 +
security/selinux/include/policycap_names.h | 1 +
security/selinux/include/security.h | 5 +++++
7 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/include/linux/memfd.h b/include/linux/memfd.h
index 6f606d9573c3..cc74de3dbcfe 100644
--- a/include/linux/memfd.h
+++ b/include/linux/memfd.h
@@ -4,6 +4,8 @@
#include <linux/file.h>
+#define MEMFD_ANON_NAME "[memfd]"
+
#ifdef CONFIG_MEMFD_CREATE
extern long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg);
struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx);
diff --git a/mm/memfd.c b/mm/memfd.c
index bbe679895ef6..63b439eb402a 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -433,6 +433,8 @@ static struct file *alloc_file(const char *name, unsigned int flags)
{
unsigned int *file_seals;
struct file *file;
+ struct inode *inode;
+ int err = 0;
if (flags & MFD_HUGETLB) {
file = hugetlb_file_setup(name, 0, VM_NORESERVE,
@@ -444,12 +446,20 @@ static struct file *alloc_file(const char *name, unsigned int flags)
}
if (IS_ERR(file))
return file;
+
+ inode = file_inode(file);
+ err = security_inode_init_security_anon(inode,
+ &QSTR(MEMFD_ANON_NAME), NULL);
+ if (err) {
+ fput(file);
+ file = ERR_PTR(err);
+ return file;
+ }
+
file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
file->f_flags |= O_LARGEFILE;
if (flags & MFD_NOEXEC_SEAL) {
- struct inode *inode = file_inode(file);
-
inode->i_mode &= ~0111;
file_seals = memfd_file_seals_ptr(file);
if (file_seals) {
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0e47b4bb8d40..2b685f9dd61d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -93,6 +93,7 @@
#include <linux/fanotify.h>
#include <linux/io_uring/cmd.h>
#include <uapi/linux/lsm.h>
+#include <linux/memfd.h>
#include "avc.h"
#include "objsec.h"
@@ -2319,6 +2320,10 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
new_tsec = selinux_cred(bprm->cred);
isec = inode_security(inode);
+ if (WARN_ON(isec->sclass != SECCLASS_FILE &&
+ isec->sclass != SECCLASS_MEMFD_FILE))
+ return -EACCES;
+
/* Default to the current task SID. */
new_tsec->sid = old_tsec->sid;
new_tsec->osid = old_tsec->sid;
@@ -2371,8 +2376,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
- rc = avc_has_perm(old_tsec->sid, isec->sid,
- SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
+ rc = avc_has_perm(old_tsec->sid, isec->sid, isec->sclass,
+ FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
@@ -2382,8 +2387,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
if (rc)
return rc;
- rc = avc_has_perm(new_tsec->sid, isec->sid,
- SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
+ rc = avc_has_perm(new_tsec->sid, isec->sid, isec->sclass,
+ FILE__ENTRYPOINT, &ad);
if (rc)
return rc;
@@ -2978,10 +2983,18 @@ static int selinux_inode_init_security_anon(struct inode *inode,
struct common_audit_data ad;
struct inode_security_struct *isec;
int rc;
+ bool is_memfd = false;
if (unlikely(!selinux_initialized()))
return 0;
+ if (name != NULL && name->name != NULL &&
+ !strcmp(name->name, MEMFD_ANON_NAME)) {
+ if (!selinux_policycap_memfd_class())
+ return 0;
+ is_memfd = true;
+ }
+
isec = selinux_inode(inode);
/*
@@ -3001,7 +3014,10 @@ static int selinux_inode_init_security_anon(struct inode *inode,
isec->sclass = context_isec->sclass;
isec->sid = context_isec->sid;
} else {
- isec->sclass = SECCLASS_ANON_INODE;
+ if (is_memfd)
+ isec->sclass = SECCLASS_MEMFD_FILE;
+ else
+ isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid(
sid, sid,
isec->sclass, name, &isec->sid);
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 5665aa5e7853..3ec85142771f 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -179,6 +179,8 @@ const struct security_class_mapping secclass_map[] = {
{ "anon_inode", { COMMON_FILE_PERMS, NULL } },
{ "io_uring", { "override_creds", "sqpoll", "cmd", "allowed", NULL } },
{ "user_namespace", { "create", NULL } },
+ { "memfd_file",
+ { COMMON_FILE_PERMS, "execute_no_trans", "entrypoint", NULL } },
/* last one */ { NULL, {} }
};
diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h
index 135a969f873c..231d02227e59 100644
--- a/security/selinux/include/policycap.h
+++ b/security/selinux/include/policycap.h
@@ -18,6 +18,7 @@ enum {
POLICYDB_CAP_NETIF_WILDCARD,
POLICYDB_CAP_GENFS_SECLABEL_WILDCARD,
POLICYDB_CAP_FUNCTIONFS_SECLABEL,
+ POLICYDB_CAP_MEMFD_CLASS,
__POLICYDB_CAP_MAX
};
#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h
index ff8882887651..454dab37bda3 100644
--- a/security/selinux/include/policycap_names.h
+++ b/security/selinux/include/policycap_names.h
@@ -21,6 +21,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = {
"netif_wildcard",
"genfs_seclabel_wildcard",
"functionfs_seclabel",
+ "memfd_class",
};
/* clang-format on */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 0f954a40d3fc..5d1dad8058b1 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -209,6 +209,11 @@ static inline bool selinux_policycap_functionfs_seclabel(void)
selinux_state.policycap[POLICYDB_CAP_FUNCTIONFS_SECLABEL]);
}
+static inline bool selinux_policycap_memfd_class(void)
+{
+ return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]);
+}
+
struct selinux_policy_convert_data;
struct selinux_load_state {
--
2.51.0.384.g4c02a37b29-goog
On Wed, Sep 17, 2025 at 10:04 PM Thiébaud Weksteen <tweek@google.com> wrote: > > Prior to this change, no security hooks were called at the creation of a > memfd file. It means that, for SELinux as an example, it will receive > the default type of the filesystem that backs the in-memory inode. In > most cases, that would be tmpfs, but if MFD_HUGETLB is passed, it will > be hugetlbfs. Both can be considered implementation details of memfd. > > It also means that it is not possible to differentiate between a file > coming from memfd_create and a file coming from a standard tmpfs mount > point. > > Additionally, no permission is validated at creation, which differs from > the similar memfd_secret syscall. > > Call security_inode_init_security_anon during creation. This ensures > that the file is setup similarly to other anonymous inodes. On SELinux, > it means that the file will receive the security context of its task. > > The ability to limit fexecve on memfd has been of interest to avoid > potential pitfalls where /proc/self/exe or similar would be executed > [1][2]. Reuse the "execute_no_trans" and "entrypoint" access vectors, > similarly to the file class. These access vectors may not make sense for > the existing "anon_inode" class. Therefore, define and assign a new > class "memfd_file" to support such access vectors. > > Guard these changes behind a new policy capability named "memfd_class". > > [1] https://crbug.com/1305267 > [2] https://lore.kernel.org/lkml/20221215001205.51969-1-jeffxu@google.com/ > > Signed-off-by: Thiébaud Weksteen <tweek@google.com> > --- > Changes since v2: > - Add WARN_ON when using unexpected class. Return -EACCES instead > of -EPERM > - Remove extra new line > - Rebase on selinux/dev > > Changes since v1: > - Move test of class earlier in selinux_bprm_creds_for_exec > - Remove duplicate call to security_transition_sid > > Changes since RFC: > - Remove enum argument, simply compare the anon inode name > - Introduce a policy capability for compatility > - Add validation of class in selinux_bprm_creds_for_exec > include/linux/memfd.h | 2 ++ > mm/memfd.c | 14 ++++++++++-- > security/selinux/hooks.c | 26 +++++++++++++++++----- > security/selinux/include/classmap.h | 2 ++ > security/selinux/include/policycap.h | 1 + > security/selinux/include/policycap_names.h | 1 + > security/selinux/include/security.h | 5 +++++ > 7 files changed, 44 insertions(+), 7 deletions(-) Thanks Thiébaud, I'm going to merge this into selinux/dev-staging now with the plan to move it over to selinux/dev after the upcoming merge window closes. Hugh, since the changes between this patch and the v2 you ACK'd are minimal and limited to the SELinux error handling code (see diff below), I'm going to carry over your ACK, but if you have any concerns or objections please let us know. Thanks everyone! -- paul-moore.com
On Sun, Sep 21, 2025 at 2:31 PM Paul Moore <paul@paul-moore.com> wrote: > > On Wed, Sep 17, 2025 at 10:04 PM Thiébaud Weksteen <tweek@google.com> wrote: > > > > Prior to this change, no security hooks were called at the creation of a > > memfd file. It means that, for SELinux as an example, it will receive > > the default type of the filesystem that backs the in-memory inode. In > > most cases, that would be tmpfs, but if MFD_HUGETLB is passed, it will > > be hugetlbfs. Both can be considered implementation details of memfd. > > > > It also means that it is not possible to differentiate between a file > > coming from memfd_create and a file coming from a standard tmpfs mount > > point. > > > > Additionally, no permission is validated at creation, which differs from > > the similar memfd_secret syscall. > > > > Call security_inode_init_security_anon during creation. This ensures > > that the file is setup similarly to other anonymous inodes. On SELinux, > > it means that the file will receive the security context of its task. > > > > The ability to limit fexecve on memfd has been of interest to avoid > > potential pitfalls where /proc/self/exe or similar would be executed > > [1][2]. Reuse the "execute_no_trans" and "entrypoint" access vectors, > > similarly to the file class. These access vectors may not make sense for > > the existing "anon_inode" class. Therefore, define and assign a new > > class "memfd_file" to support such access vectors. > > > > Guard these changes behind a new policy capability named "memfd_class". > > > > [1] https://crbug.com/1305267 > > [2] https://lore.kernel.org/lkml/20221215001205.51969-1-jeffxu@google.com/ > > > > Signed-off-by: Thiébaud Weksteen <tweek@google.com> > > --- > > Changes since v2: > > - Add WARN_ON when using unexpected class. Return -EACCES instead > > of -EPERM > > - Remove extra new line > > - Rebase on selinux/dev > > > > Changes since v1: > > - Move test of class earlier in selinux_bprm_creds_for_exec > > - Remove duplicate call to security_transition_sid > > > > Changes since RFC: > > - Remove enum argument, simply compare the anon inode name > > - Introduce a policy capability for compatility > > - Add validation of class in selinux_bprm_creds_for_exec > > include/linux/memfd.h | 2 ++ > > mm/memfd.c | 14 ++++++++++-- > > security/selinux/hooks.c | 26 +++++++++++++++++----- > > security/selinux/include/classmap.h | 2 ++ > > security/selinux/include/policycap.h | 1 + > > security/selinux/include/policycap_names.h | 1 + > > security/selinux/include/security.h | 5 +++++ > > 7 files changed, 44 insertions(+), 7 deletions(-) > > Thanks Thiébaud, I'm going to merge this into selinux/dev-staging now > with the plan to move it over to selinux/dev after the upcoming merge > window closes. > > Hugh, since the changes between this patch and the v2 you ACK'd are > minimal and limited to the SELinux error handling code (see diff > below), I'm going to carry over your ACK, but if you have any concerns > or objections please let us know. > > Thanks everyone! When would you recommend that I re-apply the corresponding userspace patch to reserve this policy capability number for memfd_class? After it is moved to selinux/dev? Understand that it isn't truly reserved until it lands in a kernel.org kernel but would prefer to reapply it sooner than that since there may be other policy capability requests queueing up (e.g. bpf token) that should be done relative to it. Can always revert it again if necessary, at least until another userspace release is made (not sure on timeline for that). > > -- > paul-moore.com
On Mon, Sep 22, 2025 at 9:12 AM Stephen Smalley <stephen.smalley.work@gmail.com> wrote: > > When would you recommend that I re-apply the corresponding userspace > patch to reserve this policy capability number for memfd_class? > After it is moved to selinux/dev? Understand that it isn't truly > reserved until it lands in a kernel.org kernel but would prefer to > reapply it sooner than that since there may be other policy capability > requests queueing up (e.g. bpf token) that should be done relative to > it. Can always revert it again if necessary, at least until another > userspace release is made (not sure on timeline for that). When it comes to API issues like this, my standard answer is "tagged release from Linus" as it is the safest option, but you know that already. The fuzzier answer is that unless something crazy happens, I'm likely going to move the patches, in order, from selinux/dev-staging into selinux/dev when the merge window closes. This means that any policycap API additions for the next cycle are going to start with the memfd_class policycap, so it *should* be fairly safe to merge the userspace bits now, I just wouldn't do a userspace release with that API change until we see a tagged release from Linus. -- paul-moore.com
On Sun, 21 Sep 2025, Paul Moore wrote: > On Wed, Sep 17, 2025 at 10:04 PM Thiébaud Weksteen <tweek@google.com> wrote: > > > > Prior to this change, no security hooks were called at the creation of a > > memfd file. It means that, for SELinux as an example, it will receive > > the default type of the filesystem that backs the in-memory inode. In > > most cases, that would be tmpfs, but if MFD_HUGETLB is passed, it will > > be hugetlbfs. Both can be considered implementation details of memfd. > > > > It also means that it is not possible to differentiate between a file > > coming from memfd_create and a file coming from a standard tmpfs mount > > point. > > > > Additionally, no permission is validated at creation, which differs from > > the similar memfd_secret syscall. > > > > Call security_inode_init_security_anon during creation. This ensures > > that the file is setup similarly to other anonymous inodes. On SELinux, > > it means that the file will receive the security context of its task. > > > > The ability to limit fexecve on memfd has been of interest to avoid > > potential pitfalls where /proc/self/exe or similar would be executed > > [1][2]. Reuse the "execute_no_trans" and "entrypoint" access vectors, > > similarly to the file class. These access vectors may not make sense for > > the existing "anon_inode" class. Therefore, define and assign a new > > class "memfd_file" to support such access vectors. > > > > Guard these changes behind a new policy capability named "memfd_class". > > > > [1] https://crbug.com/1305267 > > [2] https://lore.kernel.org/lkml/20221215001205.51969-1-jeffxu@google.com/ > > > > Signed-off-by: Thiébaud Weksteen <tweek@google.com> > > --- > > Changes since v2: > > - Add WARN_ON when using unexpected class. Return -EACCES instead > > of -EPERM > > - Remove extra new line > > - Rebase on selinux/dev > > > > Changes since v1: > > - Move test of class earlier in selinux_bprm_creds_for_exec > > - Remove duplicate call to security_transition_sid > > > > Changes since RFC: > > - Remove enum argument, simply compare the anon inode name > > - Introduce a policy capability for compatility > > - Add validation of class in selinux_bprm_creds_for_exec > > include/linux/memfd.h | 2 ++ > > mm/memfd.c | 14 ++++++++++-- > > security/selinux/hooks.c | 26 +++++++++++++++++----- > > security/selinux/include/classmap.h | 2 ++ > > security/selinux/include/policycap.h | 1 + > > security/selinux/include/policycap_names.h | 1 + > > security/selinux/include/security.h | 5 +++++ > > 7 files changed, 44 insertions(+), 7 deletions(-) > > Thanks Thiébaud, I'm going to merge this into selinux/dev-staging now > with the plan to move it over to selinux/dev after the upcoming merge > window closes. > > Hugh, since the changes between this patch and the v2 you ACK'd are > minimal and limited to the SELinux error handling code (see diff > below), I'm going to carry over your ACK, but if you have any concerns > or objections please let us know. Sure, please do carry over my ACK - thanks. Hugh
On Wed, Sep 17, 2025 at 10:04 PM Thiébaud Weksteen <tweek@google.com> wrote: > > Prior to this change, no security hooks were called at the creation of a > memfd file. It means that, for SELinux as an example, it will receive > the default type of the filesystem that backs the in-memory inode. In > most cases, that would be tmpfs, but if MFD_HUGETLB is passed, it will > be hugetlbfs. Both can be considered implementation details of memfd. > > It also means that it is not possible to differentiate between a file > coming from memfd_create and a file coming from a standard tmpfs mount > point. > > Additionally, no permission is validated at creation, which differs from > the similar memfd_secret syscall. > > Call security_inode_init_security_anon during creation. This ensures > that the file is setup similarly to other anonymous inodes. On SELinux, > it means that the file will receive the security context of its task. > > The ability to limit fexecve on memfd has been of interest to avoid > potential pitfalls where /proc/self/exe or similar would be executed > [1][2]. Reuse the "execute_no_trans" and "entrypoint" access vectors, > similarly to the file class. These access vectors may not make sense for > the existing "anon_inode" class. Therefore, define and assign a new > class "memfd_file" to support such access vectors. > > Guard these changes behind a new policy capability named "memfd_class". > > [1] https://crbug.com/1305267 > [2] https://lore.kernel.org/lkml/20221215001205.51969-1-jeffxu@google.com/ > > Signed-off-by: Thiébaud Weksteen <tweek@google.com> Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com> Tested-by: Stephen Smalley <stephen.smalley.work@gmail.com> For testing, I reverted the previous revert of the memfd_class policy capability on selinux userspace, built and installed the modified libsepol, and then followed the instructions in the testsuite commit description. Also confirmed manual execution of the tests in both enforcing and permissive mode yields the expected behavior, and the WARN_ON() was not triggered. > --- > Changes since v2: > - Add WARN_ON when using unexpected class. Return -EACCES instead > of -EPERM > - Remove extra new line > - Rebase on selinux/dev > > Changes since v1: > - Move test of class earlier in selinux_bprm_creds_for_exec > - Remove duplicate call to security_transition_sid > > Changes since RFC: > - Remove enum argument, simply compare the anon inode name > - Introduce a policy capability for compatility > - Add validation of class in selinux_bprm_creds_for_exec > include/linux/memfd.h | 2 ++ > mm/memfd.c | 14 ++++++++++-- > security/selinux/hooks.c | 26 +++++++++++++++++----- > security/selinux/include/classmap.h | 2 ++ > security/selinux/include/policycap.h | 1 + > security/selinux/include/policycap_names.h | 1 + > security/selinux/include/security.h | 5 +++++ > 7 files changed, 44 insertions(+), 7 deletions(-) > > diff --git a/include/linux/memfd.h b/include/linux/memfd.h > index 6f606d9573c3..cc74de3dbcfe 100644 > --- a/include/linux/memfd.h > +++ b/include/linux/memfd.h > @@ -4,6 +4,8 @@ > > #include <linux/file.h> > > +#define MEMFD_ANON_NAME "[memfd]" > + > #ifdef CONFIG_MEMFD_CREATE > extern long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg); > struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx); > diff --git a/mm/memfd.c b/mm/memfd.c > index bbe679895ef6..63b439eb402a 100644 > --- a/mm/memfd.c > +++ b/mm/memfd.c > @@ -433,6 +433,8 @@ static struct file *alloc_file(const char *name, unsigned int flags) > { > unsigned int *file_seals; > struct file *file; > + struct inode *inode; > + int err = 0; > > if (flags & MFD_HUGETLB) { > file = hugetlb_file_setup(name, 0, VM_NORESERVE, > @@ -444,12 +446,20 @@ static struct file *alloc_file(const char *name, unsigned int flags) > } > if (IS_ERR(file)) > return file; > + > + inode = file_inode(file); > + err = security_inode_init_security_anon(inode, > + &QSTR(MEMFD_ANON_NAME), NULL); > + if (err) { > + fput(file); > + file = ERR_PTR(err); > + return file; > + } > + > file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; > file->f_flags |= O_LARGEFILE; > > if (flags & MFD_NOEXEC_SEAL) { > - struct inode *inode = file_inode(file); > - > inode->i_mode &= ~0111; > file_seals = memfd_file_seals_ptr(file); > if (file_seals) { > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c > index 0e47b4bb8d40..2b685f9dd61d 100644 > --- a/security/selinux/hooks.c > +++ b/security/selinux/hooks.c > @@ -93,6 +93,7 @@ > #include <linux/fanotify.h> > #include <linux/io_uring/cmd.h> > #include <uapi/linux/lsm.h> > +#include <linux/memfd.h> > > #include "avc.h" > #include "objsec.h" > @@ -2319,6 +2320,10 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) > new_tsec = selinux_cred(bprm->cred); > isec = inode_security(inode); > > + if (WARN_ON(isec->sclass != SECCLASS_FILE && > + isec->sclass != SECCLASS_MEMFD_FILE)) > + return -EACCES; > + > /* Default to the current task SID. */ > new_tsec->sid = old_tsec->sid; > new_tsec->osid = old_tsec->sid; > @@ -2371,8 +2376,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) > ad.u.file = bprm->file; > > if (new_tsec->sid == old_tsec->sid) { > - rc = avc_has_perm(old_tsec->sid, isec->sid, > - SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); > + rc = avc_has_perm(old_tsec->sid, isec->sid, isec->sclass, > + FILE__EXECUTE_NO_TRANS, &ad); > if (rc) > return rc; > } else { > @@ -2382,8 +2387,8 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) > if (rc) > return rc; > > - rc = avc_has_perm(new_tsec->sid, isec->sid, > - SECCLASS_FILE, FILE__ENTRYPOINT, &ad); > + rc = avc_has_perm(new_tsec->sid, isec->sid, isec->sclass, > + FILE__ENTRYPOINT, &ad); > if (rc) > return rc; > > @@ -2978,10 +2983,18 @@ static int selinux_inode_init_security_anon(struct inode *inode, > struct common_audit_data ad; > struct inode_security_struct *isec; > int rc; > + bool is_memfd = false; > > if (unlikely(!selinux_initialized())) > return 0; > > + if (name != NULL && name->name != NULL && > + !strcmp(name->name, MEMFD_ANON_NAME)) { > + if (!selinux_policycap_memfd_class()) > + return 0; > + is_memfd = true; > + } > + > isec = selinux_inode(inode); > > /* > @@ -3001,7 +3014,10 @@ static int selinux_inode_init_security_anon(struct inode *inode, > isec->sclass = context_isec->sclass; > isec->sid = context_isec->sid; > } else { > - isec->sclass = SECCLASS_ANON_INODE; > + if (is_memfd) > + isec->sclass = SECCLASS_MEMFD_FILE; > + else > + isec->sclass = SECCLASS_ANON_INODE; > rc = security_transition_sid( > sid, sid, > isec->sclass, name, &isec->sid); > diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h > index 5665aa5e7853..3ec85142771f 100644 > --- a/security/selinux/include/classmap.h > +++ b/security/selinux/include/classmap.h > @@ -179,6 +179,8 @@ const struct security_class_mapping secclass_map[] = { > { "anon_inode", { COMMON_FILE_PERMS, NULL } }, > { "io_uring", { "override_creds", "sqpoll", "cmd", "allowed", NULL } }, > { "user_namespace", { "create", NULL } }, > + { "memfd_file", > + { COMMON_FILE_PERMS, "execute_no_trans", "entrypoint", NULL } }, > /* last one */ { NULL, {} } > }; > > diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h > index 135a969f873c..231d02227e59 100644 > --- a/security/selinux/include/policycap.h > +++ b/security/selinux/include/policycap.h > @@ -18,6 +18,7 @@ enum { > POLICYDB_CAP_NETIF_WILDCARD, > POLICYDB_CAP_GENFS_SECLABEL_WILDCARD, > POLICYDB_CAP_FUNCTIONFS_SECLABEL, > + POLICYDB_CAP_MEMFD_CLASS, > __POLICYDB_CAP_MAX > }; > #define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1) > diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h > index ff8882887651..454dab37bda3 100644 > --- a/security/selinux/include/policycap_names.h > +++ b/security/selinux/include/policycap_names.h > @@ -21,6 +21,7 @@ const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = { > "netif_wildcard", > "genfs_seclabel_wildcard", > "functionfs_seclabel", > + "memfd_class", > }; > /* clang-format on */ > > diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h > index 0f954a40d3fc..5d1dad8058b1 100644 > --- a/security/selinux/include/security.h > +++ b/security/selinux/include/security.h > @@ -209,6 +209,11 @@ static inline bool selinux_policycap_functionfs_seclabel(void) > selinux_state.policycap[POLICYDB_CAP_FUNCTIONFS_SECLABEL]); > } > > +static inline bool selinux_policycap_memfd_class(void) > +{ > + return READ_ONCE(selinux_state.policycap[POLICYDB_CAP_MEMFD_CLASS]); > +} > + > struct selinux_policy_convert_data; > > struct selinux_load_state { > -- > 2.51.0.384.g4c02a37b29-goog >
© 2016 - 2025 Red Hat, Inc.