Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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
...

+313 -74
+3 -3
Documentation/admin-guide/LSM/apparmor.rst
··· 44 44 45 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
+89 -1
security/apparmor/audit.c
··· 19 19 #include "include/audit.h" 20 20 #include "include/policy.h" 21 21 #include "include/policy_ns.h" 22 - 22 + #include "include/secid.h" 23 23 24 24 const char *const audit_mode_names[] = { 25 25 "normal", ··· 162 162 return complain_error(aad(sa)->error); 163 163 164 164 return aad(sa)->error; 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; 165 253 }
+1 -1
security/apparmor/domain.c
··· 839 839 cond, unsafe)); 840 840 841 841 } else { 842 - /* TODO: determine how much we want to losen this */ 842 + /* TODO: determine how much we want to loosen this */ 843 843 error = fn_for_each_in_ns(label, profile, 844 844 profile_onexec(profile, onexec, stack, bprm, 845 845 buffer, cond, unsafe));
+6
security/apparmor/include/audit.h
··· 189 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 198 #endif /* __AA_AUDIT_H */
+1 -1
security/apparmor/include/label.h
··· 281 281 282 282 void aa_label_free(struct aa_label *label); 283 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 285 struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp); 286 286 287 287 bool aa_label_is_subset(struct aa_label *set, struct aa_label *sub);
+16 -17
security/apparmor/include/path.h
··· 43 43 44 44 DECLARE_PER_CPU(struct aa_buffers, aa_buffers); 45 45 46 - #define ASSIGN(FN, X, N) ((X) = FN(N)) 47 - #define EVAL1(FN, X) ASSIGN(FN, X, 0) /*X = FN(0)*/ 48 - #define EVAL2(FN, X, Y...) do { ASSIGN(FN, X, 1); EVAL1(FN, Y); } while (0) 49 - #define EVAL(FN, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, X) 46 + #define ASSIGN(FN, A, X, N) ((X) = FN(A, N)) 47 + #define EVAL1(FN, A, X) ASSIGN(FN, A, X, 0) /*X = FN(0)*/ 48 + #define EVAL2(FN, A, X, Y...) \ 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 52 #define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++) 52 53 ··· 57 56 #define AA_BUG_PREEMPT_ENABLED(X) /* nop */ 58 57 #endif 59 58 60 - #define __get_buffer(N) ({ \ 61 - struct aa_buffers *__cpu_var; \ 59 + #define __get_buffer(C, N) ({ \ 62 60 AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled"); \ 63 - __cpu_var = this_cpu_ptr(&aa_buffers); \ 64 - __cpu_var->buf[(N)]; }) 61 + (C)->buf[(N)]; }) 65 62 66 - #define __get_buffers(X...) EVAL(__get_buffer, X) 63 + #define __get_buffers(C, X...) EVAL(__get_buffer, C, X) 67 64 68 65 #define __put_buffers(X, Y...) ((void)&(X)) 69 66 70 - #define get_buffers(X...) \ 71 - do { \ 72 - preempt_disable(); \ 73 - __get_buffers(X); \ 67 + #define get_buffers(X...) \ 68 + do { \ 69 + struct aa_buffers *__cpu_var = get_cpu_ptr(&aa_buffers); \ 70 + __get_buffers(__cpu_var, X); \ 74 71 } while (0) 75 72 76 - #define put_buffers(X, Y...) \ 77 - do { \ 78 - __put_buffers(X, Y); \ 79 - preempt_enable(); \ 73 + #define put_buffers(X, Y...) \ 74 + do { \ 75 + __put_buffers(X, Y); \ 76 + put_cpu_ptr(&aa_buffers); \ 80 77 } while (0) 81 78 82 79 #endif /* __AA_PATH_H */
+14 -3
security/apparmor/include/secid.h
··· 3 3 * 4 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 8 * This program is free software; you can redistribute it and/or 9 9 * modify it under the terms of the GNU General Public License as ··· 14 14 #ifndef __AA_SECID_H 15 15 #define __AA_SECID_H 16 16 17 + #include <linux/slab.h> 17 18 #include <linux/types.h> 19 + 20 + struct aa_label; 18 21 19 22 /* secid value that will not be allocated */ 20 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 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 37 #endif /* __AA_SECID_H */
+7 -8
security/apparmor/label.c
··· 128 128 } 129 129 130 130 /** 131 - * profile_cmp - profile comparision for set ordering 131 + * profile_cmp - profile comparison for set ordering 132 132 * @a: profile to compare (NOT NULL) 133 133 * @b: profile to compare (NOT NULL) 134 134 * ··· 157 157 } 158 158 159 159 /** 160 - * vec_cmp - label comparision for set ordering 160 + * vec_cmp - label comparison for set ordering 161 161 * @a: label to compare (NOT NULL) 162 162 * @vec: vector of profiles to compare (NOT NULL) 163 163 * @n: length of @vec ··· 402 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 407 AA_BUG(!label); 408 408 AA_BUG(size < 1); 409 409 410 - label->secid = aa_alloc_secid(); 411 - if (label->secid == AA_SECID_INVALID) 410 + if (aa_alloc_secid(label, gfp) < 0) 412 411 return false; 413 412 414 413 label->size = size; /* doesn't include null */ ··· 440 441 if (!new) 441 442 goto fail; 442 443 443 - if (!aa_label_init(new, size)) 444 + if (!aa_label_init(new, size, gfp)) 444 445 goto fail; 445 446 446 447 if (!proxy) { ··· 462 463 463 464 464 465 /** 465 - * label_cmp - label comparision for set ordering 466 + * label_cmp - label comparison for set ordering 466 467 * @a: label to compare (NOT NULL) 467 468 * @b: label to compare (NOT NULL) 468 469 * ··· 2010 2011 2011 2012 /** 2012 2013 * __label_update - insert updated version of @label into labelset 2013 - * @label - the label to update/repace 2014 + * @label - the label to update/replace 2014 2015 * 2015 2016 * Returns: new label that is up to date 2016 2017 * else NULL on failure
+1 -1
security/apparmor/lib.c
··· 408 408 * @request: requested perms 409 409 * @deny: Returns: explicit deny set 410 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 413 * Returns: 0 if permission else error code 414 414 *
+35 -15
security/apparmor/lsm.c
··· 39 39 #include "include/policy_ns.h" 40 40 #include "include/procattr.h" 41 41 #include "include/mount.h" 42 + #include "include/secid.h" 42 43 43 44 /* Flag indicating whether initialization completed */ 44 45 int apparmor_initialized; ··· 117 116 tracer = begin_current_label_crit_section(); 118 117 tracee = aa_get_task_label(child); 119 118 error = aa_may_ptrace(tracer, tracee, 120 - mode == PTRACE_MODE_READ ? AA_PTRACE_READ : AA_PTRACE_TRACE); 119 + (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ 120 + : AA_PTRACE_TRACE); 121 121 aa_put_label(tracee); 122 122 end_current_label_crit_section(tracer); 123 123 ··· 712 710 return; 713 711 } 714 712 713 + static void apparmor_task_getsecid(struct task_struct *p, u32 *secid) 714 + { 715 + struct aa_label *label = aa_get_task_label(p); 716 + *secid = label->secid; 717 + aa_put_label(label); 718 + } 719 + 715 720 static int apparmor_task_setrlimit(struct task_struct *task, 716 721 unsigned int resource, struct rlimit *new_rlim) 717 722 { ··· 1195 1186 1196 1187 LSM_HOOK_INIT(task_free, apparmor_task_free), 1197 1188 LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), 1189 + LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid), 1198 1190 LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), 1199 1191 LSM_HOOK_INIT(task_kill, apparmor_task_kill), 1192 + 1193 + #ifdef CONFIG_AUDIT 1194 + LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init), 1195 + LSM_HOOK_INIT(audit_rule_known, aa_audit_rule_known), 1196 + LSM_HOOK_INIT(audit_rule_match, aa_audit_rule_match), 1197 + LSM_HOOK_INIT(audit_rule_free, aa_audit_rule_free), 1198 + #endif 1199 + 1200 + LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx), 1201 + LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid), 1202 + LSM_HOOK_INIT(release_secctx, apparmor_release_secctx), 1200 1203 }; 1201 1204 1202 1205 /* ··· 1399 1378 if (apparmor_initialized && !policy_admin_capable(NULL)) 1400 1379 return -EPERM; 1401 1380 1402 - for (i = 0; i < AUDIT_MAX_INDEX; i++) { 1403 - if (strcmp(val, audit_mode_names[i]) == 0) { 1404 - aa_g_audit = i; 1405 - return 0; 1406 - } 1407 - } 1381 + i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val); 1382 + if (i < 0) 1383 + return -EINVAL; 1408 1384 1409 - return -EINVAL; 1385 + aa_g_audit = i; 1386 + return 0; 1410 1387 } 1411 1388 1412 1389 static int param_get_mode(char *buffer, const struct kernel_param *kp) ··· 1428 1409 if (apparmor_initialized && !policy_admin_capable(NULL)) 1429 1410 return -EPERM; 1430 1411 1431 - for (i = 0; i < APPARMOR_MODE_NAMES_MAX_INDEX; i++) { 1432 - if (strcmp(val, aa_profile_mode_names[i]) == 0) { 1433 - aa_g_profile_mode = i; 1434 - return 0; 1435 - } 1436 - } 1412 + i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX, 1413 + val); 1414 + if (i < 0) 1415 + return -EINVAL; 1437 1416 1438 - return -EINVAL; 1417 + aa_g_profile_mode = i; 1418 + return 0; 1439 1419 } 1440 1420 1441 1421 /* ··· 1547 1529 apparmor_enabled = false; 1548 1530 return 0; 1549 1531 } 1532 + 1533 + aa_secids_init(); 1550 1534 1551 1535 error = aa_setup_dfa_engine(); 1552 1536 if (error) {
+1 -1
security/apparmor/match.c
··· 472 472 473 473 /** 474 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 476 * @state: the state to start in 477 477 * @c: the input character to transition on 478 478 *
+1 -1
security/apparmor/mount.c
··· 121 121 * @src_name: src_name of object being mediated (MAYBE_NULL) 122 122 * @type: type of filesystem (MAYBE_NULL) 123 123 * @trans: name of trans (MAYBE NULL) 124 - * @flags: filesystem idependent mount flags 124 + * @flags: filesystem independent mount flags 125 125 * @data: filesystem mount flags 126 126 * @request: permissions requested 127 127 * @perms: the permissions computed for the request (NOT NULL)
+5 -2
security/apparmor/policy.c
··· 268 268 269 269 if (!aa_policy_init(&profile->base, NULL, hname, gfp)) 270 270 goto fail; 271 - if (!aa_label_init(&profile->label, 1)) 271 + if (!aa_label_init(&profile->label, 1, gfp)) 272 272 goto fail; 273 273 274 274 /* update being set needed by fs interface */ ··· 1008 1008 audit_policy(label, op, ns_name, ent->new->base.hname, 1009 1009 "same as current profile, skipping", 1010 1010 error); 1011 + /* break refcount cycle with proxy. */ 1012 + aa_put_proxy(ent->new->label.proxy); 1013 + ent->new->label.proxy = NULL; 1011 1014 goto skip; 1012 1015 } 1013 1016 ··· 1088 1085 * Remove a profile or sub namespace from the current namespace, so that 1089 1086 * they can not be found anymore and mark them as replaced by unconfined 1090 1087 * 1091 - * NOTE: removing confinement does not restore rlimits to preconfinemnet values 1088 + * NOTE: removing confinement does not restore rlimits to preconfinement values 1092 1089 * 1093 1090 * Returns: size of data consume else error code if fails 1094 1091 */
+1 -1
security/apparmor/resource.c
··· 124 124 */ 125 125 126 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 128 error = fn_for_each(label, profile, 129 129 audit_resource(profile, resource, 130 130 new_rlim->rlim_max, peer,
+132 -19
security/apparmor/secid.c
··· 3 3 * 4 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 8 * This program is free software; you can redistribute it and/or 9 9 * modify it under the terms of the GNU General Public License as ··· 11 11 * License. 12 12 * 13 13 * 14 - * AppArmor allocates a unique secid for every profile loaded. If a profile 15 - * is replaced it receives the secid of the profile it is replacing. 16 - * 17 - * The secid value of 0 is invalid. 14 + * AppArmor allocates a unique secid for every label used. If a label 15 + * is replaced it receives the secid of the label it is replacing. 18 16 */ 19 17 20 - #include <linux/spinlock.h> 21 18 #include <linux/errno.h> 22 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 27 #include "include/secid.h" 28 + #include "include/label.h" 29 + #include "include/policy_ns.h" 25 30 26 - /* global counter from which secids are allocated */ 27 - static u32 global_secid; 31 + /* 32 + * secids - do not pin labels with a refcount. They rely on the label 33 + * properly updating/freeing them 34 + */ 35 + 36 + #define AA_FIRST_SECID 1 37 + 38 + static DEFINE_IDR(aa_secids); 28 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 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; 38 135 39 - /* 40 - * TODO FIXME: secid recycling - part of profile mapping table 41 - */ 42 - spin_lock(&secid_lock); 43 - secid = (++global_secid); 44 - spin_unlock(&secid_lock); 45 - return secid; 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(); 141 + 142 + if (ret < 0) { 143 + label->secid = AA_SECID_INVALID; 144 + return ret; 145 + } 146 + 147 + AA_BUG(ret == AA_SECID_INVALID); 148 + label->secid = ret; 149 + return 0; 46 150 } 47 151 48 152 /** ··· 155 51 */ 156 52 void aa_free_secid(u32 secid) 157 53 { 158 - ; /* NOP ATM */ 54 + unsigned long flags; 55 + 56 + spin_lock_irqsave(&secid_lock, flags); 57 + idr_remove(&aa_secids, secid); 58 + spin_unlock_irqrestore(&secid_lock, flags); 59 + } 60 + 61 + void aa_secids_init(void) 62 + { 63 + idr_init_base(&aa_secids, AA_FIRST_SECID); 159 64 }