2019-06-01 10:08:55 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2010-07-29 14:47:59 -07:00
/*
* AppArmor security module
*
2017-10-08 00:43:02 -07:00
* This file contains AppArmor task related definitions and mediation
2010-07-29 14:47:59 -07:00
*
2017-10-08 00:43:02 -07:00
* Copyright 2017 Canonical Ltd .
2010-07-29 14:47:59 -07: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 .
*/
2021-11-22 23:28:32 -08:00
# include <linux/gfp.h>
# include <linux/ptrace.h>
# include "include/audit.h"
2017-10-11 01:04:48 -07:00
# include "include/cred.h"
2021-11-22 23:28:32 -08:00
# include "include/policy.h"
2017-10-08 00:43:02 -07:00
# include "include/task.h"
2010-07-29 14:47:59 -07:00
2013-02-18 16:03:34 -08:00
/**
2017-06-09 08:14:28 -07:00
* aa_get_task_label - Get another task ' s label
2013-02-18 16:03:34 -08:00
* @ task : task to query ( NOT NULL )
*
2017-06-09 08:14:28 -07:00
* Returns : counted reference to @ task ' s label
2013-02-18 16:03:34 -08:00
*/
2017-06-09 08:14:28 -07:00
struct aa_label * aa_get_task_label ( struct task_struct * task )
2013-02-18 16:03:34 -08:00
{
2017-06-09 08:14:28 -07:00
struct aa_label * p ;
2013-02-18 16:03:34 -08:00
rcu_read_lock ( ) ;
2022-09-23 17:21:18 +08:00
p = aa_get_newest_cred_label ( __task_cred ( task ) ) ;
2013-02-18 16:03:34 -08:00
rcu_read_unlock ( ) ;
return p ;
}
2010-07-29 14:47:59 -07:00
/**
2017-06-09 08:14:28 -07:00
* aa_replace_current_label - replace the current tasks label
* @ label : new label ( NOT NULL )
2010-07-29 14:47:59 -07:00
*
* Returns : 0 or error on failure
*/
2017-06-09 08:14:28 -07:00
int aa_replace_current_label ( struct aa_label * label )
2010-07-29 14:47:59 -07:00
{
2017-01-27 03:53:53 -08:00
struct aa_label * old = aa_current_raw_label ( ) ;
2017-10-08 18:26:19 -07:00
struct aa_task_ctx * ctx = task_ctx ( current ) ;
2010-07-29 14:47:59 -07:00
struct cred * new ;
2017-01-27 03:53:53 -08:00
2017-06-09 08:14:28 -07:00
AA_BUG ( ! label ) ;
2010-07-29 14:47:59 -07:00
2017-01-27 03:53:53 -08:00
if ( old = = label )
2010-07-29 14:47:59 -07:00
return 0 ;
2017-01-16 00:42:59 -08:00
if ( current_cred ( ) ! = current_real_cred ( ) )
return - EBUSY ;
2010-07-29 14:47:59 -07:00
new = prepare_creds ( ) ;
if ( ! new )
return - ENOMEM ;
2017-10-08 18:26:19 -07:00
if ( ctx - > nnp & & label_is_stale ( ctx - > nnp ) ) {
struct aa_label * tmp = ctx - > nnp ;
ctx - > nnp = aa_get_newest_label ( tmp ) ;
aa_put_label ( tmp ) ;
}
2017-01-27 03:53:53 -08:00
if ( unconfined ( label ) | | ( labels_ns ( old ) ! = labels_ns ( label ) ) )
/*
* if switching to unconfined or a different label namespace
2010-07-29 14:47:59 -07:00
* clear out context state
*/
2017-10-08 00:43:02 -07:00
aa_clear_task_ctx_trans ( task_ctx ( current ) ) ;
2013-02-18 16:05:34 -08:00
2017-01-16 00:43:00 -08:00
/*
2017-01-27 03:53:53 -08:00
* be careful switching cred label , when racing replacement it
* is possible that the cred labels ' s - > proxy - > label is the reference
* keeping @ label valid , so make sure to get its reference before
* dropping the reference on the cred ' s label
2017-01-16 00:43:00 -08:00
*/
2017-06-09 08:14:28 -07:00
aa_get_label ( label ) ;
2017-01-27 03:53:53 -08:00
aa_put_label ( cred_label ( new ) ) ;
2018-09-21 17:17:59 -07:00
set_cred_label ( new , label ) ;
2010-07-29 14:47:59 -07:00
commit_creds ( new ) ;
return 0 ;
}
2017-10-08 00:43:02 -07:00
2010-07-29 14:47:59 -07:00
/**
* aa_set_current_onexec - set the tasks change_profile to happen onexec
2017-06-09 08:14:28 -07:00
* @ label : system label to set at exec ( MAYBE NULL to clear value )
* @ stack : whether stacking should be done
2010-07-29 14:47:59 -07:00
* Returns : 0 or error on failure
*/
2017-06-09 08:14:28 -07:00
int aa_set_current_onexec ( struct aa_label * label , bool stack )
2010-07-29 14:47:59 -07:00
{
2017-10-08 00:43:02 -07:00
struct aa_task_ctx * ctx = task_ctx ( current ) ;
2010-07-29 14:47:59 -07:00
2017-06-09 08:14:28 -07:00
aa_get_label ( label ) ;
2017-01-20 01:59:25 -08:00
aa_put_label ( ctx - > onexec ) ;
2017-06-09 08:14:28 -07:00
ctx - > onexec = label ;
ctx - > token = stack ;
2010-07-29 14:47:59 -07:00
return 0 ;
}
/**
* aa_set_current_hat - set the current tasks hat
2017-06-09 08:14:28 -07:00
* @ label : label to set as the current hat ( NOT NULL )
2010-07-29 14:47:59 -07: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 08:14:28 -07:00
int aa_set_current_hat ( struct aa_label * label , u64 token )
2010-07-29 14:47:59 -07:00
{
2017-10-08 00:43:02 -07:00
struct aa_task_ctx * ctx = task_ctx ( current ) ;
2017-01-27 03:53:53 -08:00
struct cred * new ;
2017-01-20 01:59:25 -08:00
2017-01-27 03:53:53 -08:00
new = prepare_creds ( ) ;
2010-07-29 14:47:59 -07:00
if ( ! new )
return - ENOMEM ;
2017-06-09 08:14:28 -07:00
AA_BUG ( ! label ) ;
2010-07-29 14:47:59 -07:00
2017-01-27 04:09:40 -08:00
if ( ! ctx - > previous ) {
2010-07-29 14:47:59 -07:00
/* transfer refcount */
2017-01-27 04:09:40 -08:00
ctx - > previous = cred_label ( new ) ;
ctx - > token = token ;
} else if ( ctx - > token = = token ) {
2017-01-27 03:53:53 -08:00
aa_put_label ( cred_label ( new ) ) ;
2010-07-29 14:47:59 -07:00
} else {
2017-01-16 00:43:00 -08:00
/* previous_profile && ctx->token != token */
2010-07-29 14:47:59 -07:00
abort_creds ( new ) ;
return - EACCES ;
}
2017-01-20 01:59:25 -08:00
2018-09-21 17:17:59 -07:00
set_cred_label ( new , aa_get_newest_label ( label ) ) ;
2010-07-29 14:47:59 -07:00
/* clear exec on switching context */
2017-01-27 04:09:40 -08:00
aa_put_label ( ctx - > onexec ) ;
ctx - > onexec = NULL ;
2010-07-29 14:47:59 -07:00
commit_creds ( new ) ;
return 0 ;
}
/**
2017-06-09 08:14:28 -07:00
* aa_restore_previous_label - exit from hat context restoring previous label
2010-07-29 14:47:59 -07:00
* @ token : the token that must be matched to exit hat context
*
2017-06-09 08:14:28 -07:00
* Attempt to return out of a hat to the previous label . The token
2010-07-29 14:47:59 -07:00
* must match the stored token value .
*
* Returns : 0 or error of failure
*/
2017-06-09 08:14:28 -07:00
int aa_restore_previous_label ( u64 token )
2010-07-29 14:47:59 -07:00
{
2017-10-08 00:43:02 -07:00
struct aa_task_ctx * ctx = task_ctx ( current ) ;
2017-01-20 01:59:25 -08:00
struct cred * new ;
2010-07-29 14:47:59 -07:00
2017-01-27 04:09:40 -08:00
if ( ctx - > token ! = token )
2010-07-29 14:47:59 -07:00
return - EACCES ;
2017-06-09 08:14:28 -07:00
/* ignore restores when there is no saved label */
2017-01-27 04:09:40 -08:00
if ( ! ctx - > previous )
2010-07-29 14:47:59 -07:00
return 0 ;
2017-01-20 01:59:25 -08:00
new = prepare_creds ( ) ;
if ( ! new )
return - ENOMEM ;
2010-07-29 14:47:59 -07:00
2017-01-27 03:53:53 -08:00
aa_put_label ( cred_label ( new ) ) ;
2018-09-21 17:17:59 -07:00
set_cred_label ( new , aa_get_newest_label ( ctx - > previous ) ) ;
2017-01-27 03:53:53 -08:00
AA_BUG ( ! cred_label ( new ) ) ;
2013-02-18 16:05:34 -08:00
/* clear exec && prev information when restoring to previous context */
2017-01-27 04:09:40 -08:00
aa_clear_task_ctx_trans ( ctx ) ;
2010-07-29 14:47:59 -07:00
commit_creds ( new ) ;
2017-01-20 01:59:25 -08:00
2010-07-29 14:47:59 -07:00
return 0 ;
}
2021-11-22 23:28:32 -08:00
/**
* audit_ptrace_mask - convert mask to permission string
* @ mask : permission mask to convert
*
* Returns : pointer to static string
*/
static const char * audit_ptrace_mask ( u32 mask )
{
switch ( mask ) {
case MAY_READ :
return " read " ;
case MAY_WRITE :
return " trace " ;
case AA_MAY_BE_READ :
return " readby " ;
case AA_MAY_BE_TRACED :
return " tracedby " ;
}
return " " ;
}
/* call back to audit ptrace fields */
static void audit_ptrace_cb ( struct audit_buffer * ab , void * va )
{
struct common_audit_data * sa = va ;
if ( aad ( sa ) - > request & AA_PTRACE_PERM_MASK ) {
audit_log_format ( ab , " requested_mask= \" %s \" " ,
audit_ptrace_mask ( aad ( sa ) - > request ) ) ;
if ( aad ( sa ) - > denied & AA_PTRACE_PERM_MASK ) {
audit_log_format ( ab , " denied_mask= \" %s \" " ,
audit_ptrace_mask ( aad ( sa ) - > denied ) ) ;
}
}
audit_log_format ( ab , " peer= " ) ;
aa_label_xaudit ( ab , labels_ns ( aad ( sa ) - > label ) , aad ( sa ) - > peer ,
FLAGS_NONE , GFP_ATOMIC ) ;
}
2022-07-29 17:17:31 -07:00
/* assumes check for RULE_MEDIATES is already done */
2021-11-22 23:28:32 -08:00
/* TODO: conditionals */
static int profile_ptrace_perm ( struct aa_profile * profile ,
struct aa_label * peer , u32 request ,
struct common_audit_data * sa )
{
2022-09-05 20:47:36 -07:00
struct aa_ruleset * rules = list_first_entry ( & profile - > rules ,
typeof ( * rules ) , list ) ;
2021-11-22 23:28:32 -08:00
struct aa_perms perms = { } ;
aad ( sa ) - > peer = peer ;
2022-09-05 20:47:36 -07:00
aa_profile_match_label ( profile , rules , peer , AA_CLASS_PTRACE , request ,
& perms ) ;
2021-11-22 23:28:32 -08:00
aa_apply_modes_to_perms ( profile , & perms ) ;
return aa_check_perms ( profile , & perms , request , sa , audit_ptrace_cb ) ;
}
static int profile_tracee_perm ( struct aa_profile * tracee ,
struct aa_label * tracer , u32 request ,
struct common_audit_data * sa )
{
if ( profile_unconfined ( tracee ) | | unconfined ( tracer ) | |
2022-09-05 20:47:36 -07:00
! ANY_RULE_MEDIATES ( & tracee - > rules , AA_CLASS_PTRACE ) )
2021-11-22 23:28:32 -08:00
return 0 ;
return profile_ptrace_perm ( tracee , tracer , request , sa ) ;
}
static int profile_tracer_perm ( struct aa_profile * tracer ,
struct aa_label * tracee , u32 request ,
struct common_audit_data * sa )
{
if ( profile_unconfined ( tracer ) )
return 0 ;
2022-09-05 20:47:36 -07:00
if ( ANY_RULE_MEDIATES ( & tracer - > rules , AA_CLASS_PTRACE ) )
2021-11-22 23:28:32 -08:00
return profile_ptrace_perm ( tracer , tracee , request , sa ) ;
/* profile uses the old style capability check for ptrace */
if ( & tracer - > label = = tracee )
return 0 ;
aad ( sa ) - > label = & tracer - > label ;
aad ( sa ) - > peer = tracee ;
aad ( sa ) - > request = 0 ;
aad ( sa ) - > error = aa_capable ( & tracer - > label , CAP_SYS_PTRACE ,
CAP_OPT_NONE ) ;
return aa_audit ( AUDIT_APPARMOR_AUTO , tracer , sa , audit_ptrace_cb ) ;
}
/**
* aa_may_ptrace - test if tracer task can trace the tracee
* @ tracer : label of the task doing the tracing ( NOT NULL )
* @ tracee : task label to be traced
* @ request : permission request
*
* Returns : % 0 else error code if permission denied or error
*/
int aa_may_ptrace ( struct aa_label * tracer , struct aa_label * tracee ,
u32 request )
{
struct aa_profile * profile ;
u32 xrequest = request < < PTRACE_PERM_SHIFT ;
2022-04-19 16:25:55 -07:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , AA_CLASS_PTRACE , OP_PTRACE ) ;
2021-11-22 23:28:32 -08:00
return xcheck_labels ( tracer , tracee , profile ,
profile_tracer_perm ( profile , tracee , request , & sa ) ,
profile_tracee_perm ( profile , tracer , xrequest , & sa ) ) ;
}