/*1* AppArmor security module2*3* This file contains AppArmor functions used to manipulate object security4* contexts.5*6* Copyright (C) 1998-2008 Novell/SUSE7* Copyright 2009-2010 Canonical Ltd.8*9* This program is free software; you can redistribute it and/or10* modify it under the terms of the GNU General Public License as11* published by the Free Software Foundation, version 2 of the12* License.13*14*15* AppArmor sets confinement on every task, via the the aa_task_cxt and16* the aa_task_cxt.profile, both of which are required and are not allowed17* to be NULL. The aa_task_cxt is not reference counted and is unique18* to each cred (which is reference count). The profile pointed to by19* the task_cxt is reference counted.20*21* TODO22* If a task uses change_hat it currently does not return to the old23* cred or task context but instead creates a new one. Ideally the task24* should return to the previous cred if it has not been modified.25*26*/2728#include "include/context.h"29#include "include/policy.h"3031/**32* aa_alloc_task_context - allocate a new task_cxt33* @flags: gfp flags for allocation34*35* Returns: allocated buffer or NULL on failure36*/37struct aa_task_cxt *aa_alloc_task_context(gfp_t flags)38{39return kzalloc(sizeof(struct aa_task_cxt), flags);40}4142/**43* aa_free_task_context - free a task_cxt44* @cxt: task_cxt to free (MAYBE NULL)45*/46void aa_free_task_context(struct aa_task_cxt *cxt)47{48if (cxt) {49aa_put_profile(cxt->profile);50aa_put_profile(cxt->previous);51aa_put_profile(cxt->onexec);5253kzfree(cxt);54}55}5657/**58* aa_dup_task_context - duplicate a task context, incrementing reference counts59* @new: a blank task context (NOT NULL)60* @old: the task context to copy (NOT NULL)61*/62void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)63{64*new = *old;65aa_get_profile(new->profile);66aa_get_profile(new->previous);67aa_get_profile(new->onexec);68}6970/**71* aa_replace_current_profile - replace the current tasks profiles72* @profile: new profile (NOT NULL)73*74* Returns: 0 or error on failure75*/76int aa_replace_current_profile(struct aa_profile *profile)77{78struct aa_task_cxt *cxt = current_cred()->security;79struct cred *new;80BUG_ON(!profile);8182if (cxt->profile == profile)83return 0;8485new = prepare_creds();86if (!new)87return -ENOMEM;8889cxt = new->security;90if (unconfined(profile) || (cxt->profile->ns != profile->ns)) {91/* if switching to unconfined or a different profile namespace92* clear out context state93*/94aa_put_profile(cxt->previous);95aa_put_profile(cxt->onexec);96cxt->previous = NULL;97cxt->onexec = NULL;98cxt->token = 0;99}100/* be careful switching cxt->profile, when racing replacement it101* is possible that cxt->profile->replacedby is the reference keeping102* @profile valid, so make sure to get its reference before dropping103* the reference on cxt->profile */104aa_get_profile(profile);105aa_put_profile(cxt->profile);106cxt->profile = profile;107108commit_creds(new);109return 0;110}111112/**113* aa_set_current_onexec - set the tasks change_profile to happen onexec114* @profile: system profile to set at exec (MAYBE NULL to clear value)115*116* Returns: 0 or error on failure117*/118int aa_set_current_onexec(struct aa_profile *profile)119{120struct aa_task_cxt *cxt;121struct cred *new = prepare_creds();122if (!new)123return -ENOMEM;124125cxt = new->security;126aa_get_profile(profile);127aa_put_profile(cxt->onexec);128cxt->onexec = profile;129130commit_creds(new);131return 0;132}133134/**135* aa_set_current_hat - set the current tasks hat136* @profile: profile to set as the current hat (NOT NULL)137* @token: token value that must be specified to change from the hat138*139* Do switch of tasks hat. If the task is currently in a hat140* validate the token to match.141*142* Returns: 0 or error on failure143*/144int aa_set_current_hat(struct aa_profile *profile, u64 token)145{146struct aa_task_cxt *cxt;147struct cred *new = prepare_creds();148if (!new)149return -ENOMEM;150BUG_ON(!profile);151152cxt = new->security;153if (!cxt->previous) {154/* transfer refcount */155cxt->previous = cxt->profile;156cxt->token = token;157} else if (cxt->token == token) {158aa_put_profile(cxt->profile);159} else {160/* previous_profile && cxt->token != token */161abort_creds(new);162return -EACCES;163}164cxt->profile = aa_get_profile(aa_newest_version(profile));165/* clear exec on switching context */166aa_put_profile(cxt->onexec);167cxt->onexec = NULL;168169commit_creds(new);170return 0;171}172173/**174* aa_restore_previous_profile - exit from hat context restoring the profile175* @token: the token that must be matched to exit hat context176*177* Attempt to return out of a hat to the previous profile. The token178* must match the stored token value.179*180* Returns: 0 or error of failure181*/182int aa_restore_previous_profile(u64 token)183{184struct aa_task_cxt *cxt;185struct cred *new = prepare_creds();186if (!new)187return -ENOMEM;188189cxt = new->security;190if (cxt->token != token) {191abort_creds(new);192return -EACCES;193}194/* ignore restores when there is no saved profile */195if (!cxt->previous) {196abort_creds(new);197return 0;198}199200aa_put_profile(cxt->profile);201cxt->profile = aa_newest_version(cxt->previous);202BUG_ON(!cxt->profile);203if (unlikely(cxt->profile != cxt->previous)) {204aa_get_profile(cxt->profile);205aa_put_profile(cxt->previous);206}207/* clear exec && prev information when restoring to previous context */208cxt->previous = NULL;209cxt->token = 0;210aa_put_profile(cxt->onexec);211cxt->onexec = NULL;212213commit_creds(new);214return 0;215}216217218