linux/security/apparmor/context.c
<<
>>
Prefs
   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_cxt and
  17 * the aa_task_cxt.profile, both of which are required and are not allowed
  18 * to be NULL.  The aa_task_cxt is not reference counted and is unique
  19 * to each cred (which is reference count).  The profile pointed to by
  20 * the task_cxt 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_cxt
  34 * @flags: gfp flags for allocation
  35 *
  36 * Returns: allocated buffer or NULL on failure
  37 */
  38struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
  39{
  40        return kzalloc(sizeof(struct aa_task_cxt), flags);
  41}
  42
  43/**
  44 * aa_free_task_context - free a task_cxt
  45 * @cxt: task_cxt to free (MAYBE NULL)
  46 */
  47void aa_free_task_context(struct aa_task_cxt *cxt)
  48{
  49        if (cxt) {
  50                aa_put_profile(cxt->profile);
  51                aa_put_profile(cxt->previous);
  52                aa_put_profile(cxt->onexec);
  53
  54                kzfree(cxt);
  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_cxt *new, const struct aa_task_cxt *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_cxt *cxt = current_cxt();
  97        struct cred *new;
  98        BUG_ON(!profile);
  99
 100        if (cxt->profile == profile)
 101                return 0;
 102
 103        new  = prepare_creds();
 104        if (!new)
 105                return -ENOMEM;
 106
 107        cxt = cred_cxt(new);
 108        if (unconfined(profile) || (cxt->profile->ns != profile->ns))
 109                /* if switching to unconfined or a different profile namespace
 110                 * clear out context state
 111                 */
 112                aa_clear_task_cxt_trans(cxt);
 113
 114        /* be careful switching cxt->profile, when racing replacement it
 115         * is possible that cxt->profile->replacedby->profile is the reference
 116         * keeping @profile valid, so make sure to get its reference before
 117         * dropping the reference on cxt->profile */
 118        aa_get_profile(profile);
 119        aa_put_profile(cxt->profile);
 120        cxt->profile = profile;
 121
 122        commit_creds(new);
 123        return 0;
 124}
 125
 126/**
 127 * aa_set_current_onexec - set the tasks change_profile to happen onexec
 128 * @profile: system profile to set at exec  (MAYBE NULL to clear value)
 129 *
 130 * Returns: 0 or error on failure
 131 */
 132int aa_set_current_onexec(struct aa_profile *profile)
 133{
 134        struct aa_task_cxt *cxt;
 135        struct cred *new = prepare_creds();
 136        if (!new)
 137                return -ENOMEM;
 138
 139        cxt = cred_cxt(new);
 140        aa_get_profile(profile);
 141        aa_put_profile(cxt->onexec);
 142        cxt->onexec = profile;
 143
 144        commit_creds(new);
 145        return 0;
 146}
 147
 148/**
 149 * aa_set_current_hat - set the current tasks hat
 150 * @profile: profile to set as the current hat  (NOT NULL)
 151 * @token: token value that must be specified to change from the hat
 152 *
 153 * Do switch of tasks hat.  If the task is currently in a hat
 154 * validate the token to match.
 155 *
 156 * Returns: 0 or error on failure
 157 */
 158int aa_set_current_hat(struct aa_profile *profile, u64 token)
 159{
 160        struct aa_task_cxt *cxt;
 161        struct cred *new = prepare_creds();
 162        if (!new)
 163                return -ENOMEM;
 164        BUG_ON(!profile);
 165
 166        cxt = cred_cxt(new);
 167        if (!cxt->previous) {
 168                /* transfer refcount */
 169                cxt->previous = cxt->profile;
 170                cxt->token = token;
 171        } else if (cxt->token == token) {
 172                aa_put_profile(cxt->profile);
 173        } else {
 174                /* previous_profile && cxt->token != token */
 175                abort_creds(new);
 176                return -EACCES;
 177        }
 178        cxt->profile = aa_get_newest_profile(profile);
 179        /* clear exec on switching context */
 180        aa_put_profile(cxt->onexec);
 181        cxt->onexec = NULL;
 182
 183        commit_creds(new);
 184        return 0;
 185}
 186
 187/**
 188 * aa_restore_previous_profile - exit from hat context restoring the profile
 189 * @token: the token that must be matched to exit hat context
 190 *
 191 * Attempt to return out of a hat to the previous profile.  The token
 192 * must match the stored token value.
 193 *
 194 * Returns: 0 or error of failure
 195 */
 196int aa_restore_previous_profile(u64 token)
 197{
 198        struct aa_task_cxt *cxt;
 199        struct cred *new = prepare_creds();
 200        if (!new)
 201                return -ENOMEM;
 202
 203        cxt = cred_cxt(new);
 204        if (cxt->token != token) {
 205                abort_creds(new);
 206                return -EACCES;
 207        }
 208        /* ignore restores when there is no saved profile */
 209        if (!cxt->previous) {
 210                abort_creds(new);
 211                return 0;
 212        }
 213
 214        aa_put_profile(cxt->profile);
 215        cxt->profile = aa_get_newest_profile(cxt->previous);
 216        BUG_ON(!cxt->profile);
 217        /* clear exec && prev information when restoring to previous context */
 218        aa_clear_task_cxt_trans(cxt);
 219
 220        commit_creds(new);
 221        return 0;
 222}
 223