1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * AppArmor security module 4 * 5 * This file contains AppArmor contexts used to associate "labels" to objects. 6 * 7 * Copyright (C) 1998-2008 Novell/SUSE 8 * Copyright 2009-2010 Canonical Ltd. 9 */ 10 11 #ifndef __AA_CONTEXT_H 12 #define __AA_CONTEXT_H 13 14 #include <linux/cred.h> 15 #include <linux/slab.h> 16 #include <linux/sched.h> 17 18 #include "label.h" 19 #include "policy_ns.h" 20 #include "task.h" 21 22 static inline struct aa_label *cred_label(const struct cred *cred) 23 { 24 struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; 25 26 AA_BUG(!blob); 27 return *blob; 28 } 29 30 static inline void set_cred_label(const struct cred *cred, 31 struct aa_label *label) 32 { 33 struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; 34 35 AA_BUG(!blob); 36 *blob = label; 37 } 38 39 /** 40 * aa_get_newest_cred_label - obtain the newest label on a cred 41 * @cred: cred to obtain label from (NOT NULL) 42 * 43 * Returns: newest version of confining label 44 */ 45 static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred) 46 { 47 return aa_get_newest_label(cred_label(cred)); 48 } 49 50 static inline struct aa_label *aa_get_newest_cred_label_condref(const struct cred *cred, 51 bool *needput) 52 { 53 struct aa_label *l = cred_label(cred); 54 55 if (unlikely(label_is_stale(l))) { 56 *needput = true; 57 return aa_get_newest_label(l); 58 } 59 60 *needput = false; 61 return l; 62 } 63 64 static inline void aa_put_label_condref(struct aa_label *l, bool needput) 65 { 66 if (unlikely(needput)) 67 aa_put_label(l); 68 } 69 70 /** 71 * aa_current_raw_label - find the current tasks confining label 72 * 73 * Returns: up to date confining label or the ns unconfined label (NOT NULL) 74 * 75 * This fn will not update the tasks cred to the most up to date version 76 * of the label so it is safe to call when inside of locks. 77 */ 78 static inline struct aa_label *aa_current_raw_label(void) 79 { 80 return cred_label(current_cred()); 81 } 82 83 /** 84 * aa_get_current_label - get the newest version of the current tasks label 85 * 86 * Returns: newest version of confining label (NOT NULL) 87 * 88 * This fn will not update the tasks cred, so it is safe inside of locks 89 * 90 * The returned reference must be put with aa_put_label() 91 */ 92 static inline struct aa_label *aa_get_current_label(void) 93 { 94 struct aa_label *l = aa_current_raw_label(); 95 96 if (label_is_stale(l)) 97 return aa_get_newest_label(l); 98 return aa_get_label(l); 99 } 100 101 /** 102 * __end_cred_crit_section - end crit section begun with __begin_... 103 * @label: label obtained from __begin_cred_crit_section 104 * @needput: output: bool set by __begin_cred_crit_section 105 * 106 * While the cred passed to __begin is guaranteed to not change 107 * and the cred and label could be passed here instead of needput 108 * using needput with a local var makes it easier for the compiler 109 * and processor to optimize and speculatively execute the comparison 110 * than chasing a pointer in the cred struct. 111 */ 112 static inline void __end_cred_crit_section(struct aa_label *label, 113 bool needput) 114 { 115 if (unlikely(needput)) 116 aa_put_label(label); 117 } 118 119 /** 120 * __begin_cred_crit_section - @cred's confining label 121 * @cred: current's cred to start a crit section on its label 122 * @needput: store whether the label needs to be put when ending crit section 123 * 124 * Returns: up to date confining label or the ns unconfined label (NOT NULL) 125 * 126 * safe to call inside locks 127 * 128 * The returned reference must be put with __end_cred_crit_section() 129 * This must NOT be used if the task cred could be updated within the 130 * critical section between 131 * __begin_cred_crit_section() .. __end_cred_crit_section() 132 * 133 * The crit section is an optimization to avoid having to get and put 134 * the newest version of the label. While the cred won't change and 135 * hence the label it contains won't change, the newest version of the 136 * label can. During the crit section the newest versions of the label 137 * will be used until the end of the crit section. 138 * 139 * If the label has not been updated at the start of the crit section 140 * no refcount is taken, the cred's refcount is enough to hold the 141 * label for the duration of the crit section. 142 * 143 * If the label has been updated then a refcount will be taken and the 144 * newest version of the label will be returned. While the cred label 145 * and the returned label could be compared at the end of the crit 146 * section, needput is used because it allows better optimization by 147 * the compiler and the processor's speculative execution. 148 */ 149 static inline struct aa_label *__begin_cred_crit_section(const struct cred *cred, 150 bool *needput) 151 { 152 struct aa_label *label = cred_label(cred); 153 154 if (label_is_stale(label)) { 155 *needput = true; 156 return aa_get_newest_label(label); 157 } 158 159 *needput = false; 160 return label; 161 } 162 163 /** 164 * __end_current_label_crit_section - end crit section begun with __begin_... 165 * @label: label obtained from __begin_current_label_crit_section 166 * @needput: output: bool set by __begin_current_label_crit_section 167 * 168 * wrapper around __end_cred_crit_section() to pair nicely with 169 * __begin_current_label_crit_section() 170 */ 171 static inline void __end_current_label_crit_section(struct aa_label *label, 172 bool needput) 173 { 174 __end_cred_crit_section(label, needput); 175 } 176 177 /** 178 * end_current_label_crit_section - put a reference found with begin_current_label.. 179 * @label: label reference to put 180 * 181 * Should only be used with a reference obtained with 182 * begin_current_label_crit_section and never used in situations where the 183 * task cred may be updated 184 */ 185 static inline void end_current_label_crit_section(struct aa_label *label) 186 { 187 if (label != aa_current_raw_label()) 188 aa_put_label(label); 189 } 190 191 /** 192 * __begin_current_label_crit_section - current's confining label 193 * @needput: store whether the label needs to be put when ending crit section 194 * 195 * Returns: up to date confining label or the ns unconfined label (NOT NULL) 196 * 197 * safe to call inside locks 198 * 199 * The returned reference must be put with __end_current_label_crit_section() 200 * This must NOT be used if the task cred could be updated within the 201 * critical section between __begin_current_label_crit_section() .. 202 * __end_current_label_crit_section() 203 */ 204 static inline struct aa_label *__begin_current_label_crit_section(bool *needput) 205 { 206 return __begin_cred_crit_section(current_cred(), needput); 207 } 208 209 /** 210 * begin_current_label_crit_section - current's confining label and update it 211 * 212 * Returns: up to date confining label or the ns unconfined label (NOT NULL) 213 * 214 * Not safe to call inside locks 215 * 216 * The returned reference must be put with end_current_label_crit_section() 217 * This must NOT be used if the task cred could be updated within the 218 * critical section between begin_current_label_crit_section() .. 219 * end_current_label_crit_section() 220 */ 221 static inline struct aa_label *begin_current_label_crit_section(void) 222 { 223 struct aa_label *label = aa_current_raw_label(); 224 225 might_sleep(); 226 227 if (label_is_stale(label)) { 228 label = aa_get_newest_label(label); 229 if (aa_replace_current_label(label) == 0) 230 /* task cred will keep the reference */ 231 aa_put_label(label); 232 } 233 234 return label; 235 } 236 237 static inline struct aa_ns *aa_get_current_ns(void) 238 { 239 struct aa_label *label; 240 struct aa_ns *ns; 241 bool needput; 242 243 label = __begin_current_label_crit_section(&needput); 244 ns = aa_get_ns(labels_ns(label)); 245 __end_current_label_crit_section(label, needput); 246 247 return ns; 248 } 249 250 #endif /* __AA_CONTEXT_H */ 251