2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-07-30 01:48:05 +04:00
/*
* AppArmor security module
*
* This file contains AppArmor ipc mediation
*
* Copyright ( C ) 1998 - 2008 Novell / SUSE
2017-06-10 00:22:14 +03:00
* Copyright 2009 - 2017 Canonical Ltd .
2010-07-30 01:48:05 +04:00
*/
# include <linux/gfp.h>
# include <linux/ptrace.h>
# include "include/audit.h"
# include "include/capability.h"
2017-10-11 11:04:48 +03:00
# include "include/cred.h"
2010-07-30 01:48:05 +04:00
# include "include/policy.h"
2011-08-29 04:40:54 +04:00
# include "include/ipc.h"
2017-07-19 08:56:22 +03:00
# include "include/sig_names.h"
2010-07-30 01:48:05 +04:00
2017-06-10 00:38:35 +03: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-30 01:48:05 +04:00
/* call back to audit ptrace fields */
2017-06-09 18:14:28 +03:00
static void audit_ptrace_cb ( struct audit_buffer * ab , void * va )
2010-07-30 01:48:05 +04:00
{
struct common_audit_data * sa = va ;
2017-06-10 00:22:14 +03:00
2017-06-10 00:38:35 +03: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 11:43:02 +03:00
audit_log_format ( ab , " peer= " ) ;
2017-06-09 18:14:28 +03:00
aa_label_xaudit ( ab , labels_ns ( aad ( sa ) - > label ) , aad ( sa ) - > peer ,
FLAGS_NONE , GFP_ATOMIC ) ;
2010-07-30 01:48:05 +04:00
}
2017-12-09 04:43:18 +03:00
/* assumes check for PROFILE_MEDIATES is already done */
2017-06-10 00:38:35 +03:00
/* TODO: conditionals */
static int profile_ptrace_perm ( struct aa_profile * profile ,
2017-12-09 04:43:18 +03:00
struct aa_label * peer , u32 request ,
struct common_audit_data * sa )
2017-06-10 00:38:35 +03:00
{
struct aa_perms perms = { } ;
2017-12-09 04:43:18 +03:00
aad ( sa ) - > peer = peer ;
aa_profile_match_label ( profile , peer , AA_CLASS_PTRACE , request ,
2017-06-10 00:38:35 +03:00
& perms ) ;
aa_apply_modes_to_perms ( profile , & perms ) ;
return aa_check_perms ( profile , & perms , request , sa , audit_ptrace_cb ) ;
}
2017-12-09 04:43:18 +03:00
static int profile_tracee_perm ( struct aa_profile * tracee ,
struct aa_label * tracer , u32 request ,
struct common_audit_data * sa )
2010-07-30 01:48:05 +04:00
{
2017-12-09 04:43:18 +03:00
if ( profile_unconfined ( tracee ) | | unconfined ( tracer ) | |
! PROFILE_MEDIATES ( tracee , AA_CLASS_PTRACE ) )
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 ;
2017-06-10 00:38:35 +03:00
if ( PROFILE_MEDIATES ( tracer , AA_CLASS_PTRACE ) )
2017-12-09 04:43:18 +03:00
return profile_ptrace_perm ( tracer , tracee , request , sa ) ;
/* profile uses the old style capability check for ptrace */
if ( & tracer - > label = = tracee )
2017-06-10 00:22:14 +03:00
return 0 ;
2010-07-30 01:48:05 +04:00
2017-06-10 00:22:14 +03:00
aad ( sa ) - > label = & tracer - > label ;
2017-12-09 04:43:18 +03:00
aad ( sa ) - > peer = tracee ;
2017-06-10 00:22:14 +03:00
aad ( sa ) - > request = 0 ;
2019-01-08 03:10:53 +03:00
aad ( sa ) - > error = aa_capable ( & tracer - > label , CAP_SYS_PTRACE ,
CAP_OPT_NONE ) ;
2017-01-16 11:43:02 +03:00
2017-06-10 00:22:14 +03:00
return aa_audit ( AUDIT_APPARMOR_AUTO , tracer , sa , audit_ptrace_cb ) ;
2010-07-30 01:48:05 +04:00
}
/**
* aa_may_ptrace - test if tracer task can trace the tracee
2017-06-10 00:22:14 +03:00
* @ tracer : label of the task doing the tracing ( NOT NULL )
* @ tracee : task label to be traced
* @ request : permission request
2010-07-30 01:48:05 +04:00
*
* Returns : % 0 else error code if permission denied or error
*/
2017-06-10 00:22:14 +03:00
int aa_may_ptrace ( struct aa_label * tracer , struct aa_label * tracee ,
u32 request )
2010-07-30 01:48:05 +04:00
{
2017-12-09 04:43:18 +03:00
struct aa_profile * profile ;
u32 xrequest = request < < PTRACE_PERM_SHIFT ;
2017-06-10 00:22:14 +03:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , OP_PTRACE ) ;
2010-07-30 01:48:05 +04:00
2017-12-09 04:43:18 +03:00
return xcheck_labels ( tracer , tracee , profile ,
profile_tracer_perm ( profile , tracee , request , & sa ) ,
profile_tracee_perm ( profile , tracer , xrequest , & sa ) ) ;
2010-07-30 01:48:05 +04:00
}
2017-07-19 08:56:22 +03:00
static inline int map_signal_num ( int sig )
{
if ( sig > SIGRTMAX )
return SIGUNKNOWN ;
else if ( sig > = SIGRTMIN )
2018-02-01 14:32:02 +03:00
return sig - SIGRTMIN + SIGRT_BASE ;
2017-11-08 19:09:52 +03:00
else if ( sig < MAXMAPPED_SIG )
2017-07-19 08:56:22 +03: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 ) ;
}
}
2018-02-01 14:32:02 +03:00
if ( aad ( sa ) - > signal = = SIGUNKNOWN )
audit_log_format ( ab , " signal=unknown(%d) " ,
aad ( sa ) - > unmappedsig ) ;
else if ( aad ( sa ) - > signal < MAXMAPPED_SIGNAME )
2017-07-19 08:56:22 +03:00
audit_log_format ( ab , " signal=%s " , sig_names [ aad ( sa ) - > signal ] ) ;
else
audit_log_format ( ab , " signal=rtmin+%d " ,
2018-02-01 14:32:02 +03:00
aad ( sa ) - > signal - SIGRT_BASE ) ;
2017-07-19 08:56:22 +03:00
audit_log_format ( ab , " peer= " ) ;
aa_label_xaudit ( ab , labels_ns ( aad ( sa ) - > label ) , aad ( sa ) - > peer ,
FLAGS_NONE , GFP_ATOMIC ) ;
}
static int profile_signal_perm ( struct aa_profile * profile ,
2017-12-12 12:02:13 +03:00
struct aa_label * peer , u32 request ,
2017-07-19 08:56:22 +03:00
struct common_audit_data * sa )
{
struct aa_perms perms ;
2017-12-12 12:02:13 +03:00
unsigned int state ;
2017-07-19 08:56:22 +03:00
if ( profile_unconfined ( profile ) | |
! PROFILE_MEDIATES ( profile , AA_CLASS_SIGNAL ) )
return 0 ;
2017-12-12 12:02:13 +03:00
aad ( sa ) - > peer = peer ;
/* TODO: secondary cache check <profile, profile, perm> */
state = aa_dfa_next ( profile - > policy . dfa ,
profile - > policy . start [ AA_CLASS_SIGNAL ] ,
aad ( sa ) - > signal ) ;
aa_label_match ( profile , peer , state , false , request , & perms ) ;
2017-07-19 08:56:22 +03:00
aa_apply_modes_to_perms ( profile , & perms ) ;
return aa_check_perms ( profile , & perms , request , sa , audit_signal_cb ) ;
}
int aa_may_signal ( struct aa_label * sender , struct aa_label * target , int sig )
{
2017-12-12 12:02:13 +03:00
struct aa_profile * profile ;
2017-07-19 08:56:22 +03:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , OP_SIGNAL ) ;
aad ( & sa ) - > signal = map_signal_num ( sig ) ;
2018-02-01 14:32:02 +03:00
aad ( & sa ) - > unmappedsig = sig ;
2017-12-12 12:02:13 +03:00
return xcheck_labels ( sender , target , profile ,
profile_signal_perm ( profile , target , MAY_WRITE , & sa ) ,
profile_signal_perm ( profile , sender , MAY_READ , & sa ) ) ;
2017-07-19 08:56:22 +03:00
}