1 /* 2 * AppArmor security module 3 * 4 * This file contains AppArmor task related definitions and mediation 5 * 6 * Copyright 2017 Canonical Ltd. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation, version 2 of the 11 * License. 12 * 13 * TODO 14 * If a task uses change_hat it currently does not return to the old 15 * cred or task context but instead creates a new one. Ideally the task 16 * should return to the previous cred if it has not been modified. 17 */ 18 19 #include "include/cred.h" 20 #include "include/task.h" 21 22 /** 23 * aa_get_task_label - Get another task's label 24 * @task: task to query (NOT NULL) 25 * 26 * Returns: counted reference to @task's label 27 */ 28 struct aa_label *aa_get_task_label(struct task_struct *task) 29 { 30 struct aa_label *p; 31 32 rcu_read_lock(); 33 p = aa_get_newest_label(__aa_task_raw_label(task)); 34 rcu_read_unlock(); 35 36 return p; 37 } 38 39 /** 40 * aa_replace_current_label - replace the current tasks label 41 * @label: new label (NOT NULL) 42 * 43 * Returns: 0 or error on failure 44 */ 45 int aa_replace_current_label(struct aa_label *label) 46 { 47 struct aa_label *old = aa_current_raw_label(); 48 struct aa_task_ctx *ctx = task_ctx(current); 49 struct cred *new; 50 51 AA_BUG(!label); 52 53 if (old == label) 54 return 0; 55 56 if (current_cred() != current_real_cred()) 57 return -EBUSY; 58 59 new = prepare_creds(); 60 if (!new) 61 return -ENOMEM; 62 63 if (ctx->nnp && label_is_stale(ctx->nnp)) { 64 struct aa_label *tmp = ctx->nnp; 65 66 ctx->nnp = aa_get_newest_label(tmp); 67 aa_put_label(tmp); 68 } 69 if (unconfined(label) || (labels_ns(old) != labels_ns(label))) 70 /* 71 * if switching to unconfined or a different label namespace 72 * clear out context state 73 */ 74 aa_clear_task_ctx_trans(task_ctx(current)); 75 76 /* 77 * be careful switching cred label, when racing replacement it 78 * is possible that the cred labels's->proxy->label is the reference 79 * keeping @label valid, so make sure to get its reference before 80 * dropping the reference on the cred's label 81 */ 82 aa_get_label(label); 83 aa_put_label(cred_label(new)); 84 cred_label(new) = label; 85 86 commit_creds(new); 87 return 0; 88 } 89 90 91 /** 92 * aa_set_current_onexec - set the tasks change_profile to happen onexec 93 * @label: system label to set at exec (MAYBE NULL to clear value) 94 * @stack: whether stacking should be done 95 * Returns: 0 or error on failure 96 */ 97 int aa_set_current_onexec(struct aa_label *label, bool stack) 98 { 99 struct aa_task_ctx *ctx = task_ctx(current); 100 101 aa_get_label(label); 102 aa_put_label(ctx->onexec); 103 ctx->onexec = label; 104 ctx->token = stack; 105 106 return 0; 107 } 108 109 /** 110 * aa_set_current_hat - set the current tasks hat 111 * @label: label to set as the current hat (NOT NULL) 112 * @token: token value that must be specified to change from the hat 113 * 114 * Do switch of tasks hat. If the task is currently in a hat 115 * validate the token to match. 116 * 117 * Returns: 0 or error on failure 118 */ 119 int aa_set_current_hat(struct aa_label *label, u64 token) 120 { 121 struct aa_task_ctx *ctx = task_ctx(current); 122 struct cred *new; 123 124 new = prepare_creds(); 125 if (!new) 126 return -ENOMEM; 127 AA_BUG(!label); 128 129 if (!ctx->previous) { 130 /* transfer refcount */ 131 ctx->previous = cred_label(new); 132 ctx->token = token; 133 } else if (ctx->token == token) { 134 aa_put_label(cred_label(new)); 135 } else { 136 /* previous_profile && ctx->token != token */ 137 abort_creds(new); 138 return -EACCES; 139 } 140 141 cred_label(new) = aa_get_newest_label(label); 142 /* clear exec on switching context */ 143 aa_put_label(ctx->onexec); 144 ctx->onexec = NULL; 145 146 commit_creds(new); 147 return 0; 148 } 149 150 /** 151 * aa_restore_previous_label - exit from hat context restoring previous label 152 * @token: the token that must be matched to exit hat context 153 * 154 * Attempt to return out of a hat to the previous label. The token 155 * must match the stored token value. 156 * 157 * Returns: 0 or error of failure 158 */ 159 int aa_restore_previous_label(u64 token) 160 { 161 struct aa_task_ctx *ctx = task_ctx(current); 162 struct cred *new; 163 164 if (ctx->token != token) 165 return -EACCES; 166 /* ignore restores when there is no saved label */ 167 if (!ctx->previous) 168 return 0; 169 170 new = prepare_creds(); 171 if (!new) 172 return -ENOMEM; 173 174 aa_put_label(cred_label(new)); 175 cred_label(new) = aa_get_newest_label(ctx->previous); 176 AA_BUG(!cred_label(new)); 177 /* clear exec && prev information when restoring to previous context */ 178 aa_clear_task_ctx_trans(ctx); 179 180 commit_creds(new); 181 182 return 0; 183 } 184