* [RFC PATCH v2 0/2] ipe support for anonymous memory and memfd
@ 2025-01-29 20:39 wufan
2025-01-29 20:39 ` [RFC PATCH v2 1/2] memfd,lsm: add a security hook to memfd_create() wufan
2025-01-29 20:39 ` [RFC PATCH v2 2/2] ipe: add 'anonymous_memory' property for policy decisions wufan
0 siblings, 2 replies; 3+ messages in thread
From: wufan @ 2025-01-29 20:39 UTC (permalink / raw)
To: corbet, jmorris, paul, serge, akpm
Cc: linux-doc, linux-security-module, linux-mm, linux-kernel, Fan Wu
From: Fan Wu <wufan@kernel.org>
This patchset adds support for anonymous memory and memfd to the IPE LSM.
Currently, the IPE policy language can only allow or deny a physical file
from an integrity-verified source. However, for events triggered by
anonymous memory, either created via mmap() with MAP_ANONYMOUS or via
memfd_create(), IPE provides no mechanism to explicitly allow or deny
these events.
Execution from anonymous memory is a common use case in modern
applications. For example, JIT compilers store generated code in such
regions. This patchset introduces a new IPE property, anonymous_memory,
to let administrators explicitly allow or deny events triggered by
anonymous memory.
For example, the following policy:
policy_name=example_policy policy_version=0.0.0
DEFAULT action=DENY
op=EXECUTE dmverity_signature=TRUE action=ALLOW
op=EXECUTE anonymous_memory=TRUE action=ALLOW
will allow execution of files from a signed dm-verity volume and also
execution from anonymous memory.
In the current design, the anonymous_memory property covers both
memory regions created by mmap() with MAP_ANONYMOUS and those
allocated by memfd_create(), as both share the same semantics [1].
However, because regular files on tmpfs, shmemfs, or hugetlbfs are
also backed by anonymous memory, the policy language might not be
entirely clear to users. An alternative approach would be to define
two separate properties, one covering MAP_ANONYMOUS and another
covering memfd_create().
Nonetheless, allowing execution from anonymous memory does increase
the attack surface. Future work will add additional properties to
the IPE policy language to provide more fine-grained control.
For instance, one possibility is to permit only processes with certain
security attributes, such as specific SELinux labels, to execute code
from anonymous memory.
The ipe test suite has been updated to include anonymous memory tests:
https://github.com/microsoft/ipe/tree/test-suite
[1] https://man7.org/linux/man-pages/man2/memfd_create.2.html
Previous Postings
-----------------
v1: https://lore.kernel.org/all/66922c42-c3a2-4634-a8f0-4c8c2b4c051a@kernel.org/T/
Changelog
---------
V2:
* Update test suite to include anonymous memory tests
* Fix property implementation and add memfd support
Fan Wu (2):
memfd,lsm: add a security hook to memfd_create()
ipe: add 'anonymous_memory' property for policy decisions
Documentation/admin-guide/LSM/ipe.rst | 12 ++++++++++
Documentation/security/ipe.rst | 9 +++----
include/linux/lsm_hook_defs.h | 3 +++
include/linux/security.h | 8 +++++++
mm/memfd.c | 2 ++
security/ipe/Kconfig | 10 ++++++++
security/ipe/audit.c | 2 ++
security/ipe/eval.c | 34 +++++++++++++++++++++++----
security/ipe/eval.h | 13 ++++++----
security/ipe/hooks.c | 12 ++++++++++
security/ipe/hooks.h | 4 ++++
security/ipe/ipe.c | 7 ++++--
security/ipe/policy.h | 2 ++
security/ipe/policy_parser.c | 4 ++++
security/security.c | 11 +++++++++
15 files changed, 119 insertions(+), 14 deletions(-)
--
2.47.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [RFC PATCH v2 1/2] memfd,lsm: add a security hook to memfd_create()
2025-01-29 20:39 [RFC PATCH v2 0/2] ipe support for anonymous memory and memfd wufan
@ 2025-01-29 20:39 ` wufan
2025-01-29 20:39 ` [RFC PATCH v2 2/2] ipe: add 'anonymous_memory' property for policy decisions wufan
1 sibling, 0 replies; 3+ messages in thread
From: wufan @ 2025-01-29 20:39 UTC (permalink / raw)
To: corbet, jmorris, paul, serge, akpm
Cc: linux-doc, linux-security-module, linux-mm, linux-kernel, Fan Wu
From: Fan Wu <wufan@kernel.org>
This patch adds a new LSM hook that notifies the security subsystem
whenever a new memfd is created by memfd_create(). The hook is invoked
before fd_install() inside memfd_create(), allowing the LSM to
differentiate memfd files from regular shmemfs or hugetlbfs files that
share the same superblock.
Upon receiving this notification, the security system can label
the memfd files thereafter the lsms can make security decision
specifically for them.
Signed-off-by: Fan Wu <wufan@kernel.org>
---
include/linux/lsm_hook_defs.h | 3 +++
include/linux/security.h | 8 ++++++++
mm/memfd.c | 2 ++
security/security.c | 11 +++++++++++
4 files changed, 24 insertions(+)
diff --git a/include/linux/lsm_hook_defs.h b/include/linux/lsm_hook_defs.h
index e2f1ce37c41e..1c0a9953c924 100644
--- a/include/linux/lsm_hook_defs.h
+++ b/include/linux/lsm_hook_defs.h
@@ -463,3 +463,6 @@ LSM_HOOK(int, 0, bdev_alloc_security, struct block_device *bdev)
LSM_HOOK(void, LSM_RET_VOID, bdev_free_security, struct block_device *bdev)
LSM_HOOK(int, 0, bdev_setintegrity, struct block_device *bdev,
enum lsm_integrity_type type, const void *value, size_t size)
+
+LSM_HOOK(void, 0, memfd_created, struct file *file)
+
diff --git a/include/linux/security.h b/include/linux/security.h
index 980b6c207cad..40ae79270eaf 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -2386,4 +2386,12 @@ static inline void security_initramfs_populated(void)
}
#endif /* CONFIG_SECURITY */
+#ifdef CONFIG_SECURITY
+extern void security_memfd_created(struct file *file);
+#else
+static inline void security_memfd_created(struct file *file)
+{
+}
+#endif /* CONFIG_SECURITY */
+
#endif /* ! __LINUX_SECURITY_H */
diff --git a/mm/memfd.c b/mm/memfd.c
index 37f7be57c2f5..597d27ccb0b6 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -19,6 +19,7 @@
#include <linux/shmem_fs.h>
#include <linux/memfd.h>
#include <linux/pid_namespace.h>
+#include <linux/security.h>
#include <uapi/linux/memfd.h>
/*
@@ -483,6 +484,7 @@ SYSCALL_DEFINE2(memfd_create,
goto err_fd;
}
+ security_memfd_created(file);
fd_install(fd, file);
kfree(name);
return fd;
diff --git a/security/security.c b/security/security.c
index 143561ebc3e8..daa9e0e0e879 100644
--- a/security/security.c
+++ b/security/security.c
@@ -6010,3 +6010,14 @@ void security_initramfs_populated(void)
{
call_void_hook(initramfs_populated);
}
+
+/**
+ * security_memfd_created() - Notify LSMs that a memfd has been created
+ *
+ * Tells the LSMs that a memfd has been created.
+ */
+void security_memfd_created(struct file *file)
+{
+ call_void_hook(memfd_created, file);
+}
+
--
2.47.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [RFC PATCH v2 2/2] ipe: add 'anonymous_memory' property for policy decisions
2025-01-29 20:39 [RFC PATCH v2 0/2] ipe support for anonymous memory and memfd wufan
2025-01-29 20:39 ` [RFC PATCH v2 1/2] memfd,lsm: add a security hook to memfd_create() wufan
@ 2025-01-29 20:39 ` wufan
1 sibling, 0 replies; 3+ messages in thread
From: wufan @ 2025-01-29 20:39 UTC (permalink / raw)
To: corbet, jmorris, paul, serge, akpm
Cc: linux-doc, linux-security-module, linux-mm, linux-kernel, Fan Wu
From: Fan Wu <wufan@kernel.org>
Currently, all existing IPE properties evaluate to FALSE for
operations triggered by anonymous memory regions or memfd. As a result,
IPE falls back to the policy's default action for such operations.
In policies where the default action is DENY, this behavior blocks
all anonymous memory related operations, rendering binaries that rely on
anonymous memory, e.g. JIT engine, unusable.
This commit introduces a new IPE property, 'anonymous_memory',
which evaluates to TRUE when an operation is triggered by an
anonymous memory region or memfd. This allows administrators to
explicitly allow or deny operations involving anonymous memory.
Signed-off-by: Fan Wu <wufan@kernel.org>
---
Documentation/admin-guide/LSM/ipe.rst | 12 ++++++++++
Documentation/security/ipe.rst | 9 +++----
security/ipe/Kconfig | 10 ++++++++
security/ipe/audit.c | 2 ++
security/ipe/eval.c | 34 +++++++++++++++++++++++----
security/ipe/eval.h | 13 ++++++----
security/ipe/hooks.c | 12 ++++++++++
security/ipe/hooks.h | 4 ++++
security/ipe/ipe.c | 7 ++++--
security/ipe/policy.h | 2 ++
security/ipe/policy_parser.c | 4 ++++
11 files changed, 95 insertions(+), 14 deletions(-)
diff --git a/Documentation/admin-guide/LSM/ipe.rst b/Documentation/admin-guide/LSM/ipe.rst
index f93a467db628..9de2e72f29d5 100644
--- a/Documentation/admin-guide/LSM/ipe.rst
+++ b/Documentation/admin-guide/LSM/ipe.rst
@@ -669,6 +669,18 @@ fsverity_signature
fsverity_signature=(TRUE|FALSE)
+anonymous_memory
+~~~~~~~~~~~~~~~~
+
+ This property can be used to allow or deny operations triggered by
+ anonymous memory. It evaluates to TRUE when a memory region
+ in the evaluation context is not backed by a physical file or it
+ is from a memory file descriptor. It is controlled by
+ the ``IPE_PROP_ANONYMOUS_MEMORY`` config option.
+ The format of this property is::
+
+ anonymous_memory=(TRUE|FALSE)
+
Policy Examples
---------------
diff --git a/Documentation/security/ipe.rst b/Documentation/security/ipe.rst
index 4a7d953abcdc..1606484241cb 100644
--- a/Documentation/security/ipe.rst
+++ b/Documentation/security/ipe.rst
@@ -385,15 +385,16 @@ Anonymous Memory
Anonymous memory isn't treated any differently from any other access in IPE.
When anonymous memory is mapped with ``+X``, it still comes into the ``file_mmap``
or ``file_mprotect`` hook, but with a ``NULL`` file object. This is submitted to
-the evaluation, like any other file. However, all current trust properties will
-evaluate to false, as they are all file-based and the operation is not
-associated with a file.
+the evaluation, like any other file. However, except the ``anonymous_memory`` property,
+all current trust properties will evaluate to false, as they are all file-based and
+the operation is not associated with a file.
.. WARNING::
This also occurs with the ``kernel_load_data`` hook, when the kernel is
loading data from a userspace buffer that is not backed by a file. In this
- scenario all current trust properties will also evaluate to false.
+ scenario, all current trust properties except ``anonymous_memory`` will also evaluate
+ to false.
Securityfs Interface
~~~~~~~~~~~~~~~~~~~~
diff --git a/security/ipe/Kconfig b/security/ipe/Kconfig
index 3c75bf267da4..77520714e9ab 100644
--- a/security/ipe/Kconfig
+++ b/security/ipe/Kconfig
@@ -94,6 +94,16 @@ config IPE_PROP_FS_VERITY_BUILTIN_SIG
if unsure, answer Y.
+config IPE_PROP_ANONYMOUS_MEMORY
+ bool "Enable support for anonymous memory"
+ default y
+ help
+ This option enables the 'anonymous_memory' property within IPE
+ policies. The property evaluates to TRUE when a memory region
+ in the evaluation context is not backed by a physical file
+ or it is from a memory file descriptor.
+
+ if unsure, answer Y.
endmenu
config SECURITY_IPE_KUNIT_TEST
diff --git a/security/ipe/audit.c b/security/ipe/audit.c
index f05f0caa4850..ab5217655910 100644
--- a/security/ipe/audit.c
+++ b/security/ipe/audit.c
@@ -59,6 +59,8 @@ static const char *const audit_prop_names[__IPE_PROP_MAX] = {
"fsverity_digest=",
"fsverity_signature=FALSE",
"fsverity_signature=TRUE",
+ "anonymous_memory=FALSE",
+ "anonymous_memory=TRUE",
};
/**
diff --git a/security/ipe/eval.c b/security/ipe/eval.c
index 21439c5be336..38c7214c9889 100644
--- a/security/ipe/eval.c
+++ b/security/ipe/eval.c
@@ -52,8 +52,8 @@ static void build_ipe_bdev_ctx(struct ipe_eval_ctx *ctx, const struct inode *con
}
#endif /* CONFIG_IPE_PROP_DM_VERITY */
-#ifdef CONFIG_IPE_PROP_FS_VERITY
-#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
+#if defined(CONFIG_IPE_PROP_FS_VERITY) || defined(CONFIG_IPE_PROP_ANONYMOUS_MEMORY)
+#if defined(CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG) || defined(CONFIG_IPE_PROP_ANONYMOUS_MEMORY)
static void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx,
const struct inode *const ino)
{
@@ -64,7 +64,7 @@ static inline void build_ipe_inode_blob_ctx(struct ipe_eval_ctx *ctx,
const struct inode *const ino)
{
}
-#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#endif
/**
* build_ipe_inode_ctx() - Build inode fields of an evaluation context.
@@ -80,7 +80,7 @@ static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *co
static void build_ipe_inode_ctx(struct ipe_eval_ctx *ctx, const struct inode *const ino)
{
}
-#endif /* CONFIG_IPE_PROP_FS_VERITY */
+#endif
/**
* ipe_build_eval_ctx() - Build an ipe evaluation context.
@@ -265,6 +265,28 @@ static bool evaluate_fsv_sig_true(const struct ipe_eval_ctx *const ctx)
}
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_ANONYMOUS_MEMORY
+static bool evaluate_anonymous_memory_false(const struct ipe_eval_ctx *const ctx)
+{
+ return ctx->file && !ctx->ipe_inode->memfd;
+}
+
+static bool evaluate_anonymous_memory_true(const struct ipe_eval_ctx *const ctx)
+{
+ return !evaluate_anonymous_memory_false(ctx);
+}
+#else
+static bool evaluate_anonymous_memory_false(const struct ipe_eval_ctx *const ctx)
+{
+ return false;
+}
+
+static bool evaluate_anonymous_memory_true(const struct ipe_eval_ctx *const ctx)
+{
+ return false;
+}
+#endif /* CONFIG_IPE_PROP_ANONYMOUS_MEMORY */
+
/**
* evaluate_property() - Analyze @ctx against a rule property.
* @ctx: Supplies a pointer to the context to be evaluated.
@@ -297,6 +319,10 @@ static bool evaluate_property(const struct ipe_eval_ctx *const ctx,
return evaluate_fsv_sig_false(ctx);
case IPE_PROP_FSV_SIG_TRUE:
return evaluate_fsv_sig_true(ctx);
+ case IPE_PROP_ANON_MEM_FALSE:
+ return evaluate_anonymous_memory_false(ctx);
+ case IPE_PROP_ANON_MEM_TRUE:
+ return evaluate_anonymous_memory_true(ctx);
default:
return false;
}
diff --git a/security/ipe/eval.h b/security/ipe/eval.h
index fef65a36468c..83b57d12a778 100644
--- a/security/ipe/eval.h
+++ b/security/ipe/eval.h
@@ -31,11 +31,16 @@ struct ipe_bdev {
};
#endif /* CONFIG_IPE_PROP_DM_VERITY */
-#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
+#if defined(CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG) || defined(CONFIG_IPE_PROP_ANONYMOUS_MEMORY)
struct ipe_inode {
+#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
bool fs_verity_signed;
-};
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_ANONYMOUS_MEMORY
+ bool memfd;
+#endif /* CONFIG_IPE_PROP_ANONYMOUS_MEMORY */
+};
+#endif
struct ipe_eval_ctx {
enum ipe_op_type op;
@@ -49,9 +54,9 @@ struct ipe_eval_ctx {
#ifdef CONFIG_IPE_PROP_FS_VERITY
const struct inode *ino;
#endif /* CONFIG_IPE_PROP_FS_VERITY */
-#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
+#if defined(CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG) || defined(CONFIG_IPE_PROP_ANONYMOUS_MEMORY)
const struct ipe_inode *ipe_inode;
-#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#endif
};
enum ipe_match {
diff --git a/security/ipe/hooks.c b/security/ipe/hooks.c
index d0323b81cd8f..ce68f08ce343 100644
--- a/security/ipe/hooks.c
+++ b/security/ipe/hooks.c
@@ -312,3 +312,15 @@ int ipe_inode_setintegrity(const struct inode *inode,
return -EINVAL;
}
#endif /* CONFIG_CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+
+#ifdef CONFIG_IPE_PROP_ANONYMOUS_MEMORY
+/**
+ * ipe_memfd_created() - Mark the current file as a memfd.
+ * @file: Supplies a pointer to the file structure being created.
+ */
+void ipe_memfd_created(struct file *file)
+{
+ ipe_inode(file->f_inode)->memfd = true;
+}
+#endif /* CONFIG_IPE_PROP_ANONYMOUS_MEMORY */
+
diff --git a/security/ipe/hooks.h b/security/ipe/hooks.h
index 38d4a387d039..fa90db65ca88 100644
--- a/security/ipe/hooks.h
+++ b/security/ipe/hooks.h
@@ -49,4 +49,8 @@ int ipe_inode_setintegrity(const struct inode *inode, enum lsm_integrity_type ty
const void *value, size_t size);
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_ANONYMOUS_MEMORY
+void ipe_memfd_created(struct file *file);
+#endif /* CONFIG_IPE_PROP_ANONYMOUS_MEMORY */
+
#endif /* _IPE_HOOKS_H */
diff --git a/security/ipe/ipe.c b/security/ipe/ipe.c
index 4317134cb0da..330925b6a48e 100644
--- a/security/ipe/ipe.c
+++ b/security/ipe/ipe.c
@@ -16,9 +16,9 @@ static struct lsm_blob_sizes ipe_blobs __ro_after_init = {
#ifdef CONFIG_IPE_PROP_DM_VERITY
.lbs_bdev = sizeof(struct ipe_bdev),
#endif /* CONFIG_IPE_PROP_DM_VERITY */
-#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
+#if defined(CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG) || defined(CONFIG_IPE_PROP_ANONYMOUS_MEMORY)
.lbs_inode = sizeof(struct ipe_inode),
-#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#endif
};
static const struct lsm_id ipe_lsmid = {
@@ -59,6 +59,9 @@ static struct security_hook_list ipe_hooks[] __ro_after_init = {
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
LSM_HOOK_INIT(inode_setintegrity, ipe_inode_setintegrity),
#endif /* CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
+#ifdef CONFIG_IPE_PROP_ANONYMOUS_MEMORY
+ LSM_HOOK_INIT(memfd_created, ipe_memfd_created),
+#endif /* CONFIG_IPE_PROP_ANONYMOUS_MEMORY */
};
/**
diff --git a/security/ipe/policy.h b/security/ipe/policy.h
index 5bfbdbddeef8..0becc2d2bd33 100644
--- a/security/ipe/policy.h
+++ b/security/ipe/policy.h
@@ -39,6 +39,8 @@ enum ipe_prop_type {
IPE_PROP_FSV_DIGEST,
IPE_PROP_FSV_SIG_FALSE,
IPE_PROP_FSV_SIG_TRUE,
+ IPE_PROP_ANON_MEM_FALSE,
+ IPE_PROP_ANON_MEM_TRUE,
__IPE_PROP_MAX
};
diff --git a/security/ipe/policy_parser.c b/security/ipe/policy_parser.c
index 7f27e39931d6..5c83095e7c37 100644
--- a/security/ipe/policy_parser.c
+++ b/security/ipe/policy_parser.c
@@ -281,6 +281,8 @@ static const match_table_t property_tokens = {
{IPE_PROP_FSV_DIGEST, "fsverity_digest=%s"},
{IPE_PROP_FSV_SIG_FALSE, "fsverity_signature=FALSE"},
{IPE_PROP_FSV_SIG_TRUE, "fsverity_signature=TRUE"},
+ {IPE_PROP_ANON_MEM_FALSE, "anonymous_memory=FALSE"},
+ {IPE_PROP_ANON_MEM_TRUE, "anonymous_memory=TRUE"},
{IPE_PROP_INVALID, NULL}
};
@@ -331,6 +333,8 @@ static int parse_property(char *t, struct ipe_rule *r)
case IPE_PROP_DMV_SIG_TRUE:
case IPE_PROP_FSV_SIG_FALSE:
case IPE_PROP_FSV_SIG_TRUE:
+ case IPE_PROP_ANON_MEM_FALSE:
+ case IPE_PROP_ANON_MEM_TRUE:
p->type = token;
break;
default:
--
2.47.1
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-01-29 20:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-29 20:39 [RFC PATCH v2 0/2] ipe support for anonymous memory and memfd wufan
2025-01-29 20:39 ` [RFC PATCH v2 1/2] memfd,lsm: add a security hook to memfd_create() wufan
2025-01-29 20:39 ` [RFC PATCH v2 2/2] ipe: add 'anonymous_memory' property for policy decisions wufan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox