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 capability mediation functions
*
* Copyright ( C ) 1998 - 2008 Novell / SUSE
* Copyright 2009 - 2010 Canonical Ltd .
*/
# include <linux/capability.h>
# include <linux/errno.h>
# include <linux/gfp.h>
2017-01-16 11:43:08 +03:00
# include <linux/security.h>
2010-07-30 01:48:05 +04:00
# include "include/apparmor.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"
# include "include/audit.h"
/*
* Table of capability names : we generate it from capabilities . h .
*/
# include "capability_names.h"
2017-05-25 16:23:42 +03:00
struct aa_sfs_entry aa_sfs_entry_caps [ ] = {
AA_SFS_FILE_STRING ( " mask " , AA_SFS_CAPS_MASK ) ,
2013-08-14 22:27:32 +04:00
{ }
} ;
2010-07-30 01:48:05 +04:00
struct audit_cache {
struct aa_profile * profile ;
kernel_cap_t caps ;
} ;
static DEFINE_PER_CPU ( struct audit_cache , audit_cache ) ;
/**
* audit_cb - call back for capability components of audit struct
* @ ab - audit buffer ( NOT NULL )
* @ va - audit struct to audit data from ( NOT NULL )
*/
static void audit_cb ( struct audit_buffer * ab , void * va )
{
struct common_audit_data * sa = va ;
2017-06-10 00:07:02 +03:00
2010-07-30 01:48:05 +04:00
audit_log_format ( ab , " capname= " ) ;
audit_log_untrustedstring ( ab , capability_names [ sa - > u . cap ] ) ;
}
/**
* audit_caps - audit a capability
2017-06-10 00:07:02 +03:00
* @ sa : audit data
2013-10-08 16:37:18 +04:00
* @ profile : profile being tested for confinement ( NOT NULL )
2010-07-30 01:48:05 +04:00
* @ cap : capability tested
* @ error : error code returned by test
*
* Do auditing of capability and handle , audit / complain / kill modes switching
* and duplicate message elimination .
*
* Returns : 0 or sa - > error on success , error code on failure
*/
2017-06-10 00:07:02 +03:00
static int audit_caps ( struct common_audit_data * sa , struct aa_profile * profile ,
int cap , int error )
2010-07-30 01:48:05 +04:00
{
struct audit_cache * ent ;
int type = AUDIT_APPARMOR_AUTO ;
2017-06-10 00:07:02 +03:00
aad ( sa ) - > error = error ;
2010-07-30 01:48:05 +04:00
if ( likely ( ! error ) ) {
/* test if auditing is being forced */
if ( likely ( ( AUDIT_MODE ( profile ) ! = AUDIT_ALL ) & &
! cap_raised ( profile - > caps . audit , cap ) ) )
return 0 ;
type = AUDIT_APPARMOR_AUDIT ;
} else if ( KILL_MODE ( profile ) | |
cap_raised ( profile - > caps . kill , cap ) ) {
type = AUDIT_APPARMOR_KILL ;
} else if ( cap_raised ( profile - > caps . quiet , cap ) & &
AUDIT_MODE ( profile ) ! = AUDIT_NOQUIET & &
AUDIT_MODE ( profile ) ! = AUDIT_ALL ) {
/* quiet auditing */
return error ;
}
/* Do simple duplicate message elimination */
ent = & get_cpu_var ( audit_cache ) ;
if ( profile = = ent - > profile & & cap_raised ( ent - > caps , cap ) ) {
put_cpu_var ( audit_cache ) ;
if ( COMPLAIN_MODE ( profile ) )
return complain_error ( error ) ;
return error ;
} else {
aa_put_profile ( ent - > profile ) ;
ent - > profile = aa_get_profile ( profile ) ;
cap_raise ( ent - > caps , cap ) ;
}
put_cpu_var ( audit_cache ) ;
2017-06-10 00:07:02 +03:00
return aa_audit ( type , profile , sa , audit_cb ) ;
2010-07-30 01:48:05 +04:00
}
/**
* profile_capable - test if profile allows use of capability @ cap
* @ profile : profile being enforced ( NOT NULL , NOT unconfined )
* @ cap : capability to test if allowed
2019-01-08 03:10:53 +03:00
* @ opts : CAP_OPT_NOAUDIT bit determines whether audit record is generated
2017-06-10 00:07:02 +03:00
* @ sa : audit data ( MAY BE NULL indicating no auditing )
2010-07-30 01:48:05 +04:00
*
* Returns : 0 if allowed else - EPERM
*/
2019-01-08 03:10:53 +03:00
static int profile_capable ( struct aa_profile * profile , int cap ,
unsigned int opts , struct common_audit_data * sa )
2010-07-30 01:48:05 +04:00
{
2017-06-10 00:07:02 +03:00
int error ;
if ( cap_raised ( profile - > caps . allow , cap ) & &
! cap_raised ( profile - > caps . denied , cap ) )
error = 0 ;
else
error = - EPERM ;
2019-01-08 03:10:53 +03:00
if ( opts & CAP_OPT_NOAUDIT ) {
2017-06-10 00:07:02 +03:00
if ( ! COMPLAIN_MODE ( profile ) )
return error ;
/* audit the cap request in complain mode but note that it
* should be optional .
*/
aad ( sa ) - > info = " optional: no audit " ;
}
return audit_caps ( sa , profile , cap , error ) ;
2010-07-30 01:48:05 +04:00
}
/**
* aa_capable - test permission to use capability
2017-06-10 00:07:02 +03:00
* @ label : label being tested for capability ( NOT NULL )
2010-07-30 01:48:05 +04:00
* @ cap : capability to be tested
2019-01-08 03:10:53 +03:00
* @ opts : CAP_OPT_NOAUDIT bit determines whether audit record is generated
2010-07-30 01:48:05 +04:00
*
* Look up capability in profile capability set .
*
* Returns : 0 on success , or else an error code .
*/
2019-01-08 03:10:53 +03:00
int aa_capable ( struct aa_label * label , int cap , unsigned int opts )
2010-07-30 01:48:05 +04:00
{
2017-06-10 00:07:02 +03:00
struct aa_profile * profile ;
int error = 0 ;
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_CAP , OP_CAPABLE ) ;
2010-07-30 01:48:05 +04:00
2017-06-10 00:07:02 +03:00
sa . u . cap = cap ;
error = fn_for_each_confined ( label , profile ,
2019-01-08 03:10:53 +03:00
profile_capable ( profile , cap , opts , & sa ) ) ;
2010-07-30 01:48:05 +04:00
2017-06-10 00:07:02 +03:00
return error ;
2010-07-30 01:48:05 +04:00
}