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