From 5b9b6926302b41c0d4a3db978d862df50ba5d45e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Arkadiusz=20Mi=C5=9Bkiewicz?= Date: Fri, 15 Sep 2023 17:32:29 +0200 Subject: [PATCH] Backport ability to load apparmor profile hats before main profile is loaded. --- apparmor.patch | 133 +++++++++++++++++++++++++++++++++++++++++++++++++ kernel.spec | 4 +- 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 apparmor.patch diff --git a/apparmor.patch b/apparmor.patch new file mode 100644 index 00000000..9bb9ff38 --- /dev/null +++ b/apparmor.patch @@ -0,0 +1,133 @@ +commit 665b1856dc2399828d8ee07a18d4fd79868e729a +Author: John Johansen +Date: Mon Oct 3 06:06:26 2022 -0700 + + apparmor: Fix loading of child before parent + + Unfortunately it is possible for some userspace's to load children + profiles before the parent profile. This can even happen when the + child and the parent are in different load sets. + + Fix this by creating a null place holder profile that grants no permissions + and can be replaced by the parent once it is loaded. + + Signed-off-by: John Johansen + +diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c +index c17ccedd35f1..66034cf96f4c 100644 +--- a/security/apparmor/policy.c ++++ b/security/apparmor/policy.c +@@ -423,6 +423,57 @@ static struct aa_policy *__lookup_parent(struct aa_ns *ns, + return &profile->base; + } + ++/** ++ * __create_missing_ancestors - create place holders for missing ancestores ++ * @ns: namespace to lookup profile in (NOT NULL) ++ * @hname: hierarchical profile name to find parent of (NOT NULL) ++ * @gfp: type of allocation. ++ * ++ * Returns: NULL on error, parent profile on success ++ * ++ * Requires: ns mutex lock held ++ * ++ * Returns: unrefcounted parent policy or NULL if error creating ++ * place holder profiles. ++ */ ++static struct aa_policy *__create_missing_ancestors(struct aa_ns *ns, ++ const char *hname, ++ gfp_t gfp) ++{ ++ struct aa_policy *policy; ++ struct aa_profile *parent, *profile = NULL; ++ char *split; ++ ++ AA_BUG(!ns); ++ AA_BUG(!hname); ++ ++ policy = &ns->base; ++ ++ for (split = strstr(hname, "//"); split;) { ++ parent = profile; ++ profile = __strn_find_child(&policy->profiles, hname, ++ split - hname); ++ if (!profile) { ++ const char *name = kstrndup(hname, split - hname, ++ gfp); ++ if (!name) ++ return NULL; ++ profile = aa_alloc_null(parent, name, gfp); ++ kfree(name); ++ if (!profile) ++ return NULL; ++ if (!parent) ++ profile->ns = aa_get_ns(ns); ++ } ++ policy = &profile->base; ++ hname = split + 2; ++ split = strstr(hname, "//"); ++ } ++ if (!profile) ++ return &ns->base; ++ return &profile->base; ++} ++ + /** + * __lookupn_profile - lookup the profile matching @hname + * @base: base list to start looking up profile name from (NOT NULL) +@@ -1032,6 +1083,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, + /* setup parent and ns info */ + list_for_each_entry(ent, &lh, list) { + struct aa_policy *policy; ++ struct aa_profile *p; + + if (aa_g_export_binary) + ent->new->rawdata = aa_get_loaddata(udata); +@@ -1056,21 +1108,38 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, + continue; + + /* no ref on policy only use inside lock */ ++ p = NULL; + policy = __lookup_parent(ns, ent->new->base.hname); + if (!policy) { +- struct aa_profile *p; ++ /* first check for parent in the load set */ + p = __list_lookup_parent(&lh, ent->new); + if (!p) { +- error = -ENOENT; +- info = "parent does not exist"; +- goto fail_lock; ++ /* ++ * fill in missing parent with null ++ * profile that doesn't have ++ * permissions. This allows for ++ * individual profile loading where ++ * the child is loaded before the ++ * parent, and outside of the current ++ * atomic set. This unfortunately can ++ * happen with some userspaces. The ++ * null profile will be replaced once ++ * the parent is loaded. ++ */ ++ policy = __create_missing_ancestors(ns, ++ ent->new->base.hname, ++ GFP_KERNEL); ++ if (!policy) { ++ error = -ENOENT; ++ info = "parent does not exist"; ++ goto fail_lock; ++ } + } +- rcu_assign_pointer(ent->new->parent, aa_get_profile(p)); +- } else if (policy != &ns->base) { +- /* released on profile replacement or free_profile */ +- struct aa_profile *p = (struct aa_profile *) policy; +- rcu_assign_pointer(ent->new->parent, aa_get_profile(p)); + } ++ if (!p && policy != &ns->base) ++ /* released on profile replacement or free_profile */ ++ p = (struct aa_profile *) policy; ++ rcu_assign_pointer(ent->new->parent, aa_get_profile(p)); + } + + /* create new fs entries for introspection if needed */ diff --git a/kernel.spec b/kernel.spec index baada061..97dd6cc6 100644 --- a/kernel.spec +++ b/kernel.spec @@ -65,7 +65,7 @@ %define have_pcmcia 0 %endif -%define rel 1 +%define rel 2 %define basever 6.1 %define postver .53 @@ -155,6 +155,7 @@ Patch2: android-enable-building-binder-as-module.patch # http://dev.gentoo.org/~spock/projects/fbcondecor/archive/fbcondecor-0.9.4-2.6.25-rc6.patch Patch3: kernel-fbcondecor.patch Patch6: linux-wistron-nx.patch +Patch7: apparmor.patch # netfilter related stuff mostly based on patch-o-matic-ng # snapshot 20070806 with some fixes. Some modules @@ -615,6 +616,7 @@ cd linux-%{basever} %patch3 -p1 %endif %patch6 -p1 +%patch7 -p1 ## netfilter # -- 2.44.0