summaryrefslogtreecommitdiff
path: root/security/apparmor
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2026-05-09 18:20:27 -0700
committerJohn Johansen <john.johansen@canonical.com>2026-06-29 10:34:17 -0700
commitdda61023f976d7ab3bc7c8b46d26d6d23424f890 (patch)
tree5060950538ee29689b95f2bf67c0143d1a852251 /security/apparmor
parent17b5758bf35c7a113363cd7a350b7e6a251b80f4 (diff)
downloadlinux-next-dda61023f976d7ab3bc7c8b46d26d6d23424f890.tar.gz
linux-next-dda61023f976d7ab3bc7c8b46d26d6d23424f890.zip
apparmor: fix alternate loaders ability to load compressed policy
When policy is compressed it is given a header in userspace. The parser knows to strip this header, but alternate profile loaders like aa-load and systemd have not been updated so that they know to strip the header. This allows those loaders to just load the binary file without having to be updated. Fixes: 17b5758bf35c7 ("apparmor: Initial support for compressed policies") Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor')
-rw-r--r--security/apparmor/apparmorfs.c37
1 files changed, 34 insertions, 3 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 514ec34975a4..2ae9ab94a5a9 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -23,6 +23,7 @@
#include <linux/fs_context.h>
#include <linux/poll.h>
#include <linux/zstd.h>
+#include <linux/string.h>
#include <uapi/linux/major.h>
#include <uapi/linux/magic.h>
@@ -546,6 +547,15 @@ fail:
}
+struct aa_user_hdr {
+ uint8_t version;
+ uint8_t compress_level;
+ uint8_t padding[6]; /* force 8-byte alignment */
+} __packed __aligned(8);
+
+#define aa_hdr_magic "\x04\x08\x00\x76\x65\x72\x73\x69\x6f\x6e\x00\x02"
+#define aa_hdr_magic_size 12
+
static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
loff_t *pos, struct aa_ns *ns,
const struct cred *ocred)
@@ -556,6 +566,7 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
char *compressed_data = NULL;
__le32 magic_le;
bool is_compressed;
+ u8 aahdr[aa_hdr_magic_size];
label = begin_current_label_crit_section();
@@ -576,11 +587,30 @@ static ssize_t policy_update(u32 mask, const char __user *buf, size_t size,
if (size >= sizeof(__le32) &&
!copy_from_user(&magic_le, buf, sizeof(magic_le)) &&
- le32_to_cpu(magic_le) == ZSTD_MAGICNUMBER)
+ le32_to_cpu(magic_le) == ZSTD_MAGICNUMBER) {
is_compressed = true;
- else
+ } else if (size >= sizeof(struct aa_user_hdr) + sizeof(__le32) &&
+ !copy_from_user(&magic_le,
+ buf + sizeof(struct aa_user_hdr),
+ sizeof(magic_le)) &&
+ le32_to_cpu(magic_le) == ZSTD_MAGICNUMBER) {
+ is_compressed = true;
+ /* skip the userspace header if present */
+ buf += sizeof(struct aa_user_hdr);
+ size -= sizeof(struct aa_user_hdr);
+ } else if (size >= sizeof(struct aa_user_hdr) +
+ aa_hdr_magic_size &&
+ !copy_from_user(&aahdr,
+ buf + sizeof(struct aa_user_hdr),
+ aa_hdr_magic_size) &&
+ memcmp(&aahdr, aa_hdr_magic, aa_hdr_magic_size) == 0) {
+ /* uncompressed blob with user hdr */
+ buf += sizeof(struct aa_user_hdr);
+ size -= sizeof(struct aa_user_hdr);
is_compressed = false;
-
+ } else {
+ is_compressed = false;
+ }
if (is_compressed) {
data = aa_get_data_from_compressed(buf, size, pos, &compressed_data);
@@ -2575,6 +2605,7 @@ static struct aa_sfs_entry aa_sfs_entry_policy[] = {
AA_SFS_FILE_U64("state32", 1),
AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined),
AA_SFS_FILE_BOOLEAN("compressed_load", 1),
+ AA_SFS_FILE_BOOLEAN("extended_policy_header", 1),
{ }
};