at v4.11 5.6 kB view raw
1/* 2 * AppArmor security module 3 * 4 * This file contains AppArmor functions used to manipulate object security 5 * contexts. 6 * 7 * Copyright (C) 1998-2008 Novell/SUSE 8 * Copyright 2009-2010 Canonical Ltd. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation, version 2 of the 13 * License. 14 * 15 * 16 * AppArmor sets confinement on every task, via the the aa_task_ctx and 17 * the aa_task_ctx.profile, both of which are required and are not allowed 18 * to be NULL. The aa_task_ctx is not reference counted and is unique 19 * to each cred (which is reference count). The profile pointed to by 20 * the task_ctx is reference counted. 21 * 22 * TODO 23 * If a task uses change_hat it currently does not return to the old 24 * cred or task context but instead creates a new one. Ideally the task 25 * should return to the previous cred if it has not been modified. 26 * 27 */ 28 29#include "include/context.h" 30#include "include/policy.h" 31 32/** 33 * aa_alloc_task_context - allocate a new task_ctx 34 * @flags: gfp flags for allocation 35 * 36 * Returns: allocated buffer or NULL on failure 37 */ 38struct aa_task_ctx *aa_alloc_task_context(gfp_t flags) 39{ 40 return kzalloc(sizeof(struct aa_task_ctx), flags); 41} 42 43/** 44 * aa_free_task_context - free a task_ctx 45 * @ctx: task_ctx to free (MAYBE NULL) 46 */ 47void aa_free_task_context(struct aa_task_ctx *ctx) 48{ 49 if (ctx) { 50 aa_put_profile(ctx->profile); 51 aa_put_profile(ctx->previous); 52 aa_put_profile(ctx->onexec); 53 54 kzfree(ctx); 55 } 56} 57 58/** 59 * aa_dup_task_context - duplicate a task context, incrementing reference counts 60 * @new: a blank task context (NOT NULL) 61 * @old: the task context to copy (NOT NULL) 62 */ 63void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old) 64{ 65 *new = *old; 66 aa_get_profile(new->profile); 67 aa_get_profile(new->previous); 68 aa_get_profile(new->onexec); 69} 70 71/** 72 * aa_get_task_profile - Get another task's profile 73 * @task: task to query (NOT NULL) 74 * 75 * Returns: counted reference to @task's profile 76 */ 77struct aa_profile *aa_get_task_profile(struct task_struct *task) 78{ 79 struct aa_profile *p; 80 81 rcu_read_lock(); 82 p = aa_get_profile(__aa_task_profile(task)); 83 rcu_read_unlock(); 84 85 return p; 86} 87 88/** 89 * aa_replace_current_profile - replace the current tasks profiles 90 * @profile: new profile (NOT NULL) 91 * 92 * Returns: 0 or error on failure 93 */ 94int aa_replace_current_profile(struct aa_profile *profile) 95{ 96 struct aa_task_ctx *ctx = current_ctx(); 97 struct cred *new; 98 AA_BUG(!profile); 99 100 if (ctx->profile == profile) 101 return 0; 102 103 if (current_cred() != current_real_cred()) 104 return -EBUSY; 105 106 new = prepare_creds(); 107 if (!new) 108 return -ENOMEM; 109 110 ctx = cred_ctx(new); 111 if (unconfined(profile) || (ctx->profile->ns != profile->ns)) 112 /* if switching to unconfined or a different profile namespace 113 * clear out context state 114 */ 115 aa_clear_task_ctx_trans(ctx); 116 117 /* 118 * be careful switching ctx->profile, when racing replacement it 119 * is possible that ctx->profile->proxy->profile is the reference 120 * keeping @profile valid, so make sure to get its reference before 121 * dropping the reference on ctx->profile 122 */ 123 aa_get_profile(profile); 124 aa_put_profile(ctx->profile); 125 ctx->profile = profile; 126 127 commit_creds(new); 128 return 0; 129} 130 131/** 132 * aa_set_current_onexec - set the tasks change_profile to happen onexec 133 * @profile: system profile to set at exec (MAYBE NULL to clear value) 134 * 135 * Returns: 0 or error on failure 136 */ 137int aa_set_current_onexec(struct aa_profile *profile) 138{ 139 struct aa_task_ctx *ctx; 140 struct cred *new = prepare_creds(); 141 if (!new) 142 return -ENOMEM; 143 144 ctx = cred_ctx(new); 145 aa_get_profile(profile); 146 aa_put_profile(ctx->onexec); 147 ctx->onexec = profile; 148 149 commit_creds(new); 150 return 0; 151} 152 153/** 154 * aa_set_current_hat - set the current tasks hat 155 * @profile: profile to set as the current hat (NOT NULL) 156 * @token: token value that must be specified to change from the hat 157 * 158 * Do switch of tasks hat. If the task is currently in a hat 159 * validate the token to match. 160 * 161 * Returns: 0 or error on failure 162 */ 163int aa_set_current_hat(struct aa_profile *profile, u64 token) 164{ 165 struct aa_task_ctx *ctx; 166 struct cred *new = prepare_creds(); 167 if (!new) 168 return -ENOMEM; 169 AA_BUG(!profile); 170 171 ctx = cred_ctx(new); 172 if (!ctx->previous) { 173 /* transfer refcount */ 174 ctx->previous = ctx->profile; 175 ctx->token = token; 176 } else if (ctx->token == token) { 177 aa_put_profile(ctx->profile); 178 } else { 179 /* previous_profile && ctx->token != token */ 180 abort_creds(new); 181 return -EACCES; 182 } 183 ctx->profile = aa_get_newest_profile(profile); 184 /* clear exec on switching context */ 185 aa_put_profile(ctx->onexec); 186 ctx->onexec = NULL; 187 188 commit_creds(new); 189 return 0; 190} 191 192/** 193 * aa_restore_previous_profile - exit from hat context restoring the profile 194 * @token: the token that must be matched to exit hat context 195 * 196 * Attempt to return out of a hat to the previous profile. The token 197 * must match the stored token value. 198 * 199 * Returns: 0 or error of failure 200 */ 201int aa_restore_previous_profile(u64 token) 202{ 203 struct aa_task_ctx *ctx; 204 struct cred *new = prepare_creds(); 205 if (!new) 206 return -ENOMEM; 207 208 ctx = cred_ctx(new); 209 if (ctx->token != token) { 210 abort_creds(new); 211 return -EACCES; 212 } 213 /* ignore restores when there is no saved profile */ 214 if (!ctx->previous) { 215 abort_creds(new); 216 return 0; 217 } 218 219 aa_put_profile(ctx->profile); 220 ctx->profile = aa_get_newest_profile(ctx->previous); 221 AA_BUG(!ctx->profile); 222 /* clear exec && prev information when restoring to previous context */ 223 aa_clear_task_ctx_trans(ctx); 224 225 commit_creds(new); 226 return 0; 227}