diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-14 03:11:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-06-14 03:11:28 -0400 |
commit | 463f202172c31b9c36278001cabfbad4e12da42e (patch) | |
tree | 2e19e74001db3f5bc5012b90781435add1de4311 | |
parent | 050e9baa9dc9fbd9ce2b27f0056990fc9e0a08a0 (diff) | |
parent | 338d0be437ef10e247a35aed83dbab182cf406a2 (diff) |
Merge tag 'apparmor-pr-2018-06-13' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull AppArmor updates from John Johansen:
"Features
- add support for mapping secids and using secctxes
- add the ability to get a task's secid
- add support for audit rule filtering
Cleanups:
- multiple typo fixes
- Convert to use match_string() helper
- update git and wiki locations in AppArmor docs
- improve get_buffers macro by using get_cpu_ptr
- Use an IDR to allocate apparmor secids
Bug fixes:
- fix '*seclen' is never less than zero
- fix mediation of prlimit
- fix memory leak when deduping profile load
- fix ptrace read check
- fix memory leak of rule on error exit path"
* tag 'apparmor-pr-2018-06-13' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (21 commits)
apparmor: fix ptrace read check
apparmor: fix memory leak when deduping profile load
apparmor: fix mediation of prlimit
apparmor: fixup secid map conversion to using IDR
apparmor: Use an IDR to allocate apparmor secids
apparmor: Fix memory leak of rule on error exit path
apparmor: modify audit rule support to support profile stacks
apparmor: Add support for audit rule filtering
apparmor: update git and wiki locations in AppArmor docs
apparmor: Convert to use match_string() helper
apparmor: improve get_buffers macro by using get_cpu_ptr
apparmor: fix '*seclen' is never less than zero
apparmor: fix typo "preconfinement"
apparmor: fix typo "independent"
apparmor: fix typo "traverse"
apparmor: fix typo "type"
apparmor: fix typo "replace"
apparmor: fix typo "comparison"
apparmor: fix typo "loosen"
apparmor: add the ability to get a task's secid
...
-rw-r--r-- | Documentation/admin-guide/LSM/apparmor.rst | 6 | ||||
-rw-r--r-- | security/apparmor/audit.c | 90 | ||||
-rw-r--r-- | security/apparmor/domain.c | 2 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 6 | ||||
-rw-r--r-- | security/apparmor/include/label.h | 2 | ||||
-rw-r--r-- | security/apparmor/include/path.h | 33 | ||||
-rw-r--r-- | security/apparmor/include/secid.h | 17 | ||||
-rw-r--r-- | security/apparmor/label.c | 15 | ||||
-rw-r--r-- | security/apparmor/lib.c | 2 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 50 | ||||
-rw-r--r-- | security/apparmor/match.c | 2 | ||||
-rw-r--r-- | security/apparmor/mount.c | 2 | ||||
-rw-r--r-- | security/apparmor/policy.c | 7 | ||||
-rw-r--r-- | security/apparmor/resource.c | 2 | ||||
-rw-r--r-- | security/apparmor/secid.c | 151 |
15 files changed, 313 insertions, 74 deletions
diff --git a/Documentation/admin-guide/LSM/apparmor.rst b/Documentation/admin-guide/LSM/apparmor.rst index 3e9734bd0e05..6cf81bbd7ce8 100644 --- a/Documentation/admin-guide/LSM/apparmor.rst +++ b/Documentation/admin-guide/LSM/apparmor.rst | |||
@@ -44,8 +44,8 @@ Links | |||
44 | 44 | ||
45 | Mailing List - apparmor@lists.ubuntu.com | 45 | Mailing List - apparmor@lists.ubuntu.com |
46 | 46 | ||
47 | Wiki - http://apparmor.wiki.kernel.org/ | 47 | Wiki - http://wiki.apparmor.net |
48 | 48 | ||
49 | User space tools - https://launchpad.net/apparmor | 49 | User space tools - https://gitlab.com/apparmor |
50 | 50 | ||
51 | Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git | 51 | Kernel module - git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor |
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 8f9ecac7f8de..eeaddfe0c0fb 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "include/audit.h" | 19 | #include "include/audit.h" |
20 | #include "include/policy.h" | 20 | #include "include/policy.h" |
21 | #include "include/policy_ns.h" | 21 | #include "include/policy_ns.h" |
22 | 22 | #include "include/secid.h" | |
23 | 23 | ||
24 | const char *const audit_mode_names[] = { | 24 | const char *const audit_mode_names[] = { |
25 | "normal", | 25 | "normal", |
@@ -163,3 +163,91 @@ int aa_audit(int type, struct aa_profile *profile, struct common_audit_data *sa, | |||
163 | 163 | ||
164 | return aad(sa)->error; | 164 | return aad(sa)->error; |
165 | } | 165 | } |
166 | |||
167 | struct aa_audit_rule { | ||
168 | struct aa_label *label; | ||
169 | }; | ||
170 | |||
171 | void aa_audit_rule_free(void *vrule) | ||
172 | { | ||
173 | struct aa_audit_rule *rule = vrule; | ||
174 | |||
175 | if (rule) { | ||
176 | if (!IS_ERR(rule->label)) | ||
177 | aa_put_label(rule->label); | ||
178 | kfree(rule); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) | ||
183 | { | ||
184 | struct aa_audit_rule *rule; | ||
185 | |||
186 | switch (field) { | ||
187 | case AUDIT_SUBJ_ROLE: | ||
188 | if (op != Audit_equal && op != Audit_not_equal) | ||
189 | return -EINVAL; | ||
190 | break; | ||
191 | default: | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | rule = kzalloc(sizeof(struct aa_audit_rule), GFP_KERNEL); | ||
196 | |||
197 | if (!rule) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | /* Currently rules are treated as coming from the root ns */ | ||
201 | rule->label = aa_label_parse(&root_ns->unconfined->label, rulestr, | ||
202 | GFP_KERNEL, true, false); | ||
203 | if (IS_ERR(rule->label)) { | ||
204 | aa_audit_rule_free(rule); | ||
205 | return PTR_ERR(rule->label); | ||
206 | } | ||
207 | |||
208 | *vrule = rule; | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int aa_audit_rule_known(struct audit_krule *rule) | ||
213 | { | ||
214 | int i; | ||
215 | |||
216 | for (i = 0; i < rule->field_count; i++) { | ||
217 | struct audit_field *f = &rule->fields[i]; | ||
218 | |||
219 | switch (f->type) { | ||
220 | case AUDIT_SUBJ_ROLE: | ||
221 | return 1; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | ||
229 | struct audit_context *actx) | ||
230 | { | ||
231 | struct aa_audit_rule *rule = vrule; | ||
232 | struct aa_label *label; | ||
233 | int found = 0; | ||
234 | |||
235 | label = aa_secid_to_label(sid); | ||
236 | |||
237 | if (!label) | ||
238 | return -ENOENT; | ||
239 | |||
240 | if (aa_label_is_subset(label, rule->label)) | ||
241 | found = 1; | ||
242 | |||
243 | switch (field) { | ||
244 | case AUDIT_SUBJ_ROLE: | ||
245 | switch (op) { | ||
246 | case Audit_equal: | ||
247 | return found; | ||
248 | case Audit_not_equal: | ||
249 | return !found; | ||
250 | } | ||
251 | } | ||
252 | return 0; | ||
253 | } | ||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 590b7e8cd21c..098d546d8253 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -839,7 +839,7 @@ static struct aa_label *handle_onexec(struct aa_label *label, | |||
839 | cond, unsafe)); | 839 | cond, unsafe)); |
840 | 840 | ||
841 | } else { | 841 | } else { |
842 | /* TODO: determine how much we want to losen this */ | 842 | /* TODO: determine how much we want to loosen this */ |
843 | error = fn_for_each_in_ns(label, profile, | 843 | error = fn_for_each_in_ns(label, profile, |
844 | profile_onexec(profile, onexec, stack, bprm, | 844 | profile_onexec(profile, onexec, stack, bprm, |
845 | buffer, cond, unsafe)); | 845 | buffer, cond, unsafe)); |
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 9c9be9c98c15..b8c8b1066b0a 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h | |||
@@ -189,4 +189,10 @@ static inline int complain_error(int error) | |||
189 | return error; | 189 | return error; |
190 | } | 190 | } |
191 | 191 | ||
192 | void aa_audit_rule_free(void *vrule); | ||
193 | int aa_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule); | ||
194 | int aa_audit_rule_known(struct audit_krule *rule); | ||
195 | int aa_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, | ||
196 | struct audit_context *actx); | ||
197 | |||
192 | #endif /* __AA_AUDIT_H */ | 198 | #endif /* __AA_AUDIT_H */ |
diff --git a/security/apparmor/include/label.h b/security/apparmor/include/label.h index d871e7ff0952..7ce5fe73ae7f 100644 --- a/security/apparmor/include/label.h +++ b/security/apparmor/include/label.h | |||
@@ -281,7 +281,7 @@ void __aa_labelset_update_subtree(struct aa_ns *ns); | |||
281 | 281 | ||
282 | void aa_label_free(struct aa_label *label); | 282 | void aa_label_free(struct aa_label *label); |
283 | void aa_label_kref(struct kref *kref); | 283 | void aa_label_kref(struct kref *kref); |
284 | bool aa_label_init(struct aa_label *label, int size); | 284 | bool aa_label_init(struct aa_label *label, int size, gfp_t gfp); |
285 | struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp); | 285 | struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp); |
286 | 286 | ||
287 | bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub); | 287 | bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub); |
diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h index e042b994f2b8..b6380c5f0097 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h | |||
@@ -43,10 +43,11 @@ struct aa_buffers { | |||
43 | 43 | ||
44 | DECLARE_PER_CPU(struct aa_buffers, aa_buffers); | 44 | DECLARE_PER_CPU(struct aa_buffers, aa_buffers); |
45 | 45 | ||
46 | #define ASSIGN(FN, X, N) ((X) = FN(N)) | 46 | #define ASSIGN(FN, A, X, N) ((X) = FN(A, N)) |
47 | #define EVAL1(FN, X) ASSIGN(FN, X, 0) /*X = FN(0)*/ | 47 | #define EVAL1(FN, A, X) ASSIGN(FN, A, X, 0) /*X = FN(0)*/ |
48 | #define EVAL2(FN, X, Y...) do { ASSIGN(FN, X, 1); EVAL1(FN, Y); } while (0) | 48 | #define EVAL2(FN, A, X, Y...) \ |
49 | #define EVAL(FN, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, X) | 49 | do { ASSIGN(FN, A, X, 1); EVAL1(FN, A, Y); } while (0) |
50 | #define EVAL(FN, A, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, A, X) | ||
50 | 51 | ||
51 | #define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++) | 52 | #define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++) |
52 | 53 | ||
@@ -56,26 +57,24 @@ DECLARE_PER_CPU(struct aa_buffers, aa_buffers); | |||
56 | #define AA_BUG_PREEMPT_ENABLED(X) /* nop */ | 57 | #define AA_BUG_PREEMPT_ENABLED(X) /* nop */ |
57 | #endif | 58 | #endif |
58 | 59 | ||
59 | #define __get_buffer(N) ({ \ | 60 | #define __get_buffer(C, N) ({ \ |
60 | struct aa_buffers *__cpu_var; \ | ||
61 | AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled"); \ | 61 | AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled"); \ |
62 | __cpu_var = this_cpu_ptr(&aa_buffers); \ | 62 | (C)->buf[(N)]; }) |
63 | __cpu_var->buf[(N)]; }) | ||
64 | 63 | ||
65 | #define __get_buffers(X...) EVAL(__get_buffer, X) | 64 | #define __get_buffers(C, X...) EVAL(__get_buffer, C, X) |
66 | 65 | ||
67 | #define __put_buffers(X, Y...) ((void)&(X)) | 66 | #define __put_buffers(X, Y...) ((void)&(X)) |
68 | 67 | ||
69 | #define get_buffers(X...) \ | 68 | #define get_buffers(X...) \ |
70 | do { \ | 69 | do { \ |
71 | preempt_disable(); \ | 70 | struct aa_buffers *__cpu_var = get_cpu_ptr(&aa_buffers); \ |
72 | __get_buffers(X); \ | 71 | __get_buffers(__cpu_var, X); \ |
73 | } while (0) | 72 | } while (0) |
74 | 73 | ||
75 | #define put_buffers(X, Y...) \ | 74 | #define put_buffers(X, Y...) \ |
76 | do { \ | 75 | do { \ |
77 | __put_buffers(X, Y); \ | 76 | __put_buffers(X, Y); \ |
78 | preempt_enable(); \ | 77 | put_cpu_ptr(&aa_buffers); \ |
79 | } while (0) | 78 | } while (0) |
80 | 79 | ||
81 | #endif /* __AA_PATH_H */ | 80 | #endif /* __AA_PATH_H */ |
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index 95ed86a0f1e2..dee6fa3b6081 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains AppArmor security identifier (secid) definitions | 4 | * This file contains AppArmor security identifier (secid) definitions |
5 | * | 5 | * |
6 | * Copyright 2009-2010 Canonical Ltd. | 6 | * Copyright 2009-2018 Canonical Ltd. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License as | 9 | * modify it under the terms of the GNU General Public License as |
@@ -14,13 +14,24 @@ | |||
14 | #ifndef __AA_SECID_H | 14 | #ifndef __AA_SECID_H |
15 | #define __AA_SECID_H | 15 | #define __AA_SECID_H |
16 | 16 | ||
17 | #include <linux/slab.h> | ||
17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
18 | 19 | ||
20 | struct aa_label; | ||
21 | |||
19 | /* secid value that will not be allocated */ | 22 | /* secid value that will not be allocated */ |
20 | #define AA_SECID_INVALID 0 | 23 | #define AA_SECID_INVALID 0 |
21 | #define AA_SECID_ALLOC AA_SECID_INVALID | ||
22 | 24 | ||
23 | u32 aa_alloc_secid(void); | 25 | struct aa_label *aa_secid_to_label(u32 secid); |
26 | int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); | ||
27 | int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); | ||
28 | void apparmor_release_secctx(char *secdata, u32 seclen); | ||
29 | |||
30 | |||
31 | int aa_alloc_secid(struct aa_label *label, gfp_t gfp); | ||
24 | void aa_free_secid(u32 secid); | 32 | void aa_free_secid(u32 secid); |
33 | void aa_secid_update(u32 secid, struct aa_label *label); | ||
34 | |||
35 | void aa_secids_init(void); | ||
25 | 36 | ||
26 | #endif /* __AA_SECID_H */ | 37 | #endif /* __AA_SECID_H */ |
diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 523250e34837..ba11bdf9043a 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c | |||
@@ -128,7 +128,7 @@ static int ns_cmp(struct aa_ns *a, struct aa_ns *b) | |||
128 | } | 128 | } |
129 | 129 | ||
130 | /** | 130 | /** |
131 | * profile_cmp - profile comparision for set ordering | 131 | * profile_cmp - profile comparison for set ordering |
132 | * @a: profile to compare (NOT NULL) | 132 | * @a: profile to compare (NOT NULL) |
133 | * @b: profile to compare (NOT NULL) | 133 | * @b: profile to compare (NOT NULL) |
134 | * | 134 | * |
@@ -157,7 +157,7 @@ static int profile_cmp(struct aa_profile *a, struct aa_profile *b) | |||
157 | } | 157 | } |
158 | 158 | ||
159 | /** | 159 | /** |
160 | * vec_cmp - label comparision for set ordering | 160 | * vec_cmp - label comparison for set ordering |
161 | * @a: label to compare (NOT NULL) | 161 | * @a: label to compare (NOT NULL) |
162 | * @vec: vector of profiles to compare (NOT NULL) | 162 | * @vec: vector of profiles to compare (NOT NULL) |
163 | * @n: length of @vec | 163 | * @n: length of @vec |
@@ -402,13 +402,12 @@ static void label_free_or_put_new(struct aa_label *label, struct aa_label *new) | |||
402 | aa_put_label(new); | 402 | aa_put_label(new); |
403 | } | 403 | } |
404 | 404 | ||
405 | bool aa_label_init(struct aa_label *label, int size) | 405 | bool aa_label_init(struct aa_label *label, int size, gfp_t gfp) |
406 | { | 406 | { |
407 | AA_BUG(!label); | 407 | AA_BUG(!label); |
408 | AA_BUG(size < 1); | 408 | AA_BUG(size < 1); |
409 | 409 | ||
410 | label->secid = aa_alloc_secid(); | 410 | if (aa_alloc_secid(label, gfp) < 0) |
411 | if (label->secid == AA_SECID_INVALID) | ||
412 | return false; | 411 | return false; |
413 | 412 | ||
414 | label->size = size; /* doesn't include null */ | 413 | label->size = size; /* doesn't include null */ |
@@ -441,7 +440,7 @@ struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp) | |||
441 | if (!new) | 440 | if (!new) |
442 | goto fail; | 441 | goto fail; |
443 | 442 | ||
444 | if (!aa_label_init(new, size)) | 443 | if (!aa_label_init(new, size, gfp)) |
445 | goto fail; | 444 | goto fail; |
446 | 445 | ||
447 | if (!proxy) { | 446 | if (!proxy) { |
@@ -463,7 +462,7 @@ fail: | |||
463 | 462 | ||
464 | 463 | ||
465 | /** | 464 | /** |
466 | * label_cmp - label comparision for set ordering | 465 | * label_cmp - label comparison for set ordering |
467 | * @a: label to compare (NOT NULL) | 466 | * @a: label to compare (NOT NULL) |
468 | * @b: label to compare (NOT NULL) | 467 | * @b: label to compare (NOT NULL) |
469 | * | 468 | * |
@@ -2011,7 +2010,7 @@ out: | |||
2011 | 2010 | ||
2012 | /** | 2011 | /** |
2013 | * __label_update - insert updated version of @label into labelset | 2012 | * __label_update - insert updated version of @label into labelset |
2014 | * @label - the label to update/repace | 2013 | * @label - the label to update/replace |
2015 | * | 2014 | * |
2016 | * Returns: new label that is up to date | 2015 | * Returns: new label that is up to date |
2017 | * else NULL on failure | 2016 | * else NULL on failure |
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 068a9f471f77..a7b3f681b80e 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c | |||
@@ -408,7 +408,7 @@ int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, | |||
408 | * @request: requested perms | 408 | * @request: requested perms |
409 | * @deny: Returns: explicit deny set | 409 | * @deny: Returns: explicit deny set |
410 | * @sa: initialized audit structure (MAY BE NULL if not auditing) | 410 | * @sa: initialized audit structure (MAY BE NULL if not auditing) |
411 | * @cb: callback fn for tpye specific fields (MAY BE NULL) | 411 | * @cb: callback fn for type specific fields (MAY BE NULL) |
412 | * | 412 | * |
413 | * Returns: 0 if permission else error code | 413 | * Returns: 0 if permission else error code |
414 | * | 414 | * |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index ce2b89e9ad94..74f17376202b 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "include/policy_ns.h" | 39 | #include "include/policy_ns.h" |
40 | #include "include/procattr.h" | 40 | #include "include/procattr.h" |
41 | #include "include/mount.h" | 41 | #include "include/mount.h" |
42 | #include "include/secid.h" | ||
42 | 43 | ||
43 | /* Flag indicating whether initialization completed */ | 44 | /* Flag indicating whether initialization completed */ |
44 | int apparmor_initialized; | 45 | int apparmor_initialized; |
@@ -116,7 +117,8 @@ static int apparmor_ptrace_access_check(struct task_struct *child, | |||
116 | tracer = begin_current_label_crit_section(); | 117 | tracer = begin_current_label_crit_section(); |
117 | tracee = aa_get_task_label(child); | 118 | tracee = aa_get_task_label(child); |
118 | error = aa_may_ptrace(tracer, tracee, | 119 | error = aa_may_ptrace(tracer, tracee, |
119 | mode == PTRACE_MODE_READ ? AA_PTRACE_READ : AA_PTRACE_TRACE); | 120 | (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ |
121 | : AA_PTRACE_TRACE); | ||
120 | aa_put_label(tracee); | 122 | aa_put_label(tracee); |
121 | end_current_label_crit_section(tracer); | 123 | end_current_label_crit_section(tracer); |
122 | 124 | ||
@@ -710,6 +712,13 @@ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) | |||
710 | return; | 712 | return; |
711 | } | 713 | } |
712 | 714 | ||
715 | static void apparmor_task_getsecid(struct task_struct *p, u32 *secid) | ||
716 | { | ||
717 | struct aa_label *label = aa_get_task_label(p); | ||
718 | *secid = label->secid; | ||
719 | aa_put_label(label); | ||
720 | } | ||
721 | |||
713 | static int apparmor_task_setrlimit(struct task_struct *task, | 722 | static int apparmor_task_setrlimit(struct task_struct *task, |
714 | unsigned int resource, struct rlimit *new_rlim) | 723 | unsigned int resource, struct rlimit *new_rlim) |
715 | { | 724 | { |
@@ -1186,8 +1195,20 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |||
1186 | 1195 | ||
1187 | LSM_HOOK_INIT(task_free, apparmor_task_free), | 1196 | LSM_HOOK_INIT(task_free, apparmor_task_free), |
1188 | LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), | 1197 | LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), |
1198 | LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid), | ||
1189 | LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), | 1199 | LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), |
1190 | LSM_HOOK_INIT(task_kill, apparmor_task_kill), | 1200 | LSM_HOOK_INIT(task_kill, apparmor_task_kill), |
1201 | |||
1202 | #ifdef CONFIG_AUDIT | ||
1203 | LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init), | ||
1204 | LSM_HOOK_INIT(audit_rule_known, aa_audit_rule_known), | ||
1205 | LSM_HOOK_INIT(audit_rule_match, aa_audit_rule_match), | ||
1206 | LSM_HOOK_INIT(audit_rule_free, aa_audit_rule_free), | ||
1207 | #endif | ||
1208 | |||
1209 | LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx), | ||
1210 | LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid), | ||
1211 | LSM_HOOK_INIT(release_secctx, apparmor_release_secctx), | ||
1191 | }; | 1212 | }; |
1192 | 1213 | ||
1193 | /* | 1214 | /* |
@@ -1378,14 +1399,12 @@ static int param_set_audit(const char *val, const struct kernel_param *kp) | |||
1378 | if (apparmor_initialized && !policy_admin_capable(NULL)) | 1399 | if (apparmor_initialized && !policy_admin_capable(NULL)) |
1379 | return -EPERM; | 1400 | return -EPERM; |
1380 | 1401 | ||
1381 | for (i = 0; i < AUDIT_MAX_INDEX; i++) { | 1402 | i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val); |
1382 | if (strcmp(val, audit_mode_names[i]) == 0) { | 1403 | if (i < 0) |
1383 | aa_g_audit = i; | 1404 | return -EINVAL; |
1384 | return 0; | ||
1385 | } | ||
1386 | } | ||
1387 | 1405 | ||
1388 | return -EINVAL; | 1406 | aa_g_audit = i; |
1407 | return 0; | ||
1389 | } | 1408 | } |
1390 | 1409 | ||
1391 | static int param_get_mode(char *buffer, const struct kernel_param *kp) | 1410 | static int param_get_mode(char *buffer, const struct kernel_param *kp) |
@@ -1409,14 +1428,13 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) | |||
1409 | if (apparmor_initialized && !policy_admin_capable(NULL)) | 1428 | if (apparmor_initialized && !policy_admin_capable(NULL)) |
1410 | return -EPERM; | 1429 | return -EPERM; |
1411 | 1430 | ||
1412 | for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) { | 1431 | i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX, |
1413 | if (strcmp(val, aa_profile_mode_names[i]) == 0) { | 1432 | val); |
1414 | aa_g_profile_mode = i; | 1433 | if (i < 0) |
1415 | return 0; | 1434 | return -EINVAL; |
1416 | } | ||
1417 | } | ||
1418 | 1435 | ||
1419 | return -EINVAL; | 1436 | aa_g_profile_mode = i; |
1437 | return 0; | ||
1420 | } | 1438 | } |
1421 | 1439 | ||
1422 | /* | 1440 | /* |
@@ -1530,6 +1548,8 @@ static int __init apparmor_init(void) | |||
1530 | return 0; | 1548 | return 0; |
1531 | } | 1549 | } |
1532 | 1550 | ||
1551 | aa_secids_init(); | ||
1552 | |||
1533 | error = aa_setup_dfa_engine(); | 1553 | error = aa_setup_dfa_engine(); |
1534 | if (error) { | 1554 | if (error) { |
1535 | AA_ERROR("Unable to setup dfa engine\n"); | 1555 | AA_ERROR("Unable to setup dfa engine\n"); |
diff --git a/security/apparmor/match.c b/security/apparmor/match.c index 280eba082c7b..55f2ee505a01 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c | |||
@@ -472,7 +472,7 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, | |||
472 | 472 | ||
473 | /** | 473 | /** |
474 | * aa_dfa_next - step one character to the next state in the dfa | 474 | * aa_dfa_next - step one character to the next state in the dfa |
475 | * @dfa: the dfa to tranverse (NOT NULL) | 475 | * @dfa: the dfa to traverse (NOT NULL) |
476 | * @state: the state to start in | 476 | * @state: the state to start in |
477 | * @c: the input character to transition on | 477 | * @c: the input character to transition on |
478 | * | 478 | * |
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 6e8c7ac0b33d..c1da22482bfb 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c | |||
@@ -121,7 +121,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) | |||
121 | * @src_name: src_name of object being mediated (MAYBE_NULL) | 121 | * @src_name: src_name of object being mediated (MAYBE_NULL) |
122 | * @type: type of filesystem (MAYBE_NULL) | 122 | * @type: type of filesystem (MAYBE_NULL) |
123 | * @trans: name of trans (MAYBE NULL) | 123 | * @trans: name of trans (MAYBE NULL) |
124 | * @flags: filesystem idependent mount flags | 124 | * @flags: filesystem independent mount flags |
125 | * @data: filesystem mount flags | 125 | * @data: filesystem mount flags |
126 | * @request: permissions requested | 126 | * @request: permissions requested |
127 | * @perms: the permissions computed for the request (NOT NULL) | 127 | * @perms: the permissions computed for the request (NOT NULL) |
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index c07493ce2376..1590e2de4e84 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -268,7 +268,7 @@ struct aa_profile *aa_alloc_profile(const char *hname, struct aa_proxy *proxy, | |||
268 | 268 | ||
269 | if (!aa_policy_init(&profile->base, NULL, hname, gfp)) | 269 | if (!aa_policy_init(&profile->base, NULL, hname, gfp)) |
270 | goto fail; | 270 | goto fail; |
271 | if (!aa_label_init(&profile->label, 1)) | 271 | if (!aa_label_init(&profile->label, 1, gfp)) |
272 | goto fail; | 272 | goto fail; |
273 | 273 | ||
274 | /* update being set needed by fs interface */ | 274 | /* update being set needed by fs interface */ |
@@ -1008,6 +1008,9 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, | |||
1008 | audit_policy(label, op, ns_name, ent->new->base.hname, | 1008 | audit_policy(label, op, ns_name, ent->new->base.hname, |
1009 | "same as current profile, skipping", | 1009 | "same as current profile, skipping", |
1010 | error); | 1010 | error); |
1011 | /* break refcount cycle with proxy. */ | ||
1012 | aa_put_proxy(ent->new->label.proxy); | ||
1013 | ent->new->label.proxy = NULL; | ||
1011 | goto skip; | 1014 | goto skip; |
1012 | } | 1015 | } |
1013 | 1016 | ||
@@ -1085,7 +1088,7 @@ fail: | |||
1085 | * Remove a profile or sub namespace from the current namespace, so that | 1088 | * Remove a profile or sub namespace from the current namespace, so that |
1086 | * they can not be found anymore and mark them as replaced by unconfined | 1089 | * they can not be found anymore and mark them as replaced by unconfined |
1087 | * | 1090 | * |
1088 | * NOTE: removing confinement does not restore rlimits to preconfinemnet values | 1091 | * NOTE: removing confinement does not restore rlimits to preconfinement values |
1089 | * | 1092 | * |
1090 | * Returns: size of data consume else error code if fails | 1093 | * Returns: size of data consume else error code if fails |
1091 | */ | 1094 | */ |
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index d022137143b9..95fd26d09757 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c | |||
@@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, | |||
124 | */ | 124 | */ |
125 | 125 | ||
126 | if (label != peer && | 126 | if (label != peer && |
127 | !aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT)) | 127 | aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0) |
128 | error = fn_for_each(label, profile, | 128 | error = fn_for_each(label, profile, |
129 | audit_resource(profile, resource, | 129 | audit_resource(profile, resource, |
130 | new_rlim->rlim_max, peer, | 130 | new_rlim->rlim_max, peer, |
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index 3a3edbad0b21..f2f22d00db18 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains AppArmor security identifier (secid) manipulation fns | 4 | * This file contains AppArmor security identifier (secid) manipulation fns |
5 | * | 5 | * |
6 | * Copyright 2009-2010 Canonical Ltd. | 6 | * Copyright 2009-2017 Canonical Ltd. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU General Public License as | 9 | * modify it under the terms of the GNU General Public License as |
@@ -11,38 +11,142 @@ | |||
11 | * License. | 11 | * License. |
12 | * | 12 | * |
13 | * | 13 | * |
14 | * AppArmor allocates a unique secid for every profile loaded. If a profile | 14 | * AppArmor allocates a unique secid for every label used. If a label |
15 | * is replaced it receives the secid of the profile it is replacing. | 15 | * is replaced it receives the secid of the label it is replacing. |
16 | * | ||
17 | * The secid value of 0 is invalid. | ||
18 | */ | 16 | */ |
19 | 17 | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
22 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/gfp.h> | ||
21 | #include <linux/idr.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spinlock.h> | ||
23 | 24 | ||
25 | #include "include/cred.h" | ||
26 | #include "include/lib.h" | ||
24 | #include "include/secid.h" | 27 | #include "include/secid.h" |
28 | #include "include/label.h" | ||
29 | #include "include/policy_ns.h" | ||
30 | |||
31 | /* | ||
32 | * secids - do not pin labels with a refcount. They rely on the label | ||
33 | * properly updating/freeing them | ||
34 | */ | ||
25 | 35 | ||
26 | /* global counter from which secids are allocated */ | 36 | #define AA_FIRST_SECID 1 |
27 | static u32 global_secid; | 37 | |
38 | static DEFINE_IDR(aa_secids); | ||
28 | static DEFINE_SPINLOCK(secid_lock); | 39 | static DEFINE_SPINLOCK(secid_lock); |
29 | 40 | ||
30 | /* TODO FIXME: add secid to profile mapping, and secid recycling */ | 41 | /* |
42 | * TODO: allow policy to reserve a secid range? | ||
43 | * TODO: add secid pinning | ||
44 | * TODO: use secid_update in label replace | ||
45 | */ | ||
46 | |||
47 | /** | ||
48 | * aa_secid_update - update a secid mapping to a new label | ||
49 | * @secid: secid to update | ||
50 | * @label: label the secid will now map to | ||
51 | */ | ||
52 | void aa_secid_update(u32 secid, struct aa_label *label) | ||
53 | { | ||
54 | unsigned long flags; | ||
55 | |||
56 | spin_lock_irqsave(&secid_lock, flags); | ||
57 | idr_replace(&aa_secids, label, secid); | ||
58 | spin_unlock_irqrestore(&secid_lock, flags); | ||
59 | } | ||
60 | |||
61 | /** | ||
62 | * | ||
63 | * see label for inverse aa_label_to_secid | ||
64 | */ | ||
65 | struct aa_label *aa_secid_to_label(u32 secid) | ||
66 | { | ||
67 | struct aa_label *label; | ||
68 | |||
69 | rcu_read_lock(); | ||
70 | label = idr_find(&aa_secids, secid); | ||
71 | rcu_read_unlock(); | ||
72 | |||
73 | return label; | ||
74 | } | ||
75 | |||
76 | int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) | ||
77 | { | ||
78 | /* TODO: cache secctx and ref count so we don't have to recreate */ | ||
79 | struct aa_label *label = aa_secid_to_label(secid); | ||
80 | int len; | ||
81 | |||
82 | AA_BUG(!secdata); | ||
83 | AA_BUG(!seclen); | ||
84 | |||
85 | if (!label) | ||
86 | return -EINVAL; | ||
87 | |||
88 | if (secdata) | ||
89 | len = aa_label_asxprint(secdata, root_ns, label, | ||
90 | FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | | ||
91 | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT, | ||
92 | GFP_ATOMIC); | ||
93 | else | ||
94 | len = aa_label_snxprint(NULL, 0, root_ns, label, | ||
95 | FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | | ||
96 | FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT); | ||
97 | if (len < 0) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | *seclen = len; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) | ||
106 | { | ||
107 | struct aa_label *label; | ||
108 | |||
109 | label = aa_label_strn_parse(&root_ns->unconfined->label, secdata, | ||
110 | seclen, GFP_KERNEL, false, false); | ||
111 | if (IS_ERR(label)) | ||
112 | return PTR_ERR(label); | ||
113 | *secid = label->secid; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | void apparmor_release_secctx(char *secdata, u32 seclen) | ||
119 | { | ||
120 | kfree(secdata); | ||
121 | } | ||
31 | 122 | ||
32 | /** | 123 | /** |
33 | * aa_alloc_secid - allocate a new secid for a profile | 124 | * aa_alloc_secid - allocate a new secid for a profile |
125 | * @label: the label to allocate a secid for | ||
126 | * @gfp: memory allocation flags | ||
127 | * | ||
128 | * Returns: 0 with @label->secid initialized | ||
129 | * <0 returns error with @label->secid set to AA_SECID_INVALID | ||
34 | */ | 130 | */ |
35 | u32 aa_alloc_secid(void) | 131 | int aa_alloc_secid(struct aa_label *label, gfp_t gfp) |
36 | { | 132 | { |
37 | u32 secid; | 133 | unsigned long flags; |
134 | int ret; | ||
135 | |||
136 | idr_preload(gfp); | ||
137 | spin_lock_irqsave(&secid_lock, flags); | ||
138 | ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC); | ||
139 | spin_unlock_irqrestore(&secid_lock, flags); | ||
140 | idr_preload_end(); | ||
38 | 141 | ||
39 | /* | 142 | if (ret < 0) { |
40 | * TODO FIXME: secid recycling - part of profile mapping table | 143 | label->secid = AA_SECID_INVALID; |
41 | */ | 144 | return ret; |
42 | spin_lock(&secid_lock); | 145 | } |
43 | secid = (++global_secid); | 146 | |
44 | spin_unlock(&secid_lock); | 147 | AA_BUG(ret == AA_SECID_INVALID); |
45 | return secid; | 148 | label->secid = ret; |
149 | return 0; | ||
46 | } | 150 | } |
47 | 151 | ||
48 | /** | 152 | /** |
@@ -51,5 +155,14 @@ u32 aa_alloc_secid(void) | |||
51 | */ | 155 | */ |
52 | void aa_free_secid(u32 secid) | 156 | void aa_free_secid(u32 secid) |
53 | { | 157 | { |
54 | ; /* NOP ATM */ | 158 | unsigned long flags; |
159 | |||
160 | spin_lock_irqsave(&secid_lock, flags); | ||
161 | idr_remove(&aa_secids, secid); | ||
162 | spin_unlock_irqrestore(&secid_lock, flags); | ||
163 | } | ||
164 | |||
165 | void aa_secids_init(void) | ||
166 | { | ||
167 | idr_init_base(&aa_secids, AA_FIRST_SECID); | ||
55 | } | 168 | } |