]> git.pld-linux.org Git - packages/kernel.git/blob - apparmor.patch
Backport ability to load apparmor profile hats before main profile is loaded.
[packages/kernel.git] / apparmor.patch
1 commit 665b1856dc2399828d8ee07a18d4fd79868e729a
2 Author: John Johansen <john.johansen@canonical.com>
3 Date:   Mon Oct 3 06:06:26 2022 -0700
4
5     apparmor: Fix loading of child before parent
6     
7     Unfortunately it is possible for some userspace's to load children
8     profiles before the parent profile. This can even happen when the
9     child and the parent are in different load sets.
10     
11     Fix this by creating a null place holder profile that grants no permissions
12     and can be replaced by the parent once it is loaded.
13     
14     Signed-off-by: John Johansen <john.johansen@canonical.com>
15
16 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
17 index c17ccedd35f1..66034cf96f4c 100644
18 --- a/security/apparmor/policy.c
19 +++ b/security/apparmor/policy.c
20 @@ -423,6 +423,57 @@ static struct aa_policy *__lookup_parent(struct aa_ns *ns,
21         return &profile->base;
22  }
23  
24 +/**
25 + * __create_missing_ancestors - create place holders for missing ancestores
26 + * @ns: namespace to lookup profile in (NOT NULL)
27 + * @hname: hierarchical profile name to find parent of (NOT NULL)
28 + * @gfp: type of allocation.
29 + *
30 + * Returns: NULL on error, parent profile on success
31 + *
32 + * Requires: ns mutex lock held
33 + *
34 + * Returns: unrefcounted parent policy or NULL if error creating
35 + *          place holder profiles.
36 + */
37 +static struct aa_policy *__create_missing_ancestors(struct aa_ns *ns,
38 +                                                   const char *hname,
39 +                                                   gfp_t gfp)
40 +{
41 +       struct aa_policy *policy;
42 +       struct aa_profile *parent, *profile = NULL;
43 +       char *split;
44 +
45 +       AA_BUG(!ns);
46 +       AA_BUG(!hname);
47 +
48 +       policy = &ns->base;
49 +
50 +       for (split = strstr(hname, "//"); split;) {
51 +               parent = profile;
52 +               profile = __strn_find_child(&policy->profiles, hname,
53 +                                           split - hname);
54 +               if (!profile) {
55 +                       const char *name = kstrndup(hname, split - hname,
56 +                                                   gfp);
57 +                       if (!name)
58 +                               return NULL;
59 +                       profile = aa_alloc_null(parent, name, gfp);
60 +                       kfree(name);
61 +                       if (!profile)
62 +                               return NULL;
63 +                       if (!parent)
64 +                               profile->ns = aa_get_ns(ns);
65 +               }
66 +               policy = &profile->base;
67 +               hname = split + 2;
68 +               split = strstr(hname, "//");
69 +       }
70 +       if (!profile)
71 +               return &ns->base;
72 +       return &profile->base;
73 +}
74 +
75  /**
76   * __lookupn_profile - lookup the profile matching @hname
77   * @base: base list to start looking up profile name from  (NOT NULL)
78 @@ -1032,6 +1083,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
79         /* setup parent and ns info */
80         list_for_each_entry(ent, &lh, list) {
81                 struct aa_policy *policy;
82 +               struct aa_profile *p;
83  
84                 if (aa_g_export_binary)
85                         ent->new->rawdata = aa_get_loaddata(udata);
86 @@ -1056,21 +1108,38 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,
87                         continue;
88  
89                 /* no ref on policy only use inside lock */
90 +               p = NULL;
91                 policy = __lookup_parent(ns, ent->new->base.hname);
92                 if (!policy) {
93 -                       struct aa_profile *p;
94 +                       /* first check for parent in the load set */
95                         p = __list_lookup_parent(&lh, ent->new);
96                         if (!p) {
97 -                               error = -ENOENT;
98 -                               info = "parent does not exist";
99 -                               goto fail_lock;
100 +                               /*
101 +                                * fill in missing parent with null
102 +                                * profile that doesn't have
103 +                                * permissions. This allows for
104 +                                * individual profile loading where
105 +                                * the child is loaded before the
106 +                                * parent, and outside of the current
107 +                                * atomic set. This unfortunately can
108 +                                * happen with some userspaces.  The
109 +                                * null profile will be replaced once
110 +                                * the parent is loaded.
111 +                                */
112 +                               policy = __create_missing_ancestors(ns,
113 +                                                       ent->new->base.hname,
114 +                                                       GFP_KERNEL);
115 +                               if (!policy) {
116 +                                       error = -ENOENT;
117 +                                       info = "parent does not exist";
118 +                                       goto fail_lock;
119 +                               }
120                         }
121 -                       rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
122 -               } else if (policy != &ns->base) {
123 -                       /* released on profile replacement or free_profile */
124 -                       struct aa_profile *p = (struct aa_profile *) policy;
125 -                       rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
126                 }
127 +               if (!p && policy != &ns->base)
128 +                       /* released on profile replacement or free_profile */
129 +                       p = (struct aa_profile *) policy;
130 +               rcu_assign_pointer(ent->new->parent, aa_get_profile(p));
131         }
132  
133         /* create new fs entries for introspection if needed */
This page took 0.039359 seconds and 3 git commands to generate.