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