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 /security | |
| 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
...
Diffstat (limited to 'security')
| -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 |
14 files changed, 310 insertions, 71 deletions
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 | } |
