2010-07-29 14:48:05 -07:00
/*
* AppArmor security module
*
* This file contains AppArmor ipc mediation
*
* Copyright ( C ) 1998 - 2008 Novell / SUSE
2017-06-09 14:22:14 -07:00
* Copyright 2009 - 2017 Canonical Ltd .
2010-07-29 14:48:05 -07:00
*
* 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 .
*/
# include <linux/gfp.h>
# include <linux/ptrace.h>
# include "include/audit.h"
# include "include/capability.h"
# include "include/context.h"
# include "include/policy.h"
2011-08-29 10:40:54 +10:00
# include "include/ipc.h"
2017-07-18 22:56:22 -07:00
# include "include/sig_names.h"
2010-07-29 14:48:05 -07:00
2017-06-09 14:38:35 -07:00
/**
* audit_ptrace_mask - convert mask to permission string
* @ buffer : buffer to write string to ( NOT NULL )
* @ mask : permission mask to convert
*/
static void audit_ptrace_mask ( struct audit_buffer * ab , u32 mask )
{
switch ( mask ) {
case MAY_READ :
audit_log_string ( ab , " read " ) ;
break ;
case MAY_WRITE :
audit_log_string ( ab , " trace " ) ;
break ;
case AA_MAY_BE_READ :
audit_log_string ( ab , " readby " ) ;
break ;
case AA_MAY_BE_TRACED :
audit_log_string ( ab , " tracedby " ) ;
break ;
}
}
2010-07-29 14:48:05 -07:00
/* call back to audit ptrace fields */
2017-06-09 08:14:28 -07:00
static void audit_ptrace_cb ( struct audit_buffer * ab , void * va )
2010-07-29 14:48:05 -07:00
{
struct common_audit_data * sa = va ;
2017-06-09 14:22:14 -07:00
2017-06-09 14:38:35 -07:00
if ( aad ( sa ) - > request & AA_PTRACE_PERM_MASK ) {
audit_log_format ( ab , " requested_mask= " ) ;
audit_ptrace_mask ( ab , aad ( sa ) - > request ) ;
if ( aad ( sa ) - > denied & AA_PTRACE_PERM_MASK ) {
audit_log_format ( ab , " denied_mask= " ) ;
audit_ptrace_mask ( ab , aad ( sa ) - > denied ) ;
}
}
2017-01-16 00:43:02 -08:00
audit_log_format ( ab , " peer= " ) ;
2017-06-09 08:14:28 -07:00
aa_label_xaudit ( ab , labels_ns ( aad ( sa ) - > label ) , aad ( sa ) - > peer ,
FLAGS_NONE , GFP_ATOMIC ) ;
2010-07-29 14:48:05 -07:00
}
2017-06-09 14:38:35 -07:00
/* TODO: conditionals */
static int profile_ptrace_perm ( struct aa_profile * profile ,
struct aa_profile * peer , u32 request ,
struct common_audit_data * sa )
{
struct aa_perms perms = { } ;
/* need because of peer in cross check */
if ( profile_unconfined ( profile ) | |
! PROFILE_MEDIATES ( profile , AA_CLASS_PTRACE ) )
return 0 ;
aad ( sa ) - > peer = & peer - > label ;
aa_profile_match_label ( profile , & peer - > label , AA_CLASS_PTRACE , request ,
& perms ) ;
aa_apply_modes_to_perms ( profile , & perms ) ;
return aa_check_perms ( profile , & perms , request , sa , audit_ptrace_cb ) ;
}
2017-06-09 14:22:14 -07:00
static int cross_ptrace_perm ( struct aa_profile * tracer ,
struct aa_profile * tracee , u32 request ,
struct common_audit_data * sa )
2010-07-29 14:48:05 -07:00
{
2017-06-09 14:38:35 -07:00
if ( PROFILE_MEDIATES ( tracer , AA_CLASS_PTRACE ) )
return xcheck ( profile_ptrace_perm ( tracer , tracee , request , sa ) ,
profile_ptrace_perm ( tracee , tracer ,
request < < PTRACE_PERM_SHIFT ,
sa ) ) ;
2017-06-09 14:22:14 -07:00
/* policy uses the old style capability check for ptrace */
if ( profile_unconfined ( tracer ) | | tracer = = tracee )
return 0 ;
2010-07-29 14:48:05 -07:00
2017-06-09 14:22:14 -07:00
aad ( sa ) - > label = & tracer - > label ;
aad ( sa ) - > peer = & tracee - > label ;
aad ( sa ) - > request = 0 ;
aad ( sa ) - > error = aa_capable ( & tracer - > label , CAP_SYS_PTRACE , 1 ) ;
2017-01-16 00:43:02 -08:00
2017-06-09 14:22:14 -07:00
return aa_audit ( AUDIT_APPARMOR_AUTO , tracer , sa , audit_ptrace_cb ) ;
2010-07-29 14:48:05 -07:00
}
/**
* aa_may_ptrace - test if tracer task can trace the tracee
2017-06-09 14:22:14 -07:00
* @ tracer : label of the task doing the tracing ( NOT NULL )
* @ tracee : task label to be traced
* @ request : permission request
2010-07-29 14:48:05 -07:00
*
* Returns : % 0 else error code if permission denied or error
*/
2017-06-09 14:22:14 -07:00
int aa_may_ptrace ( struct aa_label * tracer , struct aa_label * tracee ,
u32 request )
2010-07-29 14:48:05 -07:00
{
2017-06-09 14:22:14 -07:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , OP_PTRACE ) ;
2010-07-29 14:48:05 -07:00
2017-06-09 14:22:14 -07:00
return xcheck_labels_profiles ( tracer , tracee , cross_ptrace_perm ,
request , & sa ) ;
2010-07-29 14:48:05 -07:00
}
2017-07-18 22:56:22 -07:00
static inline int map_signal_num ( int sig )
{
if ( sig > SIGRTMAX )
return SIGUNKNOWN ;
else if ( sig > = SIGRTMIN )
return sig - SIGRTMIN + 128 ; /* rt sigs mapped to 128 */
2017-11-08 08:09:52 -08:00
else if ( sig < MAXMAPPED_SIG )
2017-07-18 22:56:22 -07:00
return sig_map [ sig ] ;
return SIGUNKNOWN ;
}
/**
* audit_file_mask - convert mask to permission string
* @ buffer : buffer to write string to ( NOT NULL )
* @ mask : permission mask to convert
*/
static void audit_signal_mask ( struct audit_buffer * ab , u32 mask )
{
if ( mask & MAY_READ )
audit_log_string ( ab , " receive " ) ;
if ( mask & MAY_WRITE )
audit_log_string ( ab , " send " ) ;
}
/**
* audit_cb - call back for signal specific audit fields
* @ ab : audit_buffer ( NOT NULL )
* @ va : audit struct to audit values of ( NOT NULL )
*/
static void audit_signal_cb ( struct audit_buffer * ab , void * va )
{
struct common_audit_data * sa = va ;
if ( aad ( sa ) - > request & AA_SIGNAL_PERM_MASK ) {
audit_log_format ( ab , " requested_mask= " ) ;
audit_signal_mask ( ab , aad ( sa ) - > request ) ;
if ( aad ( sa ) - > denied & AA_SIGNAL_PERM_MASK ) {
audit_log_format ( ab , " denied_mask= " ) ;
audit_signal_mask ( ab , aad ( sa ) - > denied ) ;
}
}
2017-11-08 08:09:52 -08:00
if ( aad ( sa ) - > signal < MAXMAPPED_SIG )
2017-07-18 22:56:22 -07:00
audit_log_format ( ab , " signal=%s " , sig_names [ aad ( sa ) - > signal ] ) ;
else
audit_log_format ( ab , " signal=rtmin+%d " ,
aad ( sa ) - > signal - 128 ) ;
audit_log_format ( ab , " peer= " ) ;
aa_label_xaudit ( ab , labels_ns ( aad ( sa ) - > label ) , aad ( sa ) - > peer ,
FLAGS_NONE , GFP_ATOMIC ) ;
}
/* TODO: update to handle compound name&name2, conditionals */
static void profile_match_signal ( struct aa_profile * profile , const char * label ,
int signal , struct aa_perms * perms )
{
unsigned int state ;
/* TODO: secondary cache check <profile, profile, perm> */
state = aa_dfa_next ( profile - > policy . dfa ,
profile - > policy . start [ AA_CLASS_SIGNAL ] ,
signal ) ;
state = aa_dfa_match ( profile - > policy . dfa , state , label ) ;
aa_compute_perms ( profile - > policy . dfa , state , perms ) ;
}
static int profile_signal_perm ( struct aa_profile * profile ,
struct aa_profile * peer , u32 request ,
struct common_audit_data * sa )
{
struct aa_perms perms ;
if ( profile_unconfined ( profile ) | |
! PROFILE_MEDIATES ( profile , AA_CLASS_SIGNAL ) )
return 0 ;
aad ( sa ) - > peer = & peer - > label ;
profile_match_signal ( profile , peer - > base . hname , aad ( sa ) - > signal ,
& perms ) ;
aa_apply_modes_to_perms ( profile , & perms ) ;
return aa_check_perms ( profile , & perms , request , sa , audit_signal_cb ) ;
}
static int aa_signal_cross_perm ( struct aa_profile * sender ,
struct aa_profile * target ,
struct common_audit_data * sa )
{
return xcheck ( profile_signal_perm ( sender , target , MAY_WRITE , sa ) ,
profile_signal_perm ( target , sender , MAY_READ , sa ) ) ;
}
int aa_may_signal ( struct aa_label * sender , struct aa_label * target , int sig )
{
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , OP_SIGNAL ) ;
aad ( & sa ) - > signal = map_signal_num ( sig ) ;
return xcheck_labels_profiles ( sender , target , aa_signal_cross_perm ,
& sa ) ;
}