From 511f7b5b835726e844a5fc7444c18e4b8672edfd Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 14 Dec 2021 02:59:28 -0800 Subject: [PATCH 01/34] apparmor: fix absroot causing audited secids to begin with = AppArmor is prefixing secids that are converted to secctx with the = to indicate the secctx should only be parsed from an absolute root POV. This allows catching errors where secctx are reparsed back into internal labels. Unfortunately because audit is using secid to secctx conversion this means that subject and object labels can result in a very unfortunate == that can break audit parsing. eg. the subj==unconfined term in the below audit message type=USER_LOGIN msg=audit(1639443365.233:160): pid=1633 uid=0 auid=1000 ses=3 subj==unconfined msg='op=login id=1000 exe="/usr/sbin/sshd" hostname=192.168.122.1 addr=192.168.122.1 terminal=/dev/pts/1 res=success' Fix this by switch the prepending of = to a _. This still works as a special character to flag this case without breaking audit. Also move this check behind debug as it should not be needed during normal operqation. Fixes: 26b7899510ae ("apparmor: add support for absolute root view based labels") Reported-by: Casey Schaufler Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 5 +++++ security/apparmor/label.c | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index e2e8df0c6f1c..f42359f58eb5 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -22,6 +22,11 @@ */ #define DEBUG_ON (aa_g_debug) +/* + * split individual debug cases out in preparation for finer grained + * debug controls in the future. + */ +#define AA_DEBUG_LABEL DEBUG_ON #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args) #define AA_DEBUG(fmt, args...) \ do { \ diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 0b0265da1926..4bdb558696e8 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1631,9 +1631,9 @@ int aa_label_snxprint(char *str, size_t size, struct aa_ns *ns, AA_BUG(!str && size != 0); AA_BUG(!label); - if (flags & FLAG_ABS_ROOT) { + if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) { ns = root_ns; - len = snprintf(str, size, "="); + len = snprintf(str, size, "_"); update_for_len(total, len, size, str); } else if (!ns) { ns = labels_ns(label); @@ -1895,7 +1895,8 @@ struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str, AA_BUG(!str); str = skipn_spaces(str, n); - if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label)) + if (str == NULL || (AA_DEBUG_LABEL && *str == '_' && + base != &root_ns->unconfined->label)) return ERR_PTR(-EINVAL); len = label_count_strn_entries(str, end - str); From 240516df88795b9740cdc5b6b1fcc847763d46dd Mon Sep 17 00:00:00 2001 From: Yang Li Date: Wed, 17 Nov 2021 15:37:58 +0800 Subject: [PATCH 02/34] apparmor: Fix kernel-doc Fix function name in security/apparmor/label.c, policy.c, procattr.c kernel-doc comment to remove some warnings found by clang(make W=1 LLVM=1). security/apparmor/label.c:499: warning: expecting prototype for aa_label_next_not_in_set(). Prototype was for __aa_label_next_not_in_set() instead security/apparmor/label.c:2147: warning: expecting prototype for __aa_labelset_udate_subtree(). Prototype was for __aa_labelset_update_subtree() instead security/apparmor/policy.c:434: warning: expecting prototype for aa_lookup_profile(). Prototype was for aa_lookupn_profile() instead security/apparmor/procattr.c:101: warning: expecting prototype for aa_setprocattr_chagnehat(). Prototype was for aa_setprocattr_changehat() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/label.c | 4 ++-- security/apparmor/policy.c | 2 +- security/apparmor/procattr.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 4bdb558696e8..9eb9a9237926 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -485,7 +485,7 @@ int aa_label_next_confined(struct aa_label *label, int i) } /** - * aa_label_next_not_in_set - return the next profile of @sub not in @set + * __aa_label_next_not_in_set - return the next profile of @sub not in @set * @I: label iterator * @set: label to test against * @sub: label to if is subset of @set @@ -2137,7 +2137,7 @@ static void __labelset_update(struct aa_ns *ns) } /** - * __aa_labelset_udate_subtree - update all labels with a stale component + * __aa_labelset_update_subtree - update all labels with a stale component * @ns: ns to start update at (NOT NULL) * * Requires: @ns lock be held diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index b0cbc4906cb3..8357f4a639e1 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -422,7 +422,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base, } /** - * aa_lookup_profile - find a profile by its full or partial name + * aa_lookupn_profile - find a profile by its full or partial name * @ns: the namespace to start from (NOT NULL) * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL) * @n: size of @hname diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index fde332e0ea7d..86ad26ef72ed 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -90,7 +90,7 @@ static char *split_token_from_name(const char *op, char *args, u64 *token) } /** - * aa_setprocattr_chagnehat - handle procattr interface to change_hat + * aa_setprocattr_changehat - handle procattr interface to change_hat * @args: args received from writing to /proc//attr/current (NOT NULL) * @size: size of the args * @flags: set of flags governing behavior From 0fc6ab404c521b403a73d0ec2410785ce2cf1fb4 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 10 Dec 2021 13:57:12 +0800 Subject: [PATCH 03/34] lsm: Fix kernel-doc Fix function name in lsm.c kernel-doc comment to remove some warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. security/apparmor/lsm.c:819: warning: expecting prototype for apparmor_clone_security(). Prototype was for apparmor_sk_clone_security() instead security/apparmor/lsm.c:923: warning: expecting prototype for apparmor_socket_list(). Prototype was for apparmor_socket_listen() instead security/apparmor/lsm.c:1028: warning: expecting prototype for apparmor_getsockopt(). Prototype was for apparmor_socket_getsockopt() instead security/apparmor/lsm.c:1038: warning: expecting prototype for apparmor_setsockopt(). Prototype was for apparmor_socket_setsockopt() instead ecurity/apparmor/lsm.c:1061: warning: expecting prototype for apparmor_socket_sock_recv_skb(). Prototype was for apparmor_socket_sock_rcv_skb() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/lsm.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 900bc540656a..2654bcb5f462 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -832,7 +832,7 @@ static void apparmor_sk_free_security(struct sock *sk) } /** - * apparmor_clone_security - clone the sk_security field + * apparmor_sk_clone_security - clone the sk_security field */ static void apparmor_sk_clone_security(const struct sock *sk, struct sock *newsk) @@ -937,7 +937,7 @@ static int apparmor_socket_connect(struct socket *sock, } /** - * apparmor_socket_list - check perms before allowing listen + * apparmor_socket_listen - check perms before allowing listen */ static int apparmor_socket_listen(struct socket *sock, int backlog) { @@ -1041,7 +1041,7 @@ static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, } /** - * apparmor_getsockopt - check perms before getting socket options + * apparmor_socket_getsockopt - check perms before getting socket options */ static int apparmor_socket_getsockopt(struct socket *sock, int level, int optname) @@ -1051,7 +1051,7 @@ static int apparmor_socket_getsockopt(struct socket *sock, int level, } /** - * apparmor_setsockopt - check perms before setting socket options + * apparmor_socket_setsockopt - check perms before setting socket options */ static int apparmor_socket_setsockopt(struct socket *sock, int level, int optname) @@ -1070,7 +1070,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how) #ifdef CONFIG_NETWORK_SECMARK /** - * apparmor_socket_sock_recv_skb - check perms before associating skb to sk + * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk * * Note: can not sleep may be called with locks held * From 65cc9c391c3c4096ccc47ecd8b9f58f470b57225 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 1 Feb 2021 02:20:35 -0800 Subject: [PATCH 04/34] apparmor: Update help description of policy hash for introspection Update help to note this option is not needed for small embedded systems where regular policy introspection is not used. Signed-off-by: John Johansen --- security/apparmor/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index 348ed6cfa08a..272dca497c6d 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -25,7 +25,10 @@ config SECURITY_APPARMOR_HASH default y help This option selects whether introspection of loaded policy - is available to userspace via the apparmor filesystem. + hashes is available to userspace via the apparmor + filesystem. This option provides a light weight means of + checking loaded policy. This option adds to policy load + time and can be disabled for small embedded systems. config SECURITY_APPARMOR_HASH_DEFAULT bool "Enable policy hash introspection by default" From d61c57fde81915c04b41982f66a159ccc014e799 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 1 Feb 2021 03:43:18 -0800 Subject: [PATCH 05/34] apparmor: make export of raw binary profile to userspace optional Embedded systems have limited space and don't need the introspection or checkpoint restore capability provided by exporting the raw profile binary data so make it so make it a config option. This will reduce run time memory use and also speed up policy loads. Signed-off-by: John Johansen --- security/apparmor/Kconfig | 78 +++++++++++++++++--------- security/apparmor/apparmorfs.c | 11 +++- security/apparmor/include/apparmor.h | 1 + security/apparmor/include/apparmorfs.h | 14 +++++ security/apparmor/lsm.c | 6 ++ security/apparmor/policy.c | 31 +++++----- security/apparmor/policy_unpack.c | 20 ++++--- 7 files changed, 110 insertions(+), 51 deletions(-) diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index 272dca497c6d..4c34a28a2ddf 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -6,8 +6,6 @@ config SECURITY_APPARMOR select SECURITY_PATH select SECURITYFS select SECURITY_NETWORK - select ZLIB_INFLATE - select ZLIB_DEFLATE default n help This enables the AppArmor security module. @@ -17,32 +15,6 @@ config SECURITY_APPARMOR If you are unsure how to answer this question, answer N. -config SECURITY_APPARMOR_HASH - bool "Enable introspection of sha1 hashes for loaded profiles" - depends on SECURITY_APPARMOR - select CRYPTO - select CRYPTO_SHA1 - default y - help - This option selects whether introspection of loaded policy - hashes is available to userspace via the apparmor - filesystem. This option provides a light weight means of - checking loaded policy. This option adds to policy load - time and can be disabled for small embedded systems. - -config SECURITY_APPARMOR_HASH_DEFAULT - bool "Enable policy hash introspection by default" - depends on SECURITY_APPARMOR_HASH - default y - help - This option selects whether sha1 hashing of loaded policy - is enabled by default. The generation of sha1 hashes for - loaded policy provide system administrators a quick way - to verify that policy in the kernel matches what is expected, - however it can slow down policy load on some devices. In - these cases policy hashing can be disabled by default and - enabled only if needed. - config SECURITY_APPARMOR_DEBUG bool "Build AppArmor with debug code" depends on SECURITY_APPARMOR @@ -72,6 +44,56 @@ config SECURITY_APPARMOR_DEBUG_MESSAGES When enabled, various debug messages will be logged to the kernel message buffer. +config SECURITY_APPARMOR_INTROSPECT_POLICY + bool "Allow loaded policy to be introspected" + depends on SECURITY_APPARMOR + default y + help + This option selects whether introspection of loaded policy + is available to userspace via the apparmor filesystem. This + adds to kernel memory usage. It is required for introspection + of loaded policy, and check point and restore support. It + can be disabled for embedded systems where reducing memory and + cpu is paramount. + +config SECURITY_APPARMOR_HASH + bool "Enable introspection of sha1 hashes for loaded profiles" + depends on SECURITY_APPARMOR_INTROSPECT_POLICY + select CRYPTO + select CRYPTO_SHA1 + default y + help + This option selects whether introspection of loaded policy + hashes is available to userspace via the apparmor + filesystem. This option provides a light weight means of + checking loaded policy. This option adds to policy load + time and can be disabled for small embedded systems. + +config SECURITY_APPARMOR_HASH_DEFAULT + bool "Enable policy hash introspection by default" + depends on SECURITY_APPARMOR_HASH + default y + help + This option selects whether sha1 hashing of loaded policy + is enabled by default. The generation of sha1 hashes for + loaded policy provide system administrators a quick way + to verify that policy in the kernel matches what is expected, + however it can slow down policy load on some devices. In + these cases policy hashing can be disabled by default and + enabled only if needed. + +config SECURITY_APPARMOR_EXPORT_BINARY + bool "Allow exporting the raw binary policy" + depends on SECURITY_APPARMOR_INTROSPECT_POLICY + select ZLIB_INFLATE + select ZLIB_DEFLATE + default y + help + This option allows reading back binary policy as it was loaded. + It increases the amount of kernel memory needed by policy and + also increases policy load time. This option is required for + checkpoint and restore support, and debugging of loaded policy. + config SECURITY_APPARMOR_KUNIT_TEST bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS depends on KUNIT=y && SECURITY_APPARMOR diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 0797edb2fb3d..3770dde50a47 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -70,6 +70,7 @@ struct rawdata_f_data { struct aa_loaddata *loaddata; }; +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY #define RAWDATA_F_DATA_BUF(p) (char *)(p + 1) static void rawdata_f_data_free(struct rawdata_f_data *private) @@ -94,6 +95,7 @@ static struct rawdata_f_data *rawdata_f_data_alloc(size_t size) return ret; } +#endif /** * aa_mangle_name - mangle a profile name to std profile layout form @@ -1201,7 +1203,7 @@ SEQ_NS_FOPS(name); /* policy/raw_data/ * file ops */ - +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY #define SEQ_RAWDATA_FOPS(NAME) \ static int seq_rawdata_ ##NAME ##_open(struct inode *inode, struct file *file)\ { \ @@ -1492,6 +1494,8 @@ fail: return PTR_ERR(dent); } +#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ + /** fns to setup dynamic per profile/namespace files **/ @@ -1557,6 +1561,7 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, return dent; } +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY static int profile_depth(struct aa_profile *profile) { int depth = 0; @@ -1658,7 +1663,7 @@ static const struct inode_operations rawdata_link_abi_iops = { static const struct inode_operations rawdata_link_data_iops = { .get_link = rawdata_get_link_data, }; - +#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ /* * Requires: @profile->ns->lock held @@ -1729,6 +1734,7 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) profile->dents[AAFS_PROF_HASH] = dent; } +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY if (profile->rawdata) { dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, profile->label.proxy, NULL, NULL, @@ -1754,6 +1760,7 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) aa_get_proxy(profile->label.proxy); profile->dents[AAFS_PROF_RAW_DATA] = dent; } +#endif /*CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ list_for_each_entry(child, &profile->base.profiles, base.list) { error = __aafs_profile_mkdir(child, prof_child_dir(profile)); diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 1fbabdb565a8..9c3fc36a0702 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -36,6 +36,7 @@ extern enum audit_mode aa_g_audit; extern bool aa_g_audit_header; extern bool aa_g_debug; extern bool aa_g_hash_policy; +extern bool aa_g_export_binary; extern int aa_g_rawdata_compression_level; extern bool aa_g_lock_policy; extern bool aa_g_logsyscall; diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index 6e14f6cecdb9..1e94904f68d9 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -114,7 +114,21 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name, struct dentry *dent); struct aa_loaddata; + +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata); int __aa_fs_create_rawdata(struct aa_ns *ns, struct aa_loaddata *rawdata); +#else +static inline void __aa_fs_remove_rawdata(struct aa_loaddata *rawdata) +{ + /* empty stub */ +} + +static inline int __aa_fs_create_rawdata(struct aa_ns *ns, + struct aa_loaddata *rawdata) +{ + return 0; +} +#endif /* CONFIG_SECURITY_APPARMOR_EXPORT_BINARY */ #endif /* __AA_APPARMORFS_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 2654bcb5f462..84a4e63d922d 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1357,6 +1357,12 @@ bool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT); module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); #endif +/* whether policy exactly as loaded is retained for debug and checkpointing */ +bool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY); +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY +module_param_named(export_binary, aa_g_export_binary, aabool, 0600); +#endif + /* policy loaddata compression level */ int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION; module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level, diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 8357f4a639e1..499c0209b6a4 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -952,16 +952,18 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, mutex_lock_nested(&ns->lock, ns->level); /* check for duplicate rawdata blobs: space and file dedup */ - list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { - if (aa_rawdata_eq(rawdata_ent, udata)) { - struct aa_loaddata *tmp; + if (!list_empty(&ns->rawdata_list)) { + list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { + if (aa_rawdata_eq(rawdata_ent, udata)) { + struct aa_loaddata *tmp; - tmp = __aa_get_loaddata(rawdata_ent); - /* check we didn't fail the race */ - if (tmp) { - aa_put_loaddata(udata); - udata = tmp; - break; + tmp = __aa_get_loaddata(rawdata_ent); + /* check we didn't fail the race */ + if (tmp) { + aa_put_loaddata(udata); + udata = tmp; + break; + } } } } @@ -969,7 +971,8 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, list_for_each_entry(ent, &lh, list) { struct aa_policy *policy; - ent->new->rawdata = aa_get_loaddata(udata); + if (aa_g_export_binary) + ent->new->rawdata = aa_get_loaddata(udata); error = __lookup_replace(ns, ent->new->base.hname, !(mask & AA_MAY_REPLACE_POLICY), &ent->old, &info); @@ -1009,7 +1012,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, } /* create new fs entries for introspection if needed */ - if (!udata->dents[AAFS_LOADDATA_DIR]) { + if (!udata->dents[AAFS_LOADDATA_DIR] && aa_g_export_binary) { error = __aa_fs_create_rawdata(ns, udata); if (error) { info = "failed to create raw_data dir and files"; @@ -1037,12 +1040,14 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, /* Done with checks that may fail - do actual replacement */ __aa_bump_ns_revision(ns); - __aa_loaddata_update(udata, ns->revision); + if (aa_g_export_binary) + __aa_loaddata_update(udata, ns->revision); list_for_each_entry_safe(ent, tmp, &lh, list) { list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - if (ent->old && ent->old->rawdata == ent->new->rawdata) { + if (ent->old && ent->old->rawdata == ent->new->rawdata && + ent->new->rawdata) { /* dedup actual profile replacement */ audit_policy(label, op, ns_name, ent->new->base.hname, "same as current profile, skipping", diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 0acca6f2a93f..31d2c2626ea5 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -125,15 +125,16 @@ void __aa_loaddata_update(struct aa_loaddata *data, long revision) { AA_BUG(!data); AA_BUG(!data->ns); - AA_BUG(!data->dents[AAFS_LOADDATA_REVISION]); AA_BUG(!mutex_is_locked(&data->ns->lock)); AA_BUG(data->revision > revision); data->revision = revision; - d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = - current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); - d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = - current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); + if ((data->dents[AAFS_LOADDATA_REVISION])) { + d_inode(data->dents[AAFS_LOADDATA_DIR])->i_mtime = + current_time(d_inode(data->dents[AAFS_LOADDATA_DIR])); + d_inode(data->dents[AAFS_LOADDATA_REVISION])->i_mtime = + current_time(d_inode(data->dents[AAFS_LOADDATA_REVISION])); + } } bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r) @@ -1216,9 +1217,12 @@ int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, goto fail; } } - error = compress_loaddata(udata); - if (error) - goto fail; + + if (aa_g_export_binary) { + error = compress_loaddata(udata); + if (error) + goto fail; + } return 0; fail_profile: From 5bfcbd22ee4e6ad5ae698518fadd0f03ea109537 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 3 Feb 2021 01:35:12 -0800 Subject: [PATCH 06/34] apparmor: Enable tuning of policy paranoid load for embedded systems AppArmor by default does an extensive check on loaded policy that can take quite some time on limited resource systems. Allow disabling this check for embedded systems where system images are readonly and have checksumming making the need for the embedded policy to be fully checked to be redundant. Note: basic policy checks are still done. Signed-off-by: John Johansen --- security/apparmor/Kconfig | 11 +++++++++++ security/apparmor/lsm.c | 2 +- security/apparmor/policy_unpack.c | 4 +++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig index 4c34a28a2ddf..cb3496e00d8a 100644 --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -94,6 +94,17 @@ config SECURITY_APPARMOR_EXPORT_BINARY also increases policy load time. This option is required for checkpoint and restore support, and debugging of loaded policy. +config SECURITY_APPARMOR_PARANOID_LOAD + bool "Perform full verification of loaded policy" + depends on SECURITY_APPARMOR + default y + help + This options allows controlling whether apparmor does a full + verification of loaded policy. This should not be disabled + except for embedded systems where the image is read only, + includes policy, and has some form of integrity check. + Disabling the check will speed up policy loads. + config SECURITY_APPARMOR_KUNIT_TEST bool "Build KUnit tests for policy_unpack.c" if !KUNIT_ALL_TESTS depends on KUNIT=y && SECURITY_APPARMOR diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 84a4e63d922d..301c2bba4867 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1405,7 +1405,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); * DEPRECATED: read only as strict checking of load is always done now * that none root users (user namespaces) can load policy. */ -bool aa_g_paranoid_load = true; +bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_PARANOID_LOAD); module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); static int param_get_aaintbool(char *buffer, const struct kernel_param *kp); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 31d2c2626ea5..55dca9e3af50 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -457,7 +457,9 @@ static struct aa_dfa *unpack_dfa(struct aa_ext *e) ((e->pos - e->start) & 7); size_t pad = ALIGN(sz, 8) - sz; int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | - TO_ACCEPT2_FLAG(YYTD_DATA32) | DFA_FLAG_VERIFY_STATES; + TO_ACCEPT2_FLAG(YYTD_DATA32); + if (aa_g_paranoid_load) + flags |= DFA_FLAG_VERIFY_STATES; dfa = aa_dfa_unpack(blob + pad, size - pad, flags); if (IS_ERR(dfa)) From 482e8050aab4ad10bcd64241f1a9b540463b3274 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 5 Feb 2021 04:56:02 -0800 Subject: [PATCH 07/34] apparmor: don't create raw_sha1 symlink if sha1 hashing is disabled Currently if sha1 hashing of policy is disabled a sha1 hash symlink to the non-existent file is created. There is now reason to create the symlink in this case so don't do it. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 3770dde50a47..15efe4076fc4 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1736,14 +1736,15 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) #ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY if (profile->rawdata) { - dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, - profile->label.proxy, NULL, NULL, - &rawdata_link_sha1_iops); - if (IS_ERR(dent)) - goto fail; - aa_get_proxy(profile->label.proxy); - profile->dents[AAFS_PROF_RAW_HASH] = dent; - + if (aa_g_hash_policy) { + dent = aafs_create("raw_sha1", S_IFLNK | 0444, dir, + profile->label.proxy, NULL, NULL, + &rawdata_link_sha1_iops); + if (IS_ERR(dent)) + goto fail; + aa_get_proxy(profile->label.proxy); + profile->dents[AAFS_PROF_RAW_HASH] = dent; + } dent = aafs_create("raw_abi", S_IFLNK | 0444, dir, profile->label.proxy, NULL, NULL, &rawdata_link_abi_iops); From 7b4bd1274d350a5d0f64b990877c572fb35ad173 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 30 Dec 2021 23:07:38 -0800 Subject: [PATCH 08/34] apparmor: Update MAINTAINERS file with the lastest information Update with the latest website, wiki, and gitlab tree information. Signed-off-by: John Johansen --- MAINTAINERS | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..3935e63a1801 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1370,10 +1370,13 @@ F: include/uapi/linux/apm_bios.h APPARMOR SECURITY MODULE M: John Johansen -L: apparmor@lists.ubuntu.com (subscribers-only, general discussion) +L: apparmor@lists.ubuntu.com (moderated for non-subscribers) S: Supported -W: wiki.apparmor.net +W: apparmor.net +B: https://gitlab.com/apparmor/apparmor-kernel +C: irc://irc.oftc.net/apparmor T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor +T: https://gitlab.com/apparmor/apparmor-kernel.git F: Documentation/admin-guide/LSM/apparmor.rst F: security/apparmor/ From ba77f39062c15d8fc6dcfbf5759747b4de09bfab Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 8 Jul 2020 13:04:43 -0400 Subject: [PATCH 09/34] apparmor: resolve uninitialized symbol warnings in policy_unpack_test.c Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Mike Salvatore Signed-off-by: John Johansen --- security/apparmor/policy_unpack_test.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c index 5c18d2f19862..0641484a1997 100644 --- a/security/apparmor/policy_unpack_test.c +++ b/security/apparmor/policy_unpack_test.c @@ -48,8 +48,8 @@ struct policy_unpack_fixture { size_t e_size; }; -struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf, - struct kunit *test, size_t buf_size) +static struct aa_ext *build_aa_ext_struct(struct policy_unpack_fixture *puf, + struct kunit *test, size_t buf_size) { char *buf; struct aa_ext *e; @@ -439,7 +439,7 @@ static void policy_unpack_test_unpack_u32_with_null_name(struct kunit *test) { struct policy_unpack_fixture *puf = test->priv; bool success; - u32 data; + u32 data = 0; puf->e->pos += TEST_U32_BUF_OFFSET; @@ -456,7 +456,7 @@ static void policy_unpack_test_unpack_u32_with_name(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U32_NAME; bool success; - u32 data; + u32 data = 0; puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; @@ -473,7 +473,7 @@ static void policy_unpack_test_unpack_u32_out_of_bounds(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U32_NAME; bool success; - u32 data; + u32 data = 0; puf->e->pos += TEST_NAMED_U32_BUF_OFFSET; puf->e->end = puf->e->start + TEST_U32_BUF_OFFSET + sizeof(u32); @@ -489,7 +489,7 @@ static void policy_unpack_test_unpack_u64_with_null_name(struct kunit *test) { struct policy_unpack_fixture *puf = test->priv; bool success; - u64 data; + u64 data = 0; puf->e->pos += TEST_U64_BUF_OFFSET; @@ -506,7 +506,7 @@ static void policy_unpack_test_unpack_u64_with_name(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U64_NAME; bool success; - u64 data; + u64 data = 0; puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; @@ -523,7 +523,7 @@ static void policy_unpack_test_unpack_u64_out_of_bounds(struct kunit *test) struct policy_unpack_fixture *puf = test->priv; const char name[] = TEST_U64_NAME; bool success; - u64 data; + u64 data = 0; puf->e->pos += TEST_NAMED_U64_BUF_OFFSET; puf->e->end = puf->e->start + TEST_U64_BUF_OFFSET + sizeof(u64); From 68ff8540cc9e4ab557065b3f635c1ff4c96e1f1c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 29 Apr 2021 01:48:28 -0700 Subject: [PATCH 10/34] apparmor: fix quiet_denied for file rules Global quieting of denied AppArmor generated file events is not handled correctly. Unfortunately the is checking if quieting of all audit events is set instead of just denied events. Fixes: 67012e8209df ("AppArmor: basic auditing infrastructure.") Signed-off-by: John Johansen --- security/apparmor/audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index f7e97c7e80f3..704b0c895605 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -137,7 +137,7 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, } if (AUDIT_MODE(profile) == AUDIT_QUIET || (type == AUDIT_APPARMOR_DENIED && - AUDIT_MODE(profile) == AUDIT_QUIET)) + AUDIT_MODE(profile) == AUDIT_QUIET_DENIED)) return aad(sa)->error; if (KILL_MODE(profile) && type == AUDIT_APPARMOR_DENIED) From 84117994bc103617787147b8538a5c021b2ca79f Mon Sep 17 00:00:00 2001 From: Minghao Chi Date: Wed, 12 Jan 2022 08:03:56 +0000 Subject: [PATCH 11/34] security/apparmor: remove redundant ret variable Return value from nf_register_net_hooks() directly instead of taking this in another redundant variable. Reported-by: Zeal Robot Signed-off-by: Minghao Chi Signed-off-by: CGEL ZTE Signed-off-by: John Johansen --- security/apparmor/lsm.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 301c2bba4867..1ebcf1a6e1d0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1825,11 +1825,8 @@ static const struct nf_hook_ops apparmor_nf_ops[] = { static int __net_init apparmor_nf_register(struct net *net) { - int ret; - - ret = nf_register_net_hooks(net, apparmor_nf_ops, + return nf_register_net_hooks(net, apparmor_nf_ops, ARRAY_SIZE(apparmor_nf_ops)); - return ret; } static void __net_exit apparmor_nf_unregister(struct net *net) From ec240b5905bbb09a03dccffee03062cf39e38dc2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 25 Jan 2022 00:37:42 -0800 Subject: [PATCH 12/34] apparmor: Fix failed mount permission check error message When the mount check fails due to a permission check failure instead of explicitly at one of the subcomponent checks, AppArmor is reporting a failure in the flags match. However this is not true and AppArmor can not attribute the error at this point to any particular component, and should only indicate the mount failed due to missing permissions. Fixes: 2ea3ffb7782a ("apparmor: add mount mediation") Signed-off-by: John Johansen --- security/apparmor/mount.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index aa6fcfde3051..23aafe68d49a 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -229,7 +229,8 @@ static const char * const mnt_info_table[] = { "failed srcname match", "failed type match", "failed flags match", - "failed data match" + "failed data match", + "failed perms check" }; /* @@ -284,8 +285,8 @@ static int do_match_mnt(struct aa_dfa *dfa, unsigned int start, return 0; } - /* failed at end of flags match */ - return 4; + /* failed at perms check, don't confuse with flags match */ + return 6; } From c0ea4b919daed7333ebc0d630adc262eb0a0d8c1 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 24 Jan 2022 19:56:06 -0600 Subject: [PATCH 13/34] apparmor: Use struct_size() helper in kmalloc() Make use of the struct_size() helper instead of an open-coded version, in order to avoid any potential type mistakes or integer overflows that, in the worst scenario, could lead to heap overflows. Also, address the following sparse warnings: security/apparmor/lib.c:139:23: warning: using sizeof on a flexible structure Link: https://github.com/KSPP/linux/issues/174 Signed-off-by: Gustavo A. R. Silva Signed-off-by: John Johansen --- security/apparmor/lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index fa49b81eb54c..5eda003c0d45 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -136,7 +136,7 @@ __counted char *aa_str_alloc(int size, gfp_t gfp) { struct counted_str *str; - str = kmalloc(sizeof(struct counted_str) + size, gfp); + str = kmalloc(struct_size(str, name, size), gfp); if (!str) return NULL; From e21851b349b8dd0af00fc4d887983a2767eb393c Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sat, 29 Jan 2022 10:50:59 +0800 Subject: [PATCH 14/34] apparmor: Fix match_mnt_path_str() and match_mnt() kernel-doc comment Fix a spelling problem and change @mntpath to @path to remove warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. security/apparmor/mount.c:321: warning: Function parameter or member 'devname' not described in 'match_mnt_path_str' security/apparmor/mount.c:321: warning: Excess function parameter 'devnme' description in 'match_mnt_path_str' security/apparmor/mount.c:377: warning: Function parameter or member 'path' not described in 'match_mnt' security/apparmor/mount.c:377: warning: Excess function parameter 'mntpath' description in 'match_mnt' Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/mount.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 23aafe68d49a..5cc5de062fc8 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -304,7 +304,7 @@ static int path_flags(struct aa_profile *profile, const struct path *path) * @profile: the confining profile * @mntpath: for the mntpnt (NOT NULL) * @buffer: buffer to be used to lookup mntpath - * @devnme: string for the devname/src_name (MAY BE NULL OR ERRPTR) + * @devname: string for the devname/src_name (MAY BE NULL OR ERRPTR) * @type: string for the dev type (MAYBE NULL) * @flags: mount flags to match * @data: fs mount data (MAYBE NULL) @@ -359,7 +359,7 @@ audit: /** * match_mnt - handle path matching for mount * @profile: the confining profile - * @mntpath: for the mntpnt (NOT NULL) + * @path: for the mntpnt (NOT NULL) * @buffer: buffer to be used to lookup mntpath * @devpath: path devname/src_name (MAYBE NULL) * @devbuffer: buffer to be used to lookup devname/src_name From 5ee5d37421601f23f463b062f211b404b0fd6922 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sat, 29 Jan 2022 10:51:00 +0800 Subject: [PATCH 15/34] apparmor: Fix some kernel-doc comments Add the description of @ns_name, change function name aa_u16_chunck to unpack_u16_chunk and verify_head to verify_header in kernel-doc comment to remove warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. security/apparmor/policy_unpack.c:224: warning: expecting prototype for aa_u16_chunck(). Prototype was for unpack_u16_chunk() instead security/apparmor/policy_unpack.c:678: warning: Function parameter or member 'ns_name' not described in 'unpack_profile' security/apparmor/policy_unpack.c:950: warning: expecting prototype for verify_head(). Prototype was for verify_header() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/policy_unpack.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 55dca9e3af50..3cc0fd2dff87 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -214,7 +214,7 @@ static void *kvmemdup(const void *src, size_t len) } /** - * aa_u16_chunck - test and do bounds checking for a u16 size based chunk + * unpack_u16_chunk - test and do bounds checking for a u16 size based chunk * @e: serialized data read head (NOT NULL) * @chunk: start address for chunk of data (NOT NULL) * @@ -671,6 +671,7 @@ static int datacmp(struct rhashtable_compare_arg *arg, const void *obj) /** * unpack_profile - unpack a serialized profile * @e: serialized data extent information (NOT NULL) + * @ns_name: pointer of newly allocated copy of %NULL in case of error * * NOTE: unpack profile sets audit struct if there is a failure */ @@ -939,7 +940,7 @@ fail: } /** - * verify_head - unpack serialized stream header + * verify_header - unpack serialized stream header * @e: serialized data read head (NOT NULL) * @required: whether the header is required or optional * @ns: Returns - namespace if one is specified else NULL (NOT NULL) From 564423bf9c952bcc029b5b03c02e2937cb7a6550 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Sat, 29 Jan 2022 10:51:01 +0800 Subject: [PATCH 16/34] apparmor: Fix some kernel-doc comments Don't use /** for non-kernel-doc comments and change function name aa_mangle_name to mangle_name in kernel-doc comment to Remove some warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. security/apparmor/apparmorfs.c:1503: warning: Cannot understand * on line 1503 - I thought it was a doc line security/apparmor/apparmorfs.c:1530: warning: Cannot understand * on line 1530 - I thought it was a doc line security/apparmor/apparmorfs.c:1892: warning: Cannot understand * on line 1892 - I thought it was a doc line security/apparmor/apparmorfs.c:108: warning: expecting prototype for aa_mangle_name(). Prototype was for mangle_name() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 15efe4076fc4..4d7df859542d 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -98,7 +98,7 @@ static struct rawdata_f_data *rawdata_f_data_alloc(size_t size) #endif /** - * aa_mangle_name - mangle a profile name to std profile layout form + * mangle_name - mangle a profile name to std profile layout form * @name: profile name to mangle (NOT NULL) * @target: buffer to store mangled name, same length as @name (MAYBE NULL) * @@ -1499,7 +1499,7 @@ fail: /** fns to setup dynamic per profile/namespace files **/ -/** +/* * * Requires: @profile->ns->lock held */ @@ -1526,7 +1526,7 @@ void __aafs_profile_rmdir(struct aa_profile *profile) } } -/** +/* * * Requires: @old->ns->lock held */ @@ -1888,7 +1888,7 @@ static void __aa_fs_list_remove_rawdata(struct aa_ns *ns) __aa_fs_remove_rawdata(ent); } -/** +/* * * Requires: @ns->lock held */ From 3e2a3a0830a2090e766d0d887d52c67de2a6f323 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 13 Feb 2022 13:32:28 -0800 Subject: [PATCH 17/34] apparmor: fix aa_label_asxprint return check Clang static analysis reports this issue label.c:1802:3: warning: 2nd function call argument is an uninitialized value pr_info("%s", str); ^~~~~~~~~~~~~~~~~~ str is set from a successful call to aa_label_asxprint(&str, ...) On failure a negative value is returned, not a -1. So change the check. Fixes: f1bd904175e8 ("apparmor: add the base fns() for domain labels") Signed-off-by: Tom Rix Signed-off-by: John Johansen --- security/apparmor/label.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 9eb9a9237926..a658b67c784c 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1744,7 +1744,7 @@ void aa_label_xaudit(struct audit_buffer *ab, struct aa_ns *ns, if (!use_label_hname(ns, label, flags) || display_mode(ns, label, flags)) { len = aa_label_asxprint(&name, ns, label, flags, gfp); - if (len == -1) { + if (len < 0) { AA_DEBUG("label print error"); return; } @@ -1772,7 +1772,7 @@ void aa_label_seq_xprint(struct seq_file *f, struct aa_ns *ns, int len; len = aa_label_asxprint(&str, ns, label, flags, gfp); - if (len == -1) { + if (len < 0) { AA_DEBUG("label print error"); return; } @@ -1795,7 +1795,7 @@ void aa_label_xprintk(struct aa_ns *ns, struct aa_label *label, int flags, int len; len = aa_label_asxprint(&str, ns, label, flags, gfp); - if (len == -1) { + if (len < 0) { AA_DEBUG("label print error"); return; } From f9da5b14521cbb57ff45bd8134d3b8320638b1e6 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 22 Feb 2022 02:09:20 -0800 Subject: [PATCH 18/34] apparmor: Fix undefined reference to `zlib_deflate_workspacesize' IF CONFIG_SECURITY_APPARMOR_EXPORT_BINARY is disabled, there remains some unneed references to zlib, and can result in undefined symbol references if ZLIB_INFLATE or ZLIB_DEFLATE are not defined. Reported-by: kernel test robot Fixes: abfb9c0725f2 ("apparmor: make export of raw binary profile to userspace optional") Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 63 ++++++++++++++++--------------- security/apparmor/policy_unpack.c | 8 +++- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 4d7df859542d..8b9c92f3ff95 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -1296,44 +1296,47 @@ SEQ_RAWDATA_FOPS(compressed_size); static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen) { - int error; - struct z_stream_s strm; +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY + if (aa_g_rawdata_compression_level != 0) { + int error = 0; + struct z_stream_s strm; - if (aa_g_rawdata_compression_level == 0) { - if (dlen < slen) - return -EINVAL; - memcpy(dst, src, slen); - return 0; - } + memset(&strm, 0, sizeof(strm)); - memset(&strm, 0, sizeof(strm)); + strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); + if (!strm.workspace) + return -ENOMEM; - strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (!strm.workspace) - return -ENOMEM; + strm.next_in = src; + strm.avail_in = slen; - strm.next_in = src; - strm.avail_in = slen; + error = zlib_inflateInit(&strm); + if (error != Z_OK) { + error = -ENOMEM; + goto fail_inflate_init; + } - error = zlib_inflateInit(&strm); - if (error != Z_OK) { - error = -ENOMEM; - goto fail_inflate_init; - } + strm.next_out = dst; + strm.avail_out = dlen; - strm.next_out = dst; - strm.avail_out = dlen; + error = zlib_inflate(&strm, Z_FINISH); + if (error != Z_STREAM_END) + error = -EINVAL; + else + error = 0; - error = zlib_inflate(&strm, Z_FINISH); - if (error != Z_STREAM_END) - error = -EINVAL; - else - error = 0; - - zlib_inflateEnd(&strm); + zlib_inflateEnd(&strm); fail_inflate_init: - kvfree(strm.workspace); - return error; + kvfree(strm.workspace); + + return error; + } +#endif + + if (dlen < slen) + return -EINVAL; + memcpy(dst, src, slen); + return 0; } static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size, diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 3cc0fd2dff87..df4033db0e0f 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -1056,6 +1056,7 @@ struct aa_load_ent *aa_load_ent_alloc(void) static int deflate_compress(const char *src, size_t slen, char **dst, size_t *dlen) { +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY int error; struct z_stream_s strm; void *stgbuf, *dstbuf; @@ -1127,6 +1128,10 @@ fail_deflate_init: fail_deflate: kvfree(stgbuf); goto fail_stg_alloc; +#else + *dlen = slen; + return 0; +#endif } static int compress_loaddata(struct aa_loaddata *data) @@ -1145,7 +1150,8 @@ static int compress_loaddata(struct aa_loaddata *data) if (error) return error; - kvfree(udata); + if (udata != data->data) + kvfree(udata); } else data->compressed_size = data->size; From bab1f77fb815374e9d092a72d5a2abc7c943bca3 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 17 Mar 2022 09:03:30 +0800 Subject: [PATCH 19/34] apparmor: Fix some kernel-doc comments Remove some warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. security/apparmor/domain.c:137: warning: Function parameter or member 'state' not described in 'label_compound_match' security/apparmor/domain.c:137: warning: Excess function parameter 'start' description in 'label_compound_match' security/apparmor/domain.c:1294: warning: Excess function parameter 'onexec' description in 'aa_change_profile' Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/domain.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index a29e69d2c300..d71023f5c9c4 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -119,7 +119,7 @@ static inline unsigned int match_component(struct aa_profile *profile, * @profile: profile to find perms for * @label: label to check access permissions for * @stack: whether this is a stacking request - * @start: state to start match in + * @state: state to start match in * @subns: whether to do permission checks on components in a subns * @request: permissions to request * @perms: perms struct to set @@ -1279,7 +1279,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name, /** * aa_change_profile - perform a one-way profile transition * @fqname: name of profile may include namespace (NOT NULL) - * @onexec: whether this transition is to take place immediately or at exec * @flags: flags affecting change behavior * * Change to new profile @name. Unlike with hats, there is no way From 11c3627ec6b56c1525013f336f41b79a983b4d46 Mon Sep 17 00:00:00 2001 From: Xin Xiong Date: Thu, 28 Apr 2022 11:39:08 +0800 Subject: [PATCH 20/34] apparmor: fix reference count leak in aa_pivotroot() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The aa_pivotroot() function has a reference counting bug in a specific path. When aa_replace_current_label() returns on success, the function forgets to decrement the reference count of “target”, which is increased earlier by build_pivotroot(), causing a reference leak. Fix it by decreasing the refcount of “target” in that path. Fixes: 2ea3ffb7782a ("apparmor: add mount mediation") Co-developed-by: Xiyu Yang Signed-off-by: Xiyu Yang Co-developed-by: Xin Tan Signed-off-by: Xin Tan Signed-off-by: Xin Xiong Signed-off-by: John Johansen --- security/apparmor/mount.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 5cc5de062fc8..fa64a2db3aec 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -719,6 +719,7 @@ int aa_pivotroot(struct aa_label *label, const struct path *old_path, aa_put_label(target); goto out; } + aa_put_label(target); } else /* already audited error */ error = PTR_ERR(target); From 417ea9fe972d2654a268ad66e89c8fcae67017c3 Mon Sep 17 00:00:00 2001 From: Xiu Jianfeng Date: Tue, 14 Jun 2022 17:00:01 +0800 Subject: [PATCH 21/34] apparmor: Fix memleak in aa_simple_write_to_buffer() When copy_from_user failed, the memory is freed by kvfree. however the management struct and data blob are allocated independently, so only kvfree(data) cause a memleak issue here. Use aa_put_loaddata(data) to fix this issue. Fixes: a6a52579e52b5 ("apparmor: split load data into management struct and data blob") Signed-off-by: Xiu Jianfeng Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 8b9c92f3ff95..0275a350dc23 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -403,7 +403,7 @@ static struct aa_loaddata *aa_simple_write_to_buffer(const char __user *userbuf, data->size = copy_size; if (copy_from_user(data->data, userbuf, copy_size)) { - kvfree(data); + aa_put_loaddata(data); return ERR_PTR(-EFAULT); } From e2f76ad7d2859e333609c775fda707f205d93fd8 Mon Sep 17 00:00:00 2001 From: David Gow Date: Wed, 6 Jul 2022 18:06:07 +0800 Subject: [PATCH 22/34] apparmor: test: Remove some casts which are no-longer required With some of the stricter type checking in KUnit's EXPECT macros removed, several casts in policy_unpack_test are no longer required. Remove the unnecessary casts, making the conditions clearer. Reviewed-by: Brendan Higgins Acked-by: John Johansen Signed-off-by: David Gow Signed-off-by: John Johansen --- security/apparmor/policy_unpack_test.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/security/apparmor/policy_unpack_test.c b/security/apparmor/policy_unpack_test.c index 0641484a1997..0a969b2e03db 100644 --- a/security/apparmor/policy_unpack_test.c +++ b/security/apparmor/policy_unpack_test.c @@ -177,7 +177,7 @@ static void policy_unpack_test_unpack_array_out_of_bounds(struct kunit *test) array_size = unpack_array(puf->e, name); - KUNIT_EXPECT_EQ(test, array_size, (u16)0); + KUNIT_EXPECT_EQ(test, array_size, 0); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_NAMED_ARRAY_BUF_OFFSET); } @@ -391,10 +391,10 @@ static void policy_unpack_test_unpack_u16_chunk_basic(struct kunit *test) size = unpack_u16_chunk(puf->e, &chunk); - KUNIT_EXPECT_PTR_EQ(test, (void *)chunk, + KUNIT_EXPECT_PTR_EQ(test, chunk, puf->e->start + TEST_U16_OFFSET + 2); - KUNIT_EXPECT_EQ(test, size, (size_t)TEST_U16_DATA); - KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (void *)(chunk + TEST_U16_DATA)); + KUNIT_EXPECT_EQ(test, size, TEST_U16_DATA); + KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, (chunk + TEST_U16_DATA)); } static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1( @@ -408,7 +408,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_1( size = unpack_u16_chunk(puf->e, &chunk); - KUNIT_EXPECT_EQ(test, size, (size_t)0); + KUNIT_EXPECT_EQ(test, size, 0); KUNIT_EXPECT_NULL(test, chunk); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->end - 1); } @@ -430,7 +430,7 @@ static void policy_unpack_test_unpack_u16_chunk_out_of_bounds_2( size = unpack_u16_chunk(puf->e, &chunk); - KUNIT_EXPECT_EQ(test, size, (size_t)0); + KUNIT_EXPECT_EQ(test, size, 0); KUNIT_EXPECT_NULL(test, chunk); KUNIT_EXPECT_PTR_EQ(test, puf->e->pos, puf->e->start + TEST_U16_OFFSET); } From 95c0581f9bfdfbe97126ba1c7f5650a9dd064dda Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 24 May 2022 02:38:12 -0700 Subject: [PATCH 23/34] apparmor: add a kernel label to use on kernel objects Separate kernel objects from unconfined. This is done so we can distinguish between the two in debugging, auditing and in preparation for being able to replace unconfined, which is not appropriate for the kernel. The kernel label will continue to behave similar to unconfined. Acked-by: Jon Tourville Signed-off-by: John Johansen --- security/apparmor/include/policy_ns.h | 1 + security/apparmor/lsm.c | 5 +--- security/apparmor/net.c | 3 +- security/apparmor/policy_ns.c | 41 +++++++++++++++++++++------ 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 3df6f804922d..33d665516fc1 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -74,6 +74,7 @@ struct aa_ns { struct dentry *dents[AAFS_NS_SIZEOF]; }; +extern struct aa_label *kernel_t; extern struct aa_ns *root_ns; extern const char *aa_hidden_ns_name; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1ebcf1a6e1d0..9efb7ac60c7c 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -886,10 +886,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family, struct aa_label *label; if (kern) { - struct aa_ns *ns = aa_get_current_ns(); - - label = aa_get_label(ns_unconfined(ns)); - aa_put_ns(ns); + label = aa_get_label(kernel_t); } else label = aa_get_current_label(); diff --git a/security/apparmor/net.c b/security/apparmor/net.c index e0c1b50d6edd..7efe4d17273d 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -145,12 +145,13 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, struct sock *sk) { + struct aa_sk_ctx *ctx = SK_CTX(sk); int error = 0; AA_BUG(!label); AA_BUG(!sk); - if (!unconfined(label)) { + if (ctx->label != kernel_t && !unconfined(label)) { struct aa_profile *profile; DEFINE_AUDIT_SK(sa, op, sk); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 70921d95fb40..300953a02a24 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -22,6 +22,9 @@ #include "include/label.h" #include "include/policy.h" +/* kernel label */ +struct aa_label *kernel_t; + /* root profile namespace */ struct aa_ns *root_ns; const char *aa_hidden_ns_name = "---"; @@ -77,6 +80,23 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns) return aa_hidden_ns_name; } +struct aa_profile *alloc_unconfined(const char *name) +{ + struct aa_profile *profile; + + profile = aa_alloc_profile(name, NULL, GFP_KERNEL); + if (!profile) + return NULL; + + profile->label.flags |= FLAG_IX_ON_NAME_ERROR | + FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; + profile->mode = APPARMOR_UNCONFINED; + profile->file.dfa = aa_get_dfa(nulldfa); + profile->policy.dfa = aa_get_dfa(nulldfa); + + return profile; +} + /** * alloc_ns - allocate, initialize and return a new namespace * @prefix: parent namespace name (MAYBE NULL) @@ -101,16 +121,9 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) init_waitqueue_head(&ns->wait); /* released by aa_free_ns() */ - ns->unconfined = aa_alloc_profile("unconfined", NULL, GFP_KERNEL); + ns->unconfined = alloc_unconfined("unconfined"); if (!ns->unconfined) goto fail_unconfined; - - ns->unconfined->label.flags |= FLAG_IX_ON_NAME_ERROR | - FLAG_IMMUTIBLE | FLAG_NS_COUNT | FLAG_UNCONFINED; - ns->unconfined->mode = APPARMOR_UNCONFINED; - ns->unconfined->file.dfa = aa_get_dfa(nulldfa); - ns->unconfined->policy.dfa = aa_get_dfa(nulldfa); - /* ns and ns->unconfined share ns->unconfined refcount */ ns->unconfined->ns = ns; @@ -388,11 +401,22 @@ static void __ns_list_release(struct list_head *head) */ int __init aa_alloc_root_ns(void) { + struct aa_profile *kernel_p; + /* released by aa_free_root_ns - used as list ref*/ root_ns = alloc_ns(NULL, "root"); if (!root_ns) return -ENOMEM; + kernel_p = alloc_unconfined("kernel_t"); + if (!kernel_p) { + destroy_ns(root_ns); + aa_free_ns(root_ns); + return -ENOMEM; + } + kernel_t = &kernel_p->label; + root_ns->unconfined->ns = aa_get_ns(root_ns); + return 0; } @@ -405,6 +429,7 @@ void __init aa_free_root_ns(void) root_ns = NULL; + aa_label_free(kernel_t); destroy_ns(ns); aa_put_ns(ns); } From df4390934da48e0462d1e77fba3e15f080e2c2a0 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 6 Jun 2022 21:23:22 +0100 Subject: [PATCH 24/34] apparmor: Convert secid mapping to XArrays instead of IDR XArrays are a better match than IDR for how AppArmor is mapping secids. Specifically AppArmor is trying to keep the allocation dense. XArrays also have the advantage of avoiding the complexity IDRs preallocation. In addition this avoids/fixes a lockdep issue raised in the LKML thread "Linux 5.18-rc4" where there is a report of an interaction between apparmor and IPC, this warning may have been spurious as the reported issue is in a per-cpu local lock taken by the IDR. With the one side in the IPC id allocation and the other in AppArmor's secid allocation. Description by John Johansen Message-Id: <226cee6a-6ca1-b603-db08-8500cd8f77b7@gnuweeb.org> Signed-off-by: Matthew Wilcox Signed-off-by: John Johansen --- security/apparmor/include/secid.h | 2 -- security/apparmor/lsm.c | 2 -- security/apparmor/secid.c | 41 ++++++++++--------------------- 3 files changed, 13 insertions(+), 32 deletions(-) diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index 48ff1ddecad5..278dff5ecd1f 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h @@ -31,6 +31,4 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp); void aa_free_secid(u32 secid); void aa_secid_update(u32 secid, struct aa_label *label); -void aa_secids_init(void); - #endif /* __AA_SECID_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 9efb7ac60c7c..b1a0f2172a2e 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1857,8 +1857,6 @@ static int __init apparmor_init(void) { int error; - aa_secids_init(); - error = aa_setup_dfa_engine(); if (error) { AA_ERROR("Unable to setup dfa engine\n"); diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index ce545f99259e..3b08942db1f6 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c @@ -13,9 +13,9 @@ #include #include #include -#include #include #include +#include #include "include/cred.h" #include "include/lib.h" @@ -29,8 +29,7 @@ */ #define AA_FIRST_SECID 2 -static DEFINE_IDR(aa_secids); -static DEFINE_SPINLOCK(secid_lock); +static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE); /* * TODO: allow policy to reserve a secid range? @@ -47,9 +46,9 @@ void aa_secid_update(u32 secid, struct aa_label *label) { unsigned long flags; - spin_lock_irqsave(&secid_lock, flags); - idr_replace(&aa_secids, label, secid); - spin_unlock_irqrestore(&secid_lock, flags); + xa_lock_irqsave(&aa_secids, flags); + __xa_store(&aa_secids, secid, label, 0); + xa_unlock_irqrestore(&aa_secids, flags); } /** @@ -58,13 +57,7 @@ void aa_secid_update(u32 secid, struct aa_label *label) */ struct aa_label *aa_secid_to_label(u32 secid) { - struct aa_label *label; - - rcu_read_lock(); - label = idr_find(&aa_secids, secid); - rcu_read_unlock(); - - return label; + return xa_load(&aa_secids, secid); } int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) @@ -126,19 +119,16 @@ int aa_alloc_secid(struct aa_label *label, gfp_t gfp) unsigned long flags; int ret; - idr_preload(gfp); - spin_lock_irqsave(&secid_lock, flags); - ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC); - spin_unlock_irqrestore(&secid_lock, flags); - idr_preload_end(); + xa_lock_irqsave(&aa_secids, flags); + ret = __xa_alloc(&aa_secids, &label->secid, label, + XA_LIMIT(AA_FIRST_SECID, INT_MAX), gfp); + xa_unlock_irqrestore(&aa_secids, flags); if (ret < 0) { label->secid = AA_SECID_INVALID; return ret; } - AA_BUG(ret == AA_SECID_INVALID); - label->secid = ret; return 0; } @@ -150,12 +140,7 @@ void aa_free_secid(u32 secid) { unsigned long flags; - spin_lock_irqsave(&secid_lock, flags); - idr_remove(&aa_secids, secid); - spin_unlock_irqrestore(&secid_lock, flags); -} - -void aa_secids_init(void) -{ - idr_init_base(&aa_secids, AA_FIRST_SECID); + xa_lock_irqsave(&aa_secids, flags); + __xa_erase(&aa_secids, secid); + xa_unlock_irqrestore(&aa_secids, flags); } From 524d8e14258a3c31bcaf915db5762e41249eb924 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 6 Oct 2020 14:43:16 -0700 Subject: [PATCH 25/34] apparmor: disable showing the mode as part of a secid to secctx Displaying the mode as part of the seectx takes up unnecessary memory, makes it so we can't use refcounted secctx so we need to alloc/free on every conversion from secid to secctx and introduces a space that could be potentially mishandled by tooling. Eg. In an audit record we get subj_type=firefix (enforce) Having the mode reported is not necessary, and might even be confusing eg. when writing an audit rule to match the above record field you would use -F subj_type=firefox ie. the mode is not included. AppArmor provides ways to find the mode without reporting as part of the secctx. So disable this by default before its use is wide spread and we can't. For now we add a sysctl to control the behavior as we can't guarantee no one is using this. Acked-by: Andrea Righi Signed-off-by: John Johansen --- security/apparmor/include/secid.h | 3 +++ security/apparmor/lsm.c | 8 ++++++++ security/apparmor/secid.c | 15 +++++++++------ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index 278dff5ecd1f..a912a5d5d04f 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h @@ -21,6 +21,9 @@ struct aa_label; /* secid value that matches any other secid */ #define AA_SECID_WILDCARD 1 +/* sysctl to enable displaying mode when converting secid to secctx */ +extern int apparmor_display_secid_mode; + struct aa_label *aa_secid_to_label(u32 secid); int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index b1a0f2172a2e..090a20805664 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1764,6 +1764,14 @@ static struct ctl_table apparmor_sysctl_table[] = { .mode = 0600, .proc_handler = apparmor_dointvec, }, + { + .procname = "apparmor_display_secid_mode", + .data = &apparmor_display_secid_mode, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = apparmor_dointvec, + }, + { } }; diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index 3b08942db1f6..24a0e23f1b2b 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c @@ -31,6 +31,8 @@ static DEFINE_XARRAY_FLAGS(aa_secids, XA_FLAGS_LOCK_IRQ | XA_FLAGS_TRACK_FREE); +int apparmor_display_secid_mode; + /* * TODO: allow policy to reserve a secid range? * TODO: add secid pinning @@ -64,6 +66,7 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { /* TODO: cache secctx and ref count so we don't have to recreate */ struct aa_label *label = aa_secid_to_label(secid); + int flags = FLAG_VIEW_SUBNS | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT; int len; AA_BUG(!seclen); @@ -71,15 +74,15 @@ int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) if (!label) return -EINVAL; + if (apparmor_display_secid_mode) + flags |= FLAG_SHOW_MODE; + if (secdata) len = aa_label_asxprint(secdata, root_ns, label, - FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | - FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT, - GFP_ATOMIC); + flags, GFP_ATOMIC); else - len = aa_label_snxprint(NULL, 0, root_ns, label, - FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | - FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT); + len = aa_label_snxprint(NULL, 0, root_ns, label, flags); + if (len < 0) return -ENOMEM; From a3f215ef088f1fc3e751dc9a5fa4c1a22f16212b Mon Sep 17 00:00:00 2001 From: "Souptick Joarder (HPE)" Date: Tue, 19 Jul 2022 07:42:18 +0530 Subject: [PATCH 26/34] apparmor: Mark alloc_unconfined() as static Kernel test robot throws below warning -> security/apparmor/policy_ns.c:83:20: warning: no previous prototype for function 'alloc_unconfined' [-Wmissing-prototypes] Mark it as static. Reported-by: kernel test robot Signed-off-by: Souptick Joarder (HPE) Signed-off-by: John Johansen --- security/apparmor/policy_ns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 300953a02a24..4f6e9b3c24e6 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -80,7 +80,7 @@ const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view, bool subns) return aa_hidden_ns_name; } -struct aa_profile *alloc_unconfined(const char *name) +static struct aa_profile *alloc_unconfined(const char *name) { struct aa_profile *profile; From f378973698657404f059687025e1e35f229b124c Mon Sep 17 00:00:00 2001 From: Yang Li Date: Mon, 18 Jul 2022 14:30:22 +0800 Subject: [PATCH 27/34] apparmor: Fix some kernel-doc comments Remove warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. security/apparmor/policy_ns.c:65: warning: Function parameter or member 'curr' not described in 'aa_ns_name' security/apparmor/policy_ns.c:65: warning: Function parameter or member 'view' not described in 'aa_ns_name' security/apparmor/policy_ns.c:65: warning: Function parameter or member 'subns' not described in 'aa_ns_name' security/apparmor/policy_ns.c:65: warning: expecting prototype for aa_na_name(). Prototype was for aa_ns_name() instead security/apparmor/policy_ns.c:214: warning: Function parameter or member 'view' not described in '__aa_lookupn_ns' security/apparmor/policy_ns.c:214: warning: Excess function parameter 'base' description in '__aa_lookupn_ns' security/apparmor/policy_ns.c:297: warning: expecting prototype for aa_create_ns(). Prototype was for __aa_find_or_create_ns() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: John Johansen --- security/apparmor/policy_ns.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 4f6e9b3c24e6..43beaad083fe 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -54,10 +54,10 @@ bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns) } /** - * aa_na_name - Find the ns name to display for @view from @curr - * @curr - current namespace (NOT NULL) - * @view - namespace attempting to view (NOT NULL) - * @subns - are subns visible + * aa_ns_name - Find the ns name to display for @view from @curr + * @curr: current namespace (NOT NULL) + * @view: namespace attempting to view (NOT NULL) + * @subns: are subns visible * * Returns: name of @view visible from @curr */ @@ -200,7 +200,7 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) /** * __aa_lookupn_ns - lookup the namespace matching @hname - * @base: base list to start looking up profile name from (NOT NULL) + * @view: namespace to search in (NOT NULL) * @hname: hierarchical ns name (NOT NULL) * @n: length of @hname * @@ -285,7 +285,7 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, } /** - * aa_create_ns - create an ns, fail if it already exists + * __aa_find_or_create_ns - create an ns, fail if it already exists * @parent: the parent of the namespace being created * @name: the name of the namespace * @dir: if not null the dir to put the ns entries in From 3bbb7b2e9bbcd22e539e23034da753898fe3b4dc Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sat, 26 Mar 2022 01:52:06 -0700 Subject: [PATCH 28/34] apparmor: fix setting unconfined mode on a loaded profile When loading a profile that is set to unconfined mode, that label flag is not set when it should be. Ensure it is set so that when used in a label the unconfined check will be applied correctly. Fixes: 038165070aa5 ("apparmor: allow setting any profile into the unconfined state") Signed-off-by: John Johansen --- security/apparmor/policy_unpack.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index df4033db0e0f..302fecf9b197 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -750,16 +750,18 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) profile->label.flags |= FLAG_HAT; if (!unpack_u32(e, &tmp, NULL)) goto fail; - if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) + if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) { profile->mode = APPARMOR_COMPLAIN; - else if (tmp == PACKED_MODE_ENFORCE) + } else if (tmp == PACKED_MODE_ENFORCE) { profile->mode = APPARMOR_ENFORCE; - else if (tmp == PACKED_MODE_KILL) + } else if (tmp == PACKED_MODE_KILL) { profile->mode = APPARMOR_KILL; - else if (tmp == PACKED_MODE_UNCONFINED) + } else if (tmp == PACKED_MODE_UNCONFINED) { profile->mode = APPARMOR_UNCONFINED; - else + profile->label.flags |= FLAG_UNCONFINED; + } else { goto fail; + } if (!unpack_u32(e, &tmp, NULL)) goto fail; if (tmp) From 2504db207146543736e877241f3b3de005cbe056 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sat, 26 Mar 2022 01:58:15 -0700 Subject: [PATCH 29/34] apparmor: fix overlapping attachment computation When finding the profile via patterned attachments, the longest left match is being set to the static compile time value and not using the runtime computed value. Fix this by setting the candidate value to the greater of the precomputed value or runtime computed value. Fixes: 21f606610502 ("apparmor: improve overlapping domain attachment resolution") Signed-off-by: John Johansen --- security/apparmor/domain.c | 2 +- security/apparmor/include/policy.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index d71023f5c9c4..91689d34d281 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -466,7 +466,7 @@ restart: * xattrs, or a longer match */ candidate = profile; - candidate_len = profile->xmatch_len; + candidate_len = max(count, profile->xmatch_len); candidate_xattrs = ret; conflict = false; } diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index cb5ef21991b7..232d3d9566eb 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -135,7 +135,7 @@ struct aa_profile { const char *attach; struct aa_dfa *xmatch; - int xmatch_len; + unsigned int xmatch_len; enum audit_mode audit; long mode; u32 path_flags; From c1ed5da197652318341fd36333d45e8e6d5c3359 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sat, 26 Mar 2022 01:46:18 -0700 Subject: [PATCH 30/34] apparmor: allow label to carry debug flags Allow labels to have debug flags that can be used to trigger debug output only from profiles/labels that are marked. This can help reduce debug output by allowing debug to be target to a specific confinement condition. Signed-off-by: John Johansen --- security/apparmor/include/label.h | 2 ++ security/apparmor/include/path.h | 4 ++-- security/apparmor/include/policy.h | 4 ++++ security/apparmor/include/policy_unpack.h | 2 ++ security/apparmor/label.c | 12 ++++++------ security/apparmor/policy_unpack.c | 4 ++++ 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index 9101c2c76d9e..860484c6f99a 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h @@ -92,6 +92,8 @@ enum label_flags { FLAG_STALE = 0x800, /* replaced/removed */ FLAG_RENAMED = 0x1000, /* label has renaming in it */ FLAG_REVOKED = 0x2000, /* label has revocation in it */ + FLAG_DEBUG1 = 0x4000, + FLAG_DEBUG2 = 0x8000, /* These flags must correspond with PATH_flags */ /* TODO: add new path flags */ diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h index 44a7945fbe3c..343189903dba 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h @@ -17,8 +17,8 @@ enum path_flags { PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */ PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */ - PATH_DELEGATE_DELETED = 0x08000, /* delegate deleted files */ - PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ + PATH_DELEGATE_DELETED = 0x10000, /* delegate deleted files */ + PATH_MEDIATE_DELETED = 0x20000, /* mediate deleted paths */ }; int aa_path_name(const struct path *path, int flags, char *buffer, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 232d3d9566eb..639b5b248e63 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -48,6 +48,10 @@ extern const char *const aa_profile_mode_names[]; #define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT) +#define CHECK_DEBUG1(_profile) ((_profile)->label.flags & FLAG_DEBUG1) + +#define CHECK_DEBUG2(_profile) ((_profile)->label.flags & FLAG_DEBUG2) + #define profile_is_stale(_profile) (label_is_stale(&(_profile)->label)) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index e0e1ca7ebc38..eb5f7d7f132b 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -28,6 +28,8 @@ void aa_load_ent_free(struct aa_load_ent *ent); struct aa_load_ent *aa_load_ent_alloc(void); #define PACKED_FLAG_HAT 1 +#define PACKED_FLAG_DEBUG1 2 +#define PACKED_FLAG_DEBUG2 4 #define PACKED_MODE_ENFORCE 0 #define PACKED_MODE_COMPLAIN 1 diff --git a/security/apparmor/label.c b/security/apparmor/label.c index a658b67c784c..0f36ee907438 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -197,18 +197,18 @@ static bool vec_is_stale(struct aa_profile **vec, int n) return false; } -static bool vec_unconfined(struct aa_profile **vec, int n) +static long union_vec_flags(struct aa_profile **vec, int n, long mask) { + long u = 0; int i; AA_BUG(!vec); for (i = 0; i < n; i++) { - if (!profile_unconfined(vec[i])) - return false; + u |= vec[i]->label.flags & mask; } - return true; + return u; } static int sort_cmp(const void *a, const void *b) @@ -1097,8 +1097,8 @@ static struct aa_label *label_merge_insert(struct aa_label *new, else if (k == b->size) return aa_get_label(b); } - if (vec_unconfined(new->vec, new->size)) - new->flags |= FLAG_UNCONFINED; + new->flags |= union_vec_flags(new->vec, new->size, FLAG_UNCONFINED | + FLAG_DEBUG1 | FLAG_DEBUG2); ls = labels_set(new); write_lock_irqsave(&ls->lock, flags); label = __label_insert(labels_set(new), new, false); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 302fecf9b197..55d31bac4f35 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -748,6 +748,10 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) goto fail; if (tmp & PACKED_FLAG_HAT) profile->label.flags |= FLAG_HAT; + if (tmp & PACKED_FLAG_DEBUG1) + profile->label.flags |= FLAG_DEBUG1; + if (tmp & PACKED_FLAG_DEBUG2) + profile->label.flags |= FLAG_DEBUG2; if (!unpack_u32(e, &tmp, NULL)) goto fail; if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) { From f567e7fada03d4c9c5f646a439ad2356371c4147 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 25 Mar 2022 05:20:02 -0700 Subject: [PATCH 31/34] apparmor: extend policydb permission set by making use of the xbits The policydb permission set has left the xbits unused. Make them available for mediation. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 1 + security/apparmor/include/file.h | 3 +++ security/apparmor/lib.c | 25 +++++++++++++++++++++---- security/apparmor/mount.c | 1 - 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 0275a350dc23..d5838249cda5 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2334,6 +2334,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = { AA_SFS_FILE_BOOLEAN("v6", 1), AA_SFS_FILE_BOOLEAN("v7", 1), AA_SFS_FILE_BOOLEAN("v8", 1), + AA_SFS_FILE_BOOLEAN("v9", 1), { } }; diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 7517605a183d..029cb20e322d 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -142,6 +142,7 @@ static inline u16 dfa_map_xindex(u16 mask) */ #define dfa_user_allow(dfa, state) (((ACCEPT_TABLE(dfa)[state]) & 0x7f) | \ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) +#define dfa_user_xbits(dfa, state) (((ACCEPT_TABLE(dfa)[state]) >> 7) & 0x7f) #define dfa_user_audit(dfa, state) ((ACCEPT_TABLE2(dfa)[state]) & 0x7f) #define dfa_user_quiet(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 7) & 0x7f) #define dfa_user_xindex(dfa, state) \ @@ -150,6 +151,8 @@ static inline u16 dfa_map_xindex(u16 mask) #define dfa_other_allow(dfa, state) ((((ACCEPT_TABLE(dfa)[state]) >> 14) & \ 0x7f) | \ ((ACCEPT_TABLE(dfa)[state]) & 0x80000000)) +#define dfa_other_xbits(dfa, state) \ + ((((ACCEPT_TABLE(dfa)[state]) >> 7) >> 14) & 0x7f) #define dfa_other_audit(dfa, state) (((ACCEPT_TABLE2(dfa)[state]) >> 14) & 0x7f) #define dfa_other_quiet(dfa, state) \ ((((ACCEPT_TABLE2(dfa)[state]) >> 7) >> 14) & 0x7f) diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 5eda003c0d45..1c72a61108d3 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -322,22 +322,39 @@ static u32 map_other(u32 x) ((x & 0x60) << 19); /* SETOPT/GETOPT */ } +static u32 map_xbits(u32 x) +{ + return ((x & 0x1) << 7) | + ((x & 0x7e) << 9); +} + void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, struct aa_perms *perms) { + /* This mapping is convulated due to history. + * v1-v4: only file perms + * v5: added policydb which dropped in perm user conditional to + * gain new perm bits, but had to map around the xbits because + * the userspace compiler was still munging them. + * v9: adds using the xbits in policydb because the compiler now + * supports treating policydb permission bits different. + * Unfortunately there is not way to force auditing on the + * perms represented by the xbits + */ *perms = (struct aa_perms) { - .allow = dfa_user_allow(dfa, state), + .allow = dfa_user_allow(dfa, state) | + map_xbits(dfa_user_xbits(dfa, state)), .audit = dfa_user_audit(dfa, state), - .quiet = dfa_user_quiet(dfa, state), + .quiet = dfa_user_quiet(dfa, state) | + map_xbits(dfa_other_xbits(dfa, state)), }; - /* for v5 perm mapping in the policydb, the other set is used + /* for v5-v9 perm mapping in the policydb, the other set is used * to extend the general perm set */ perms->allow |= map_other(dfa_other_allow(dfa, state)); perms->audit |= map_other(dfa_other_audit(dfa, state)); perms->quiet |= map_other(dfa_other_quiet(dfa, state)); -// perms->xindex = dfa_user_xindex(dfa, state); } /** diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index fa64a2db3aec..f61247241803 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -217,7 +217,6 @@ static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa, .allow = dfa_user_allow(dfa, state), .audit = dfa_user_audit(dfa, state), .quiet = dfa_user_quiet(dfa, state), - .xindex = dfa_user_xindex(dfa, state), }; return perms; From eac931254d99c5aeb12ace02366dd338c4371164 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 22 Nov 2021 23:28:32 -0800 Subject: [PATCH 32/34] apparmor: move ptrace mediation to more logical task.{h,c} AppArmor split out task oriented controls to their own logical file a while ago. Ptrace mediation is better grouped with task than ipc, so move it. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 1 + security/apparmor/include/ipc.h | 18 ----- security/apparmor/include/task.h | 18 +++++ security/apparmor/ipc.c | 110 ----------------------------- security/apparmor/task.c | 114 +++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 128 deletions(-) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d5838249cda5..d066ccc219e2 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -36,6 +36,7 @@ #include "include/policy_ns.h" #include "include/resource.h" #include "include/policy_unpack.h" +#include "include/task.h" /* * The apparmor filesystem interface used for policy load and introspection diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h index 9cafd80f7731..a1ac6ffb95e9 100644 --- a/security/apparmor/include/ipc.h +++ b/security/apparmor/include/ipc.h @@ -13,24 +13,6 @@ #include -struct aa_profile; - -#define AA_PTRACE_TRACE MAY_WRITE -#define AA_PTRACE_READ MAY_READ -#define AA_MAY_BE_TRACED AA_MAY_APPEND -#define AA_MAY_BE_READ AA_MAY_CREATE -#define PTRACE_PERM_SHIFT 2 - -#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \ - AA_MAY_BE_READ | AA_MAY_BE_TRACED) -#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE) - -#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \ - "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \ - "xcpu xfsz vtalrm prof winch io pwr sys emt lost" - -int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, - u32 request); int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig); #endif /* __AA_IPC_H */ diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h index f13d12373b25..13437d62c70f 100644 --- a/security/apparmor/include/task.h +++ b/security/apparmor/include/task.h @@ -77,4 +77,22 @@ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) ctx->token = 0; } +#define AA_PTRACE_TRACE MAY_WRITE +#define AA_PTRACE_READ MAY_READ +#define AA_MAY_BE_TRACED AA_MAY_APPEND +#define AA_MAY_BE_READ AA_MAY_CREATE +#define PTRACE_PERM_SHIFT 2 + +#define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \ + AA_MAY_BE_READ | AA_MAY_BE_TRACED) +#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE) + +#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \ + "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \ + "xcpu xfsz vtalrm prof winch io pwr sys emt lost" + +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, + u32 request); + + #endif /* __AA_TASK_H */ diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index fe36d112aad9..3dbbc59d440d 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -9,7 +9,6 @@ */ #include -#include #include "include/audit.h" #include "include/capability.h" @@ -18,115 +17,6 @@ #include "include/ipc.h" #include "include/sig_names.h" -/** - * audit_ptrace_mask - convert mask to permission string - * @mask: permission mask to convert - * - * Returns: pointer to static string - */ -static const char *audit_ptrace_mask(u32 mask) -{ - switch (mask) { - case MAY_READ: - return "read"; - case MAY_WRITE: - return "trace"; - case AA_MAY_BE_READ: - return "readby"; - case AA_MAY_BE_TRACED: - return "tracedby"; - } - return ""; -} - -/* call back to audit ptrace fields */ -static void audit_ptrace_cb(struct audit_buffer *ab, void *va) -{ - struct common_audit_data *sa = va; - - if (aad(sa)->request & AA_PTRACE_PERM_MASK) { - audit_log_format(ab, " requested_mask=\"%s\"", - audit_ptrace_mask(aad(sa)->request)); - - if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { - audit_log_format(ab, " denied_mask=\"%s\"", - audit_ptrace_mask(aad(sa)->denied)); - } - } - audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, - FLAGS_NONE, GFP_ATOMIC); -} - -/* assumes check for PROFILE_MEDIATES is already done */ -/* TODO: conditionals */ -static int profile_ptrace_perm(struct aa_profile *profile, - struct aa_label *peer, u32 request, - struct common_audit_data *sa) -{ - struct aa_perms perms = { }; - - aad(sa)->peer = peer; - aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, - &perms); - aa_apply_modes_to_perms(profile, &perms); - return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); -} - -static int profile_tracee_perm(struct aa_profile *tracee, - struct aa_label *tracer, u32 request, - struct common_audit_data *sa) -{ - if (profile_unconfined(tracee) || unconfined(tracer) || - !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) - return 0; - - return profile_ptrace_perm(tracee, tracer, request, sa); -} - -static int profile_tracer_perm(struct aa_profile *tracer, - struct aa_label *tracee, u32 request, - struct common_audit_data *sa) -{ - if (profile_unconfined(tracer)) - return 0; - - if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) - return profile_ptrace_perm(tracer, tracee, request, sa); - - /* profile uses the old style capability check for ptrace */ - if (&tracer->label == tracee) - return 0; - - aad(sa)->label = &tracer->label; - aad(sa)->peer = tracee; - aad(sa)->request = 0; - aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, - CAP_OPT_NONE); - - return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); -} - -/** - * aa_may_ptrace - test if tracer task can trace the tracee - * @tracer: label of the task doing the tracing (NOT NULL) - * @tracee: task label to be traced - * @request: permission request - * - * Returns: %0 else error code if permission denied or error - */ -int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, - u32 request) -{ - struct aa_profile *profile; - u32 xrequest = request << PTRACE_PERM_SHIFT; - DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); - - return xcheck_labels(tracer, tracee, profile, - profile_tracer_perm(profile, tracee, request, &sa), - profile_tracee_perm(profile, tracer, xrequest, &sa)); -} - static inline int map_signal_num(int sig) { diff --git a/security/apparmor/task.c b/security/apparmor/task.c index d17130ee6795..503dc0877fb1 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -12,7 +12,12 @@ * should return to the previous cred if it has not been modified. */ +#include +#include + +#include "include/audit.h" #include "include/cred.h" +#include "include/policy.h" #include "include/task.h" /** @@ -177,3 +182,112 @@ int aa_restore_previous_label(u64 token) return 0; } + +/** + * audit_ptrace_mask - convert mask to permission string + * @mask: permission mask to convert + * + * Returns: pointer to static string + */ +static const char *audit_ptrace_mask(u32 mask) +{ + switch (mask) { + case MAY_READ: + return "read"; + case MAY_WRITE: + return "trace"; + case AA_MAY_BE_READ: + return "readby"; + case AA_MAY_BE_TRACED: + return "tracedby"; + } + return ""; +} + +/* call back to audit ptrace fields */ +static void audit_ptrace_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + if (aad(sa)->request & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " requested_mask=\"%s\"", + audit_ptrace_mask(aad(sa)->request)); + + if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { + audit_log_format(ab, " denied_mask=\"%s\"", + audit_ptrace_mask(aad(sa)->denied)); + } + } + audit_log_format(ab, " peer="); + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, + FLAGS_NONE, GFP_ATOMIC); +} + +/* assumes check for PROFILE_MEDIATES is already done */ +/* TODO: conditionals */ +static int profile_ptrace_perm(struct aa_profile *profile, + struct aa_label *peer, u32 request, + struct common_audit_data *sa) +{ + struct aa_perms perms = { }; + + aad(sa)->peer = peer; + aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, + &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); +} + +static int profile_tracee_perm(struct aa_profile *tracee, + struct aa_label *tracer, u32 request, + struct common_audit_data *sa) +{ + if (profile_unconfined(tracee) || unconfined(tracer) || + !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) + return 0; + + return profile_ptrace_perm(tracee, tracer, request, sa); +} + +static int profile_tracer_perm(struct aa_profile *tracer, + struct aa_label *tracee, u32 request, + struct common_audit_data *sa) +{ + if (profile_unconfined(tracer)) + return 0; + + if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) + return profile_ptrace_perm(tracer, tracee, request, sa); + + /* profile uses the old style capability check for ptrace */ + if (&tracer->label == tracee) + return 0; + + aad(sa)->label = &tracer->label; + aad(sa)->peer = tracee; + aad(sa)->request = 0; + aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, + CAP_OPT_NONE); + + return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); +} + +/** + * aa_may_ptrace - test if tracer task can trace the tracee + * @tracer: label of the task doing the tracing (NOT NULL) + * @tracee: task label to be traced + * @request: permission request + * + * Returns: %0 else error code if permission denied or error + */ +int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, + u32 request) +{ + struct aa_profile *profile; + u32 xrequest = request << PTRACE_PERM_SHIFT; + DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); + + return xcheck_labels(tracer, tracee, profile, + profile_tracer_perm(profile, tracee, request, &sa), + profile_tracee_perm(profile, tracer, xrequest, &sa)); +} From 79eb2711c919e6db10ed2b8fb22ab605121e80ea Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 20 Jul 2022 14:04:43 +0200 Subject: [PATCH 33/34] apparmor: correct config reference to intended one Commit 5bfcbd22ee4e ("apparmor: Enable tuning of policy paranoid load for embedded systems") introduces the config SECURITY_APPARMOR_PARANOID_LOAD, but then refers in the code to SECURITY_PARANOID_LOAD; note the missing APPARMOR in the middle. Correct this to the introduced and intended config option. Fixes: 5bfcbd22ee4e ("apparmor: Enable tuning of policy paranoid load for embedded systems") Signed-off-by: Lukas Bulwahn Signed-off-by: John Johansen --- security/apparmor/lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 090a20805664..e29cade7b662 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1402,7 +1402,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); * DEPRECATED: read only as strict checking of load is always done now * that none root users (user namespaces) can load policy. */ -bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_PARANOID_LOAD); +bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD); module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); static int param_get_aaintbool(char *buffer, const struct kernel_param *kp); From c269fca7b37a08b7eec6f6b79a0abf1d0a245acb Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sat, 6 Aug 2022 12:07:07 -0700 Subject: [PATCH 34/34] apparmor: Update MAINTAINERS file with new email address Add the apparmor.net email address that the project is transitioning emails to. Signed-off-by: John Johansen --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 3935e63a1801..9a2fb3ab9c80 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1370,6 +1370,7 @@ F: include/uapi/linux/apm_bios.h APPARMOR SECURITY MODULE M: John Johansen +M: John Johansen L: apparmor@lists.ubuntu.com (moderated for non-subscribers) S: Supported W: apparmor.net