2010-07-30 01:47:59 +04:00
/*
* AppArmor security module
*
* This file contains AppArmor functions used to manipulate object security
* contexts .
*
* Copyright ( C ) 1998 - 2008 Novell / SUSE
* Copyright 2009 - 2010 Canonical Ltd .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation , version 2 of the
* License .
*
*
2017-01-20 01:08:36 +03:00
* AppArmor sets confinement on every task , via the the aa_cred_ctx and
* the aa_cred_ctx . label , both of which are required and are not allowed
* to be NULL . The aa_cred_ctx is not reference counted and is unique
2017-06-09 18:14:28 +03:00
* to each cred ( which is reference count ) . The label pointed to by
2017-01-20 01:08:36 +03:00
* the cred_ctx is reference counted .
2010-07-30 01:47:59 +04:00
*
* TODO
* If a task uses change_hat it currently does not return to the old
* cred or task context but instead creates a new one . Ideally the task
* should return to the previous cred if it has not been modified .
*
*/
# include "include/context.h"
# include "include/policy.h"
/**
2017-01-20 01:08:36 +03:00
* aa_alloc_cred_ctx - allocate a new cred_ctx
2010-07-30 01:47:59 +04:00
* @ flags : gfp flags for allocation
*
* Returns : allocated buffer or NULL on failure
*/
2017-01-20 01:08:36 +03:00
struct aa_cred_ctx * aa_alloc_cred_ctx ( gfp_t flags )
2010-07-30 01:47:59 +04:00
{
2017-01-20 01:08:36 +03:00
return kzalloc ( sizeof ( struct aa_cred_ctx ) , flags ) ;
2010-07-30 01:47:59 +04:00
}
/**
2017-01-20 01:08:36 +03:00
* aa_free_cred_ctx - free a cred_ctx
* @ ctx : cred_ctx to free ( MAYBE NULL )
2010-07-30 01:47:59 +04:00
*/
2017-01-20 01:08:36 +03:00
void aa_free_cred_ctx ( struct aa_cred_ctx * ctx )
2010-07-30 01:47:59 +04:00
{
2017-01-16 11:43:00 +03:00
if ( ctx ) {
2017-06-09 18:14:28 +03:00
aa_put_label ( ctx - > label ) ;
2010-07-30 01:47:59 +04:00
2017-01-16 11:43:00 +03:00
kzfree ( ctx ) ;
2010-07-30 01:47:59 +04:00
}
}
/**
2017-01-20 01:08:36 +03:00
* aa_dup_cred_ctx - duplicate a task context , incrementing reference counts
2010-07-30 01:47:59 +04:00
* @ new : a blank task context ( NOT NULL )
* @ old : the task context to copy ( NOT NULL )
*/
2017-01-20 01:08:36 +03:00
void aa_dup_cred_ctx ( struct aa_cred_ctx * new , const struct aa_cred_ctx * old )
2010-07-30 01:47:59 +04:00
{
* new = * old ;
2017-06-09 18:14:28 +03:00
aa_get_label ( new - > label ) ;
2010-07-30 01:47:59 +04:00
}
2013-02-19 04:03:34 +04:00
/**
2017-06-09 18:14:28 +03:00
* aa_get_task_label - Get another task ' s label
2013-02-19 04:03:34 +04:00
* @ task : task to query ( NOT NULL )
*
2017-06-09 18:14:28 +03:00
* Returns : counted reference to @ task ' s label
2013-02-19 04:03:34 +04:00
*/
2017-06-09 18:14:28 +03:00
struct aa_label * aa_get_task_label ( struct task_struct * task )
2013-02-19 04:03:34 +04:00
{
2017-06-09 18:14:28 +03:00
struct aa_label * p ;
2013-02-19 04:03:34 +04:00
rcu_read_lock ( ) ;
2017-06-09 18:14:28 +03:00
p = aa_get_newest_label ( __aa_task_raw_label ( task ) ) ;
2013-02-19 04:03:34 +04:00
rcu_read_unlock ( ) ;
return p ;
}
2017-01-20 12:59:25 +03:00
/**
* aa_alloc_task_ctx - allocate a new task_ctx
* @ flags : gfp flags for allocation
*
* Returns : allocated buffer or NULL on failure
*/
struct aa_task_ctx * aa_alloc_task_ctx ( gfp_t flags )
{
return kzalloc ( sizeof ( struct aa_task_ctx ) , flags ) ;
}
/**
* aa_free_task_ctx - free a task_ctx
* @ ctx : task_ctx to free ( MAYBE NULL )
*/
void aa_free_task_ctx ( struct aa_task_ctx * ctx )
{
if ( ctx ) {
aa_put_label ( ctx - > previous ) ;
aa_put_label ( ctx - > onexec ) ;
kzfree ( ctx ) ;
}
}
/**
* aa_dup_task_ctx - duplicate a task context , incrementing reference counts
* @ new : a blank task context ( NOT NULL )
* @ old : the task context to copy ( NOT NULL )
*/
void aa_dup_task_ctx ( struct aa_task_ctx * new , const struct aa_task_ctx * old )
{
* new = * old ;
aa_get_label ( new - > previous ) ;
aa_get_label ( new - > onexec ) ;
}
2010-07-30 01:47:59 +04:00
/**
2017-06-09 18:14:28 +03:00
* aa_replace_current_label - replace the current tasks label
* @ label : new label ( NOT NULL )
2010-07-30 01:47:59 +04:00
*
* Returns : 0 or error on failure
*/
2017-06-09 18:14:28 +03:00
int aa_replace_current_label ( struct aa_label * label )
2010-07-30 01:47:59 +04:00
{
2017-01-20 01:08:36 +03:00
struct aa_cred_ctx * ctx = current_cred_ctx ( ) ;
2010-07-30 01:47:59 +04:00
struct cred * new ;
2017-06-09 18:14:28 +03:00
AA_BUG ( ! label ) ;
2010-07-30 01:47:59 +04:00
2017-06-09 18:14:28 +03:00
if ( ctx - > label = = label )
2010-07-30 01:47:59 +04:00
return 0 ;
2017-01-16 11:42:59 +03:00
if ( current_cred ( ) ! = current_real_cred ( ) )
return - EBUSY ;
2010-07-30 01:47:59 +04:00
new = prepare_creds ( ) ;
if ( ! new )
return - ENOMEM ;
2017-01-16 11:43:00 +03:00
ctx = cred_ctx ( new ) ;
2017-06-09 18:14:28 +03:00
if ( unconfined ( label ) | | ( labels_ns ( ctx - > label ) ! = labels_ns ( label ) ) )
/* if switching to unconfined or a different label namespace
2010-07-30 01:47:59 +04:00
* clear out context state
*/
2017-01-20 12:59:25 +03:00
aa_clear_task_ctx_trans ( current_task_ctx ( ) ) ;
2013-02-19 04:05:34 +04:00
2017-01-16 11:43:00 +03:00
/*
* be careful switching ctx - > profile , when racing replacement it
* is possible that ctx - > profile - > proxy - > profile is the reference
2013-07-11 08:07:43 +04:00
* keeping @ profile valid , so make sure to get its reference before
2017-01-16 11:43:00 +03:00
* dropping the reference on ctx - > profile
*/
2017-06-09 18:14:28 +03:00
aa_get_label ( label ) ;
aa_put_label ( ctx - > label ) ;
ctx - > label = label ;
2010-07-30 01:47:59 +04:00
commit_creds ( new ) ;
return 0 ;
}
/**
* aa_set_current_onexec - set the tasks change_profile to happen onexec
2017-06-09 18:14:28 +03:00
* @ label : system label to set at exec ( MAYBE NULL to clear value )
* @ stack : whether stacking should be done
2010-07-30 01:47:59 +04:00
* Returns : 0 or error on failure
*/
2017-06-09 18:14:28 +03:00
int aa_set_current_onexec ( struct aa_label * label , bool stack )
2010-07-30 01:47:59 +04:00
{
2017-01-20 12:59:25 +03:00
struct aa_task_ctx * ctx = current_task_ctx ( ) ;
2010-07-30 01:47:59 +04:00
2017-06-09 18:14:28 +03:00
aa_get_label ( label ) ;
2017-01-20 12:59:25 +03:00
aa_put_label ( ctx - > onexec ) ;
2017-06-09 18:14:28 +03:00
ctx - > onexec = label ;
ctx - > token = stack ;
2010-07-30 01:47:59 +04:00
return 0 ;
}
/**
* aa_set_current_hat - set the current tasks hat
2017-06-09 18:14:28 +03:00
* @ label : label to set as the current hat ( NOT NULL )
2010-07-30 01:47:59 +04:00
* @ token : token value that must be specified to change from the hat
*
* Do switch of tasks hat . If the task is currently in a hat
* validate the token to match .
*
* Returns : 0 or error on failure
*/
2017-06-09 18:14:28 +03:00
int aa_set_current_hat ( struct aa_label * label , u64 token )
2010-07-30 01:47:59 +04:00
{
2017-01-20 12:59:25 +03:00
struct aa_task_ctx * tctx = current_task_ctx ( ) ;
2017-01-20 01:08:36 +03:00
struct aa_cred_ctx * ctx ;
2010-07-30 01:47:59 +04:00
struct cred * new = prepare_creds ( ) ;
2017-01-20 12:59:25 +03:00
2010-07-30 01:47:59 +04:00
if ( ! new )
return - ENOMEM ;
2017-06-09 18:14:28 +03:00
AA_BUG ( ! label ) ;
2010-07-30 01:47:59 +04:00
2017-01-16 11:43:00 +03:00
ctx = cred_ctx ( new ) ;
2017-01-20 12:59:25 +03:00
if ( ! tctx - > previous ) {
2010-07-30 01:47:59 +04:00
/* transfer refcount */
2017-01-20 12:59:25 +03:00
tctx - > previous = ctx - > label ;
tctx - > token = token ;
} else if ( tctx - > token = = token ) {
2017-06-09 18:14:28 +03:00
aa_put_label ( ctx - > label ) ;
2010-07-30 01:47:59 +04:00
} else {
2017-01-16 11:43:00 +03:00
/* previous_profile && ctx->token != token */
2010-07-30 01:47:59 +04:00
abort_creds ( new ) ;
return - EACCES ;
}
2017-01-20 12:59:25 +03:00
2017-06-09 18:14:28 +03:00
ctx - > label = aa_get_newest_label ( label ) ;
2010-07-30 01:47:59 +04:00
/* clear exec on switching context */
2017-01-20 12:59:25 +03:00
aa_put_label ( tctx - > onexec ) ;
tctx - > onexec = NULL ;
2010-07-30 01:47:59 +04:00
commit_creds ( new ) ;
return 0 ;
}
/**
2017-06-09 18:14:28 +03:00
* aa_restore_previous_label - exit from hat context restoring previous label
2010-07-30 01:47:59 +04:00
* @ token : the token that must be matched to exit hat context
*
2017-06-09 18:14:28 +03:00
* Attempt to return out of a hat to the previous label . The token
2010-07-30 01:47:59 +04:00
* must match the stored token value .
*
* Returns : 0 or error of failure
*/
2017-06-09 18:14:28 +03:00
int aa_restore_previous_label ( u64 token )
2010-07-30 01:47:59 +04:00
{
2017-01-20 12:59:25 +03:00
struct aa_task_ctx * tctx = current_task_ctx ( ) ;
2017-01-20 01:08:36 +03:00
struct aa_cred_ctx * ctx ;
2017-01-20 12:59:25 +03:00
struct cred * new ;
2010-07-30 01:47:59 +04:00
2017-01-20 12:59:25 +03:00
if ( tctx - > token ! = token )
2010-07-30 01:47:59 +04:00
return - EACCES ;
2017-06-09 18:14:28 +03:00
/* ignore restores when there is no saved label */
2017-01-20 12:59:25 +03:00
if ( ! tctx - > previous )
2010-07-30 01:47:59 +04:00
return 0 ;
2017-01-20 12:59:25 +03:00
new = prepare_creds ( ) ;
if ( ! new )
return - ENOMEM ;
ctx = cred_ctx ( new ) ;
2010-07-30 01:47:59 +04:00
2017-06-09 18:14:28 +03:00
aa_put_label ( ctx - > label ) ;
2017-01-20 12:59:25 +03:00
ctx - > label = aa_get_newest_label ( tctx - > previous ) ;
2017-06-09 18:14:28 +03:00
AA_BUG ( ! ctx - > label ) ;
2013-02-19 04:05:34 +04:00
/* clear exec && prev information when restoring to previous context */
2017-01-20 12:59:25 +03:00
aa_clear_task_ctx_trans ( tctx ) ;
2010-07-30 01:47:59 +04:00
commit_creds ( new ) ;
2017-01-20 12:59:25 +03:00
2010-07-30 01:47:59 +04:00
return 0 ;
}