From: "Maxime Bélair" <maxime.belair@canonical.com>
To: linux-security-module@vger.kernel.org
Cc: john.johansen@canonical.com, paul@paul-moore.com,
jmorris@namei.org, serge@hallyn.com, mic@digikod.net,
kees@kernel.org, stephen.smalley.work@gmail.com,
casey@schaufler-ca.com, takedakn@nttdata.co.jp,
penguin-kernel@I-love.SAKURA.ne.jp, song@kernel.org,
rdunlap@infradead.org, linux-api@vger.kernel.org,
apparmor@lists.ubuntu.com, linux-kernel@vger.kernel.org,
"Maxime Bélair" <maxime.belair@canonical.com>
Subject: [PATCH v6 3/5] AppArmor: add support for lsm_config_self_policy and lsm_config_system_policy
Date: Fri, 10 Oct 2025 15:25:30 +0200 [thread overview]
Message-ID: <20251010132610.12001-4-maxime.belair@canonical.com> (raw)
In-Reply-To: <20251010132610.12001-1-maxime.belair@canonical.com>
Enable users to manage AppArmor policies through the new hooks
lsm_config_self_policy and lsm_config_system_policy.
lsm_config_self_policy allows stacking existing policies in the kernel.
This ensures that it can only further restrict the caller and can never
be used to gain new privileges.
lsm_config_system_policy allows loading or replacing AppArmor policies in
any AppArmor namespace and is restricted to CAP_MAC_ADMIN.
Signed-off-by: Maxime Bélair <maxime.belair@canonical.com>
---
security/apparmor/apparmorfs.c | 31 ++++++++++
security/apparmor/include/apparmor.h | 4 ++
security/apparmor/include/apparmorfs.h | 3 +
security/apparmor/lsm.c | 84 ++++++++++++++++++++++++++
4 files changed, 122 insertions(+)
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 6039afae4bfc..6df43299b045 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -439,6 +439,37 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
return error;
}
+/**
+ * aa_profile_load_ns_name - load a profile into the current namespace identified by name
+ * @name: The name of the namesapce to load the policy in. "" for root_ns
+ * @name_size: size of @name. 0 For root ns
+ * @buf: buffer containing the user-provided policy
+ * @size: size of @buf
+ * @ppos: position pointer in the file
+ *
+ * Returns: 0 on success, negative value on error
+ */
+ssize_t aa_profile_load_ns_name(char *name, size_t name_size, const void __user *buf,
+ size_t size, loff_t *ppos)
+{
+ struct aa_ns *ns;
+
+ if (name_size == 0)
+ ns = aa_get_ns(root_ns);
+ else
+ ns = aa_lookupn_ns(root_ns, name, name_size);
+
+ if (!ns)
+ return -EINVAL;
+
+ int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY,
+ buf, size, ppos, ns);
+
+ aa_put_ns(ns);
+
+ return error >= 0 ? 0 : error;
+}
+
/* .load file hook fn to load policy */
static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
loff_t *pos)
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index f83934913b0f..1d9a2881a8b9 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -62,5 +62,9 @@ extern unsigned int aa_g_path_max;
#define AA_DEFAULT_CLEVEL 0
#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */
+/* Syscall-related buffer size limits */
+
+#define AA_PROFILE_NAME_MAX_SIZE (1 << 9)
+#define AA_PROFILE_MAX_SIZE (1 << 28)
#endif /* __APPARMOR_H */
diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h
index 1e94904f68d9..fd415afb7659 100644
--- a/security/apparmor/include/apparmorfs.h
+++ b/security/apparmor/include/apparmorfs.h
@@ -112,6 +112,9 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent);
void __aafs_ns_rmdir(struct aa_ns *ns);
int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name,
struct dentry *dent);
+ssize_t aa_profile_load_ns_name(char *name, size_t name_len, const void __user *buf,
+ size_t size, loff_t *ppos);
+
struct aa_loaddata;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 9b6c2f157f83..0c127f9dae19 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1275,6 +1275,86 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
}
+/**
+ * apparmor_lsm_config_self_policy - Stack a profile
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: buffer containing the user-provided name of the profile to stack
+ * @size: size of @buf
+ * @flags: reserved for future use; must be zero
+ *
+ * Returns: 0 on success, negative value on error
+ */
+static int apparmor_lsm_config_self_policy(u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ char *name;
+ long name_size;
+ int ret;
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+ if (size == 0)
+ return -EINVAL;
+ if (size > AA_PROFILE_NAME_MAX_SIZE)
+ return -E2BIG;
+
+ name = kmalloc(size, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ name_size = strncpy_from_user(name, buf, size);
+ if (name_size <= 0) {
+ kfree(name);
+ return name_size;
+ } else if (name_size == size) {
+ kfree(name);
+ return -E2BIG;
+ }
+
+ ret = aa_change_profile(name, AA_CHANGE_STACK);
+
+ kfree(name);
+
+ return ret;
+}
+
+/**
+ * apparmor_lsm_config_system_policy - Load or replace a system policy
+ * @op: operation to perform. Currently, only LSM_POLICY_LOAD is supported
+ * @buf: user-supplied buffer in the form "<ns>\0<policy>"
+ * <ns> is the namespace to load the policy into (empty string for root)
+ * <policy> is the policy to load
+ * @size: size of @buf
+ * @flags: reserved for future uses; must be zero
+ *
+ * Returns: 0 on success, negative value on error
+ */
+static int apparmor_lsm_config_system_policy(u32 op, void __user *buf,
+ size_t size, u32 flags)
+{
+ loff_t pos = 0; // Partial writing is not currently supported
+ char ns_name[AA_PROFILE_NAME_MAX_SIZE];
+ size_t ns_size;
+ size_t max_ns_size = min(size, AA_PROFILE_NAME_MAX_SIZE);
+
+ if (op != LSM_POLICY_LOAD || flags)
+ return -EOPNOTSUPP;
+ if (size < 2)
+ return -EINVAL;
+ if (size > AA_PROFILE_MAX_SIZE)
+ return -E2BIG;
+
+ ns_size = strncpy_from_user(ns_name, buf, max_ns_size);
+ if (ns_size < 0)
+ return ns_size;
+ if (ns_size == max_ns_size)
+ return -E2BIG;
+
+ return aa_profile_load_ns_name(ns_name, ns_size, buf + ns_size + 1,
+ size - ns_size - 1, &pos);
+}
+
+
#ifdef CONFIG_NETWORK_SECMARK
/**
* apparmor_socket_sock_rcv_skb - check perms before associating skb to sk
@@ -1483,6 +1563,10 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
+
+ LSM_HOOK_INIT(lsm_config_self_policy, apparmor_lsm_config_self_policy),
+ LSM_HOOK_INIT(lsm_config_system_policy,
+ apparmor_lsm_config_system_policy),
#ifdef CONFIG_NETWORK_SECMARK
LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
#endif
--
2.48.1
next prev parent reply other threads:[~2025-10-10 13:35 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-10 13:25 [PATCH v6 0/5] lsm: introduce lsm_config_self_policy() and lsm_config_system_policy() syscalls Maxime Bélair
2025-10-10 13:25 ` [PATCH v6 1/5] Wire up lsm_config_self_policy and lsm_config_system_policy syscalls Maxime Bélair
2025-10-10 18:06 ` Song Liu
2025-10-10 21:13 ` Casey Schaufler
2025-10-11 12:07 ` kernel test robot
2025-10-10 13:25 ` [PATCH v6 2/5] lsm: introduce security_lsm_config_*_policy hooks Maxime Bélair
2025-10-10 13:25 ` Maxime Bélair [this message]
2025-10-10 13:25 ` [PATCH v6 4/5] SELinux: add support for lsm_config_system_policy Maxime Bélair
2025-10-10 13:58 ` Stephen Smalley
2025-10-10 14:42 ` Stephen Smalley
2025-10-10 14:57 ` Paul Moore
2025-10-10 13:25 ` [PATCH v6 5/5] Smack: add support for lsm_config_self_policy and lsm_config_system_policy Maxime Bélair
2025-10-10 15:15 ` Casey Schaufler
2025-11-04 14:41 ` Casey Schaufler
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=20251010132610.12001-4-maxime.belair@canonical.com \
--to=maxime.belair@canonical.com \
--cc=apparmor@lists.ubuntu.com \
--cc=casey@schaufler-ca.com \
--cc=jmorris@namei.org \
--cc=john.johansen@canonical.com \
--cc=kees@kernel.org \
--cc=linux-api@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=mic@digikod.net \
--cc=paul@paul-moore.com \
--cc=penguin-kernel@I-love.SAKURA.ne.jp \
--cc=rdunlap@infradead.org \
--cc=serge@hallyn.com \
--cc=song@kernel.org \
--cc=stephen.smalley.work@gmail.com \
--cc=takedakn@nttdata.co.jp \
/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;
as well as URLs for NNTP newsgroup(s).