1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AppArmor security module 4 * 5 * This file contains AppArmor security identifier (secid) manipulation fns 6 * 7 * Copyright 2009-2017 Canonical Ltd. 8 * 9 * AppArmor allocates a unique secid for every label used. If a label 10 * is replaced it receives the secid of the label it is replacing. 11 */ 12 13 #include <linux/errno.h> 14 #include <linux/err.h> 15 #include <linux/gfp.h> 16 #include <linux/idr.h> 17 #include <linux/slab.h> 18 #include <linux/spinlock.h> 19 20 #include "include/cred.h" 21 #include "include/lib.h" 22 #include "include/secid.h" 23 #include "include/label.h" 24 #include "include/policy_ns.h" 25 26 /* 27 * secids - do not pin labels with a refcount. They rely on the label 28 * properly updating/freeing them 29 */ 30 #define AA_FIRST_SECID 2 31 32 static DEFINE_IDR(aa_secids); 33 static DEFINE_SPINLOCK(secid_lock); 34 35 /* 36 * TODO: allow policy to reserve a secid range? 37 * TODO: add secid pinning 38 * TODO: use secid_update in label replace 39 */ 40 41 /** 42 * aa_secid_update - update a secid mapping to a new label 43 * @secid: secid to update 44 * @label: label the secid will now map to 45 */ 46 void aa_secid_update(u32 secid, struct aa_label *label) 47 { 48 unsigned long flags; 49 50 spin_lock_irqsave(&secid_lock, flags); 51 idr_replace(&aa_secids, label, secid); 52 spin_unlock_irqrestore(&secid_lock, flags); 53 } 54 55 /** 56 * 57 * see label for inverse aa_label_to_secid 58 */ 59 struct aa_label *aa_secid_to_label(u32 secid) 60 { 61 struct aa_label *label; 62 63 rcu_read_lock(); 64 label = idr_find(&aa_secids, secid); 65 rcu_read_unlock(); 66 67 return label; 68 } 69 70 int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 71 { 72 /* TODO: cache secctx and ref count so we don't have to recreate */ 73 struct aa_label *label = aa_secid_to_label(secid); 74 int len; 75 76 AA_BUG(!seclen); 77 78 if (!label) 79 return -EINVAL; 80 81 if (secdata) 82 len = aa_label_asxprint(secdata, root_ns, label, 83 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 84 FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT, 85 GFP_ATOMIC); 86 else 87 len = aa_label_snxprint(NULL, 0, root_ns, label, 88 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 89 FLAG_HIDDEN_UNCONFINED | FLAG_ABS_ROOT); 90 if (len < 0) 91 return -ENOMEM; 92 93 *seclen = len; 94 95 return 0; 96 } 97 98 int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) 99 { 100 struct aa_label *label; 101 102 label = aa_label_strn_parse(&root_ns->unconfined->label, secdata, 103 seclen, GFP_KERNEL, false, false); 104 if (IS_ERR(label)) 105 return PTR_ERR(label); 106 *secid = label->secid; 107 108 return 0; 109 } 110 111 void apparmor_release_secctx(char *secdata, u32 seclen) 112 { 113 kfree(secdata); 114 } 115 116 /** 117 * aa_alloc_secid - allocate a new secid for a profile 118 * @label: the label to allocate a secid for 119 * @gfp: memory allocation flags 120 * 121 * Returns: 0 with @label->secid initialized 122 * <0 returns error with @label->secid set to AA_SECID_INVALID 123 */ 124 int aa_alloc_secid(struct aa_label *label, gfp_t gfp) 125 { 126 unsigned long flags; 127 int ret; 128 129 idr_preload(gfp); 130 spin_lock_irqsave(&secid_lock, flags); 131 ret = idr_alloc(&aa_secids, label, AA_FIRST_SECID, 0, GFP_ATOMIC); 132 spin_unlock_irqrestore(&secid_lock, flags); 133 idr_preload_end(); 134 135 if (ret < 0) { 136 label->secid = AA_SECID_INVALID; 137 return ret; 138 } 139 140 AA_BUG(ret == AA_SECID_INVALID); 141 label->secid = ret; 142 return 0; 143 } 144 145 /** 146 * aa_free_secid - free a secid 147 * @secid: secid to free 148 */ 149 void aa_free_secid(u32 secid) 150 { 151 unsigned long flags; 152 153 spin_lock_irqsave(&secid_lock, flags); 154 idr_remove(&aa_secids, secid); 155 spin_unlock_irqrestore(&secid_lock, flags); 156 } 157 158 void aa_secids_init(void) 159 { 160 idr_init_base(&aa_secids, AA_FIRST_SECID); 161 } 162