]>
Commit | Line | Data |
---|---|---|
c3701be9 DM |
1 | From 1b5e29dcf1c18938e62e23f24e9a19c01b861561 Mon Sep 17 00:00:00 2001 |
2 | From: John Johansen <john.johansen@canonical.com> | |
3 | Date: Thu, 22 Jul 2010 02:32:02 -0700 | |
4 | Subject: [PATCH 1/4] UBUNTU: SAUCE: AppArmor: Add profile introspection file | |
5 | to interface | |
6 | ||
7 | Add the dynamic profiles file to the interace, to allow load policy | |
8 | introspection. | |
9 | ||
10 | Signed-off-by: John Johansen <john.johansen@canonical.com> | |
11 | Acked-by: Kees Cook <kees@ubuntu.com> | |
12 | --- | |
13 | security/apparmor/Kconfig | 9 ++ | |
14 | security/apparmor/apparmorfs.c | 231 +++++++++++++++++++++++++++++++++++++++++ | |
15 | 2 files changed, 240 insertions(+) | |
16 | ||
17 | diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig | |
18 | index 9b9013b..51ebf96 100644 | |
19 | --- a/security/apparmor/Kconfig | |
20 | +++ b/security/apparmor/Kconfig | |
21 | @@ -29,3 +29,12 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE | |
22 | boot. | |
23 | ||
24 | If you are unsure how to answer this question, answer 1. | |
25 | + | |
26 | +config SECURITY_APPARMOR_COMPAT_24 | |
27 | + bool "Enable AppArmor 2.4 compatability" | |
28 | + depends on SECURITY_APPARMOR | |
29 | + default y | |
30 | + help | |
31 | + This option enables compatability with AppArmor 2.4. It is | |
32 | + recommended if compatability with older versions of AppArmor | |
33 | + is desired. | |
34 | diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c | |
35 | index 16c15ec..42b7c9f 100644 | |
36 | --- a/security/apparmor/apparmorfs.c | |
37 | +++ b/security/apparmor/apparmorfs.c | |
38 | @@ -182,6 +182,234 @@ const struct file_operations aa_fs_seq_file_ops = { | |
39 | .release = single_release, | |
40 | }; | |
41 | ||
42 | +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 | |
43 | +/** | |
44 | + * __next_namespace - find the next namespace to list | |
45 | + * @root: root namespace to stop search at (NOT NULL) | |
46 | + * @ns: current ns position (NOT NULL) | |
47 | + * | |
48 | + * Find the next namespace from @ns under @root and handle all locking needed | |
49 | + * while switching current namespace. | |
50 | + * | |
51 | + * Returns: next namespace or NULL if at last namespace under @root | |
52 | + * NOTE: will not unlock root->lock | |
53 | + */ | |
54 | +static struct aa_namespace *__next_namespace(struct aa_namespace *root, | |
55 | + struct aa_namespace *ns) | |
56 | +{ | |
57 | + struct aa_namespace *parent; | |
58 | + | |
59 | + /* is next namespace a child */ | |
60 | + if (!list_empty(&ns->sub_ns)) { | |
61 | + struct aa_namespace *next; | |
62 | + next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); | |
63 | + read_lock(&next->lock); | |
64 | + return next; | |
65 | + } | |
66 | + | |
67 | + /* check if the next ns is a sibling, parent, gp, .. */ | |
68 | + parent = ns->parent; | |
69 | + while (parent) { | |
70 | + read_unlock(&ns->lock); | |
71 | + list_for_each_entry_continue(ns, &parent->sub_ns, base.list) { | |
72 | + read_lock(&ns->lock); | |
73 | + return ns; | |
74 | + } | |
75 | + if (parent == root) | |
76 | + return NULL; | |
77 | + ns = parent; | |
78 | + parent = parent->parent; | |
79 | + } | |
80 | + | |
81 | + return NULL; | |
82 | +} | |
83 | + | |
84 | +/** | |
85 | + * __first_profile - find the first profile in a namespace | |
86 | + * @root: namespace that is root of profiles being displayed (NOT NULL) | |
87 | + * @ns: namespace to start in (NOT NULL) | |
88 | + * | |
89 | + * Returns: unrefcounted profile or NULL if no profile | |
90 | + */ | |
91 | +static struct aa_profile *__first_profile(struct aa_namespace *root, | |
92 | + struct aa_namespace *ns) | |
93 | +{ | |
94 | + for ( ; ns; ns = __next_namespace(root, ns)) { | |
95 | + if (!list_empty(&ns->base.profiles)) | |
96 | + return list_first_entry(&ns->base.profiles, | |
97 | + struct aa_profile, base.list); | |
98 | + } | |
99 | + return NULL; | |
100 | +} | |
101 | + | |
102 | +/** | |
103 | + * __next_profile - step to the next profile in a profile tree | |
104 | + * @profile: current profile in tree (NOT NULL) | |
105 | + * | |
106 | + * Perform a depth first taversal on the profile tree in a namespace | |
107 | + * | |
108 | + * Returns: next profile or NULL if done | |
109 | + * Requires: profile->ns.lock to be held | |
110 | + */ | |
111 | +static struct aa_profile *__next_profile(struct aa_profile *p) | |
112 | +{ | |
113 | + struct aa_profile *parent; | |
114 | + struct aa_namespace *ns = p->ns; | |
115 | + | |
116 | + /* is next profile a child */ | |
117 | + if (!list_empty(&p->base.profiles)) | |
118 | + return list_first_entry(&p->base.profiles, typeof(*p), | |
119 | + base.list); | |
120 | + | |
121 | + /* is next profile a sibling, parent sibling, gp, subling, .. */ | |
122 | + parent = p->parent; | |
123 | + while (parent) { | |
124 | + list_for_each_entry_continue(p, &parent->base.profiles, | |
125 | + base.list) | |
126 | + return p; | |
127 | + p = parent; | |
128 | + parent = parent->parent; | |
129 | + } | |
130 | + | |
131 | + /* is next another profile in the namespace */ | |
132 | + list_for_each_entry_continue(p, &ns->base.profiles, base.list) | |
133 | + return p; | |
134 | + | |
135 | + return NULL; | |
136 | +} | |
137 | + | |
138 | +/** | |
139 | + * next_profile - step to the next profile in where ever it may be | |
140 | + * @root: root namespace (NOT NULL) | |
141 | + * @profile: current profile (NOT NULL) | |
142 | + * | |
143 | + * Returns: next profile or NULL if there isn't one | |
144 | + */ | |
145 | +static struct aa_profile *next_profile(struct aa_namespace *root, | |
146 | + struct aa_profile *profile) | |
147 | +{ | |
148 | + struct aa_profile *next = __next_profile(profile); | |
149 | + if (next) | |
150 | + return next; | |
151 | + | |
152 | + /* finished all profiles in namespace move to next namespace */ | |
153 | + return __first_profile(root, __next_namespace(root, profile->ns)); | |
154 | +} | |
155 | + | |
156 | +/** | |
157 | + * p_start - start a depth first traversal of profile tree | |
158 | + * @f: seq_file to fill | |
159 | + * @pos: current position | |
160 | + * | |
161 | + * Returns: first profile under current namespace or NULL if none found | |
162 | + * | |
163 | + * acquires first ns->lock | |
164 | + */ | |
165 | +static void *p_start(struct seq_file *f, loff_t *pos) | |
166 | + __acquires(root->lock) | |
167 | +{ | |
168 | + struct aa_profile *profile = NULL; | |
169 | + struct aa_namespace *root = aa_current_profile()->ns; | |
170 | + loff_t l = *pos; | |
171 | + f->private = aa_get_namespace(root); | |
172 | + | |
173 | + | |
174 | + /* find the first profile */ | |
175 | + read_lock(&root->lock); | |
176 | + profile = __first_profile(root, root); | |
177 | + | |
178 | + /* skip to position */ | |
179 | + for (; profile && l > 0; l--) | |
180 | + profile = next_profile(root, profile); | |
181 | + | |
182 | + return profile; | |
183 | +} | |
184 | + | |
185 | +/** | |
186 | + * p_next - read the next profile entry | |
187 | + * @f: seq_file to fill | |
188 | + * @p: profile previously returned | |
189 | + * @pos: current position | |
190 | + * | |
191 | + * Returns: next profile after @p or NULL if none | |
192 | + * | |
193 | + * may acquire/release locks in namespace tree as necessary | |
194 | + */ | |
195 | +static void *p_next(struct seq_file *f, void *p, loff_t *pos) | |
196 | +{ | |
197 | + struct aa_profile *profile = p; | |
198 | + struct aa_namespace *root = f->private; | |
199 | + (*pos)++; | |
200 | + | |
201 | + return next_profile(root, profile); | |
202 | +} | |
203 | + | |
204 | +/** | |
205 | + * p_stop - stop depth first traversal | |
206 | + * @f: seq_file we are filling | |
207 | + * @p: the last profile writen | |
208 | + * | |
209 | + * Release all locking done by p_start/p_next on namespace tree | |
210 | + */ | |
211 | +static void p_stop(struct seq_file *f, void *p) | |
212 | + __releases(root->lock) | |
213 | +{ | |
214 | + struct aa_profile *profile = p; | |
215 | + struct aa_namespace *root = f->private, *ns; | |
216 | + | |
217 | + if (profile) { | |
218 | + for (ns = profile->ns; ns && ns != root; ns = ns->parent) | |
219 | + read_unlock(&ns->lock); | |
220 | + } | |
221 | + read_unlock(&root->lock); | |
222 | + aa_put_namespace(root); | |
223 | +} | |
224 | + | |
225 | +/** | |
226 | + * seq_show_profile - show a profile entry | |
227 | + * @f: seq_file to file | |
228 | + * @p: current position (profile) (NOT NULL) | |
229 | + * | |
230 | + * Returns: error on failure | |
231 | + */ | |
232 | +static int seq_show_profile(struct seq_file *f, void *p) | |
233 | +{ | |
234 | + struct aa_profile *profile = (struct aa_profile *)p; | |
235 | + struct aa_namespace *root = f->private; | |
236 | + | |
237 | + if (profile->ns != root) | |
238 | + seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); | |
239 | + seq_printf(f, "%s (%s)\n", profile->base.hname, | |
240 | + COMPLAIN_MODE(profile) ? "complain" : "enforce"); | |
241 | + | |
242 | + return 0; | |
243 | +} | |
244 | + | |
245 | +static const struct seq_operations aa_fs_profiles_op = { | |
246 | + .start = p_start, | |
247 | + .next = p_next, | |
248 | + .stop = p_stop, | |
249 | + .show = seq_show_profile, | |
250 | +}; | |
251 | + | |
252 | +static int profiles_open(struct inode *inode, struct file *file) | |
253 | +{ | |
254 | + return seq_open(file, &aa_fs_profiles_op); | |
255 | +} | |
256 | + | |
257 | +static int profiles_release(struct inode *inode, struct file *file) | |
258 | +{ | |
259 | + return seq_release(inode, file); | |
260 | +} | |
261 | + | |
262 | +const struct file_operations aa_fs_profiles_fops = { | |
263 | + .open = profiles_open, | |
264 | + .read = seq_read, | |
265 | + .llseek = seq_lseek, | |
266 | + .release = profiles_release, | |
267 | +}; | |
268 | +#endif /* CONFIG_SECURITY_APPARMOR_COMPAT_24 */ | |
269 | + | |
270 | /** Base file system setup **/ | |
271 | ||
272 | static struct aa_fs_entry aa_fs_entry_file[] = { | |
273 | @@ -210,6 +438,9 @@ static struct aa_fs_entry aa_fs_entry_apparmor[] = { | |
274 | AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), | |
275 | AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), | |
276 | AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), | |
277 | +#ifdef CONFIG_SECURITY_APPARMOR_COMPAT_24 | |
278 | + AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops), | |
279 | +#endif | |
280 | AA_FS_DIR("features", aa_fs_entry_features), | |
281 | { } | |
282 | }; | |
283 | -- | |
284 | 1.8.3.2 | |
285 |