18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor task related definitions and mediation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright 2017 Canonical Ltd. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * TODO 108c2ecf20Sopenharmony_ci * If a task uses change_hat it currently does not return to the old 118c2ecf20Sopenharmony_ci * cred or task context but instead creates a new one. Ideally the task 128c2ecf20Sopenharmony_ci * should return to the previous cred if it has not been modified. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "include/cred.h" 168c2ecf20Sopenharmony_ci#include "include/task.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/** 198c2ecf20Sopenharmony_ci * aa_get_task_label - Get another task's label 208c2ecf20Sopenharmony_ci * @task: task to query (NOT NULL) 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Returns: counted reference to @task's label 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_cistruct aa_label *aa_get_task_label(struct task_struct *task) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct aa_label *p; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci rcu_read_lock(); 298c2ecf20Sopenharmony_ci p = aa_get_newest_label(__aa_task_raw_label(task)); 308c2ecf20Sopenharmony_ci rcu_read_unlock(); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return p; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/** 368c2ecf20Sopenharmony_ci * aa_replace_current_label - replace the current tasks label 378c2ecf20Sopenharmony_ci * @label: new label (NOT NULL) 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Returns: 0 or error on failure 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ciint aa_replace_current_label(struct aa_label *label) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct aa_label *old = aa_current_raw_label(); 448c2ecf20Sopenharmony_ci struct aa_task_ctx *ctx = task_ctx(current); 458c2ecf20Sopenharmony_ci struct cred *new; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci AA_BUG(!label); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (old == label) 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (current_cred() != current_real_cred()) 538c2ecf20Sopenharmony_ci return -EBUSY; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci new = prepare_creds(); 568c2ecf20Sopenharmony_ci if (!new) 578c2ecf20Sopenharmony_ci return -ENOMEM; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (ctx->nnp && label_is_stale(ctx->nnp)) { 608c2ecf20Sopenharmony_ci struct aa_label *tmp = ctx->nnp; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci ctx->nnp = aa_get_newest_label(tmp); 638c2ecf20Sopenharmony_ci aa_put_label(tmp); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci if (unconfined(label) || (labels_ns(old) != labels_ns(label))) 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * if switching to unconfined or a different label namespace 688c2ecf20Sopenharmony_ci * clear out context state 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_ci aa_clear_task_ctx_trans(task_ctx(current)); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* 738c2ecf20Sopenharmony_ci * be careful switching cred label, when racing replacement it 748c2ecf20Sopenharmony_ci * is possible that the cred labels's->proxy->label is the reference 758c2ecf20Sopenharmony_ci * keeping @label valid, so make sure to get its reference before 768c2ecf20Sopenharmony_ci * dropping the reference on the cred's label 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci aa_get_label(label); 798c2ecf20Sopenharmony_ci aa_put_label(cred_label(new)); 808c2ecf20Sopenharmony_ci set_cred_label(new, label); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci commit_creds(new); 838c2ecf20Sopenharmony_ci return 0; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * aa_set_current_onexec - set the tasks change_profile to happen onexec 898c2ecf20Sopenharmony_ci * @label: system label to set at exec (MAYBE NULL to clear value) 908c2ecf20Sopenharmony_ci * @stack: whether stacking should be done 918c2ecf20Sopenharmony_ci * Returns: 0 or error on failure 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ciint aa_set_current_onexec(struct aa_label *label, bool stack) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct aa_task_ctx *ctx = task_ctx(current); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci aa_get_label(label); 988c2ecf20Sopenharmony_ci aa_put_label(ctx->onexec); 998c2ecf20Sopenharmony_ci ctx->onexec = label; 1008c2ecf20Sopenharmony_ci ctx->token = stack; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/** 1068c2ecf20Sopenharmony_ci * aa_set_current_hat - set the current tasks hat 1078c2ecf20Sopenharmony_ci * @label: label to set as the current hat (NOT NULL) 1088c2ecf20Sopenharmony_ci * @token: token value that must be specified to change from the hat 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * Do switch of tasks hat. If the task is currently in a hat 1118c2ecf20Sopenharmony_ci * validate the token to match. 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * Returns: 0 or error on failure 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ciint aa_set_current_hat(struct aa_label *label, u64 token) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct aa_task_ctx *ctx = task_ctx(current); 1188c2ecf20Sopenharmony_ci struct cred *new; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci new = prepare_creds(); 1218c2ecf20Sopenharmony_ci if (!new) 1228c2ecf20Sopenharmony_ci return -ENOMEM; 1238c2ecf20Sopenharmony_ci AA_BUG(!label); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (!ctx->previous) { 1268c2ecf20Sopenharmony_ci /* transfer refcount */ 1278c2ecf20Sopenharmony_ci ctx->previous = cred_label(new); 1288c2ecf20Sopenharmony_ci ctx->token = token; 1298c2ecf20Sopenharmony_ci } else if (ctx->token == token) { 1308c2ecf20Sopenharmony_ci aa_put_label(cred_label(new)); 1318c2ecf20Sopenharmony_ci } else { 1328c2ecf20Sopenharmony_ci /* previous_profile && ctx->token != token */ 1338c2ecf20Sopenharmony_ci abort_creds(new); 1348c2ecf20Sopenharmony_ci return -EACCES; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci set_cred_label(new, aa_get_newest_label(label)); 1388c2ecf20Sopenharmony_ci /* clear exec on switching context */ 1398c2ecf20Sopenharmony_ci aa_put_label(ctx->onexec); 1408c2ecf20Sopenharmony_ci ctx->onexec = NULL; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci commit_creds(new); 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * aa_restore_previous_label - exit from hat context restoring previous label 1488c2ecf20Sopenharmony_ci * @token: the token that must be matched to exit hat context 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Attempt to return out of a hat to the previous label. The token 1518c2ecf20Sopenharmony_ci * must match the stored token value. 1528c2ecf20Sopenharmony_ci * 1538c2ecf20Sopenharmony_ci * Returns: 0 or error of failure 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ciint aa_restore_previous_label(u64 token) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct aa_task_ctx *ctx = task_ctx(current); 1588c2ecf20Sopenharmony_ci struct cred *new; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (ctx->token != token) 1618c2ecf20Sopenharmony_ci return -EACCES; 1628c2ecf20Sopenharmony_ci /* ignore restores when there is no saved label */ 1638c2ecf20Sopenharmony_ci if (!ctx->previous) 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci new = prepare_creds(); 1678c2ecf20Sopenharmony_ci if (!new) 1688c2ecf20Sopenharmony_ci return -ENOMEM; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci aa_put_label(cred_label(new)); 1718c2ecf20Sopenharmony_ci set_cred_label(new, aa_get_newest_label(ctx->previous)); 1728c2ecf20Sopenharmony_ci AA_BUG(!cred_label(new)); 1738c2ecf20Sopenharmony_ci /* clear exec && prev information when restoring to previous context */ 1748c2ecf20Sopenharmony_ci aa_clear_task_ctx_trans(ctx); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci commit_creds(new); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 180