1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AppArmor security module 4 * 5 * This file contains AppArmor task related definitions and mediation 6 * 7 * Copyright 2017 Canonical Ltd. 8 * 9 * TODO 10 * If a task uses change_hat it currently does not return to the old 11 * cred or task context but instead creates a new one. Ideally the task 12 * should return to the previous cred if it has not been modified. 13 */ 14 15 #include <linux/gfp.h> 16 #include <linux/ptrace.h> 17 #include <linux/task_work.h> 18 19 #include "include/path.h" 20 #include "include/audit.h" 21 #include "include/cred.h" 22 #include "include/policy.h" 23 #include "include/task.h" 24 25 /** 26 * aa_get_task_label - Get another task's label 27 * @task: task to query (NOT NULL) 28 * 29 * Returns: counted reference to @task's label 30 */ 31 struct aa_label *aa_get_task_label(struct task_struct *task) 32 { 33 struct aa_label *p; 34 35 rcu_read_lock(); 36 p = aa_get_newest_cred_label(__task_cred(task)); 37 rcu_read_unlock(); 38 39 return p; 40 } 41 42 /** 43 * aa_replace_current_label - replace the current tasks label 44 * @label: new label (NOT NULL) 45 * 46 * Returns: 0 or error on failure 47 */ 48 int aa_replace_current_label(struct aa_label *label) 49 { 50 struct aa_label *old = aa_current_raw_label(); 51 struct aa_task_ctx *ctx = task_ctx(current); 52 struct cred *new; 53 54 AA_BUG(!label); 55 56 if (old == label) 57 return 0; 58 59 if (current_cred() != current_real_cred()) 60 return -EBUSY; 61 62 new = prepare_creds(); 63 if (!new) 64 return -ENOMEM; 65 66 if (ctx->nnp && label_is_stale(ctx->nnp)) { 67 struct aa_label *tmp = ctx->nnp; 68 69 ctx->nnp = aa_get_newest_label(tmp); 70 aa_put_label(tmp); 71 } 72 if (unconfined(label) || (labels_ns(old) != labels_ns(label))) 73 /* 74 * if switching to unconfined or a different label namespace 75 * clear out context state 76 */ 77 aa_clear_task_ctx_trans(task_ctx(current)); 78 79 /* 80 * be careful switching cred label, when racing replacement it 81 * is possible that the cred labels's->proxy->label is the reference 82 * keeping @label valid, so make sure to get its reference before 83 * dropping the reference on the cred's label 84 */ 85 aa_get_label(label); 86 aa_put_label(cred_label(new)); 87 set_cred_label(new, label); 88 89 commit_creds(new); 90 return 0; 91 } 92 93 static void aa_replace_stale_label_tw_func(struct callback_head *tw) 94 { 95 struct aa_task_ctx *ctx = task_ctx(current); 96 struct aa_label *label; 97 98 ctx->label_replacement_pending = false; 99 label = aa_current_raw_label(); 100 if (!label_is_stale(label)) 101 return; 102 label = aa_get_newest_label(label); 103 aa_replace_current_label(label); 104 aa_put_label(label); 105 } 106 107 /* replace the current task's stale label on syscall return */ 108 void aa_schedule_stale_label_replacement(void) 109 { 110 struct aa_task_ctx *ctx = task_ctx(current); 111 112 if (ctx->label_replacement_pending) 113 return; 114 init_task_work(&ctx->label_replacement_tw, aa_replace_stale_label_tw_func); 115 if (task_work_add(current, &ctx->label_replacement_tw, TWA_RESUME) == 0) 116 ctx->label_replacement_pending = true; 117 } 118 119 120 /** 121 * aa_set_current_onexec - set the tasks change_profile to happen onexec 122 * @label: system label to set at exec (MAYBE NULL to clear value) 123 * @stack: whether stacking should be done 124 */ 125 void aa_set_current_onexec(struct aa_label *label, bool stack) 126 { 127 struct aa_task_ctx *ctx = task_ctx(current); 128 129 aa_get_label(label); 130 aa_put_label(ctx->onexec); 131 ctx->onexec = label; 132 ctx->token = stack; 133 } 134 135 /** 136 * aa_set_current_hat - set the current tasks hat 137 * @label: label to set as the current hat (NOT NULL) 138 * @token: token value that must be specified to change from the hat 139 * 140 * Do switch of tasks hat. If the task is currently in a hat 141 * validate the token to match. 142 * 143 * Returns: 0 or error on failure 144 */ 145 int aa_set_current_hat(struct aa_label *label, u64 token) 146 { 147 struct aa_task_ctx *ctx = task_ctx(current); 148 struct cred *new; 149 150 new = prepare_creds(); 151 if (!new) 152 return -ENOMEM; 153 AA_BUG(!label); 154 155 if (!ctx->previous) { 156 /* transfer refcount */ 157 ctx->previous = cred_label(new); 158 ctx->token = token; 159 } else if (ctx->token == token) { 160 aa_put_label(cred_label(new)); 161 } else { 162 /* previous_profile && ctx->token != token */ 163 abort_creds(new); 164 return -EACCES; 165 } 166 167 set_cred_label(new, aa_get_newest_label(label)); 168 /* clear exec on switching context */ 169 aa_put_label(ctx->onexec); 170 ctx->onexec = NULL; 171 172 commit_creds(new); 173 return 0; 174 } 175 176 /** 177 * aa_restore_previous_label - exit from hat context restoring previous label 178 * @token: the token that must be matched to exit hat context 179 * 180 * Attempt to return out of a hat to the previous label. The token 181 * must match the stored token value. 182 * 183 * Returns: 0 or error of failure 184 */ 185 int aa_restore_previous_label(u64 token) 186 { 187 struct aa_task_ctx *ctx = task_ctx(current); 188 struct cred *new; 189 190 if (ctx->token != token) 191 return -EACCES; 192 /* ignore restores when there is no saved label */ 193 if (!ctx->previous) 194 return 0; 195 196 new = prepare_creds(); 197 if (!new) 198 return -ENOMEM; 199 200 aa_put_label(cred_label(new)); 201 set_cred_label(new, aa_get_newest_label(ctx->previous)); 202 AA_BUG(!cred_label(new)); 203 /* clear exec && prev information when restoring to previous context */ 204 aa_clear_task_ctx_trans(ctx); 205 206 commit_creds(new); 207 208 return 0; 209 } 210 211 /** 212 * audit_ptrace_mask - convert mask to permission string 213 * @mask: permission mask to convert 214 * 215 * Returns: pointer to static string 216 */ 217 static const char *audit_ptrace_mask(u32 mask) 218 { 219 switch (mask) { 220 case MAY_READ: 221 return "read"; 222 case MAY_WRITE: 223 return "trace"; 224 case AA_MAY_BE_READ: 225 return "readby"; 226 case AA_MAY_BE_TRACED: 227 return "tracedby"; 228 } 229 return ""; 230 } 231 232 /* call back to audit ptrace fields */ 233 static void audit_ptrace_cb(struct audit_buffer *ab, void *va) 234 { 235 struct common_audit_data *sa = va; 236 struct apparmor_audit_data *ad = aad(sa); 237 238 if (ad->request & AA_PTRACE_PERM_MASK) { 239 audit_log_format(ab, " requested_mask=\"%s\"", 240 audit_ptrace_mask(ad->request)); 241 242 if (ad->denied & AA_PTRACE_PERM_MASK) { 243 audit_log_format(ab, " denied_mask=\"%s\"", 244 audit_ptrace_mask(ad->denied)); 245 } 246 } 247 audit_log_format(ab, " peer="); 248 aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, 249 FLAGS_NONE, GFP_ATOMIC); 250 } 251 252 /* assumes check for RULE_MEDIATES is already done */ 253 /* TODO: conditionals */ 254 static int profile_ptrace_perm(const struct cred *cred, 255 struct aa_profile *profile, 256 struct aa_label *peer, u32 request, 257 struct apparmor_audit_data *ad) 258 { 259 struct aa_ruleset *rules = profile->label.rules[0]; 260 struct aa_perms perms = { }; 261 262 ad->subj_cred = cred; 263 ad->peer = peer; 264 aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request, 265 &perms); 266 aa_apply_modes_to_perms(profile, &perms); 267 return aa_check_perms(profile, &perms, request, ad, audit_ptrace_cb); 268 } 269 270 static int profile_tracee_perm(const struct cred *cred, 271 struct aa_profile *tracee, 272 struct aa_label *tracer, u32 request, 273 struct apparmor_audit_data *ad) 274 { 275 if (profile_unconfined(tracee) || unconfined(tracer) || 276 !label_mediates(&tracee->label, AA_CLASS_PTRACE)) 277 return 0; 278 279 return profile_ptrace_perm(cred, tracee, tracer, request, ad); 280 } 281 282 static int profile_tracer_perm(const struct cred *cred, 283 struct aa_profile *tracer, 284 struct aa_label *tracee, u32 request, 285 struct apparmor_audit_data *ad) 286 { 287 if (profile_unconfined(tracer)) 288 return 0; 289 290 if (label_mediates(&tracer->label, AA_CLASS_PTRACE)) 291 return profile_ptrace_perm(cred, tracer, tracee, request, ad); 292 293 /* profile uses the old style capability check for ptrace */ 294 if (&tracer->label == tracee) 295 return 0; 296 297 ad->subj_label = &tracer->label; 298 ad->peer = tracee; 299 ad->request = 0; 300 ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE, 301 CAP_OPT_NONE); 302 303 return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb); 304 } 305 306 /** 307 * aa_may_ptrace - test if tracer task can trace the tracee 308 * @tracer_cred: cred of task doing the tracing (NOT NULL) 309 * @tracer: label of the task doing the tracing (NOT NULL) 310 * @tracee_cred: cred of task to be traced 311 * @tracee: task label to be traced 312 * @request: permission request 313 * 314 * Returns: %0 else error code if permission denied or error 315 */ 316 int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer, 317 const struct cred *tracee_cred, struct aa_label *tracee, 318 u32 request) 319 { 320 struct aa_profile *profile; 321 u32 xrequest = request << PTRACE_PERM_SHIFT; 322 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE); 323 324 return xcheck_labels(tracer, tracee, profile, 325 profile_tracer_perm(tracer_cred, profile, tracee, 326 request, &sa), 327 profile_tracee_perm(tracee_cred, profile, tracer, 328 xrequest, &sa)); 329 } 330 331 static const char *get_current_exe_path(char *buffer, int buffer_size) 332 { 333 struct file *exe_file; 334 struct path p; 335 const char *path_str; 336 337 exe_file = get_task_exe_file(current); 338 if (!exe_file) 339 return ERR_PTR(-ENOENT); 340 p = exe_file->f_path; 341 path_get(&p); 342 343 if (aa_path_name(&p, FLAG_VIEW_SUBNS, buffer, &path_str, NULL, NULL)) 344 path_str = ERR_PTR(-ENOMEM); 345 346 fput(exe_file); 347 path_put(&p); 348 349 return path_str; 350 } 351 352 /* call back to audit ptrace fields */ 353 static void audit_ns_cb(struct audit_buffer *ab, void *va) 354 { 355 struct apparmor_audit_data *ad = aad_of_va(va); 356 char *buffer; 357 const char *path; 358 359 if (ad->request & AA_USERNS_CREATE) 360 audit_log_format(ab, " requested=\"userns_create\""); 361 362 if (ad->denied & AA_USERNS_CREATE) 363 audit_log_format(ab, " denied=\"userns_create\""); 364 365 buffer = aa_get_buffer(false); 366 if (!buffer) 367 return; // OOM 368 path = get_current_exe_path(buffer, aa_g_path_max); 369 if (!IS_ERR(path)) 370 audit_log_format(ab, " execpath=\"%s\"", path); 371 aa_put_buffer(buffer); 372 } 373 374 int aa_profile_ns_perm(struct aa_profile *profile, 375 struct apparmor_audit_data *ad, 376 u32 request) 377 { 378 struct aa_perms perms = { }; 379 int error = 0; 380 381 ad->subj_label = &profile->label; 382 ad->request = request; 383 384 if (!profile_unconfined(profile)) { 385 struct aa_ruleset *rules = profile->label.rules[0]; 386 aa_state_t state; 387 388 state = RULE_MEDIATES(rules, ad->class); 389 if (!state) 390 /* TODO: add flag to complain about unmediated */ 391 return 0; 392 perms = *aa_lookup_perms(rules->policy, state); 393 aa_apply_modes_to_perms(profile, &perms); 394 error = aa_check_perms(profile, &perms, request, ad, 395 audit_ns_cb); 396 } 397 398 return error; 399 } 400