2010-07-30 01:48:05 +04:00
/*
* AppArmor security module
*
* This file contains AppArmor resource mediation and attachment
*
* 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 .
*/
# include <linux/audit.h>
2017-06-10 00:15:20 +03:00
# include <linux/security.h>
2010-07-30 01:48:05 +04:00
# include "include/audit.h"
2013-02-19 04:07:34 +04:00
# include "include/context.h"
2010-07-30 01:48:05 +04:00
# include "include/resource.h"
# include "include/policy.h"
/*
* Table of rlimit names : we generate it from resource . h .
*/
# include "rlim_names.h"
2017-05-25 16:23:42 +03:00
struct aa_sfs_entry aa_sfs_entry_rlimit [ ] = {
AA_SFS_FILE_STRING ( " mask " , AA_SFS_RLIMIT_MASK ) ,
2012-01-27 04:29:23 +04:00
{ }
} ;
2010-07-30 01:48:05 +04:00
/* audit callback for resource specific fields */
static void audit_cb ( struct audit_buffer * ab , void * va )
{
struct common_audit_data * sa = va ;
audit_log_format ( ab , " rlimit=%s value=%lu " ,
2017-01-16 11:43:02 +03:00
rlim_names [ aad ( sa ) - > rlim . rlim ] , aad ( sa ) - > rlim . max ) ;
2017-06-10 00:15:20 +03:00
if ( aad ( sa ) - > peer ) {
audit_log_format ( ab , " peer= " ) ;
aa_label_xaudit ( ab , labels_ns ( aad ( sa ) - > label ) , aad ( sa ) - > peer ,
FLAGS_NONE , GFP_ATOMIC ) ;
}
2010-07-30 01:48:05 +04:00
}
/**
* audit_resource - audit setting resource limit
* @ profile : profile being enforced ( NOT NULL )
* @ resoure : rlimit being auditing
* @ value : value being set
* @ error : error value
*
* Returns : 0 or sa - > error else other error code on failure
*/
static int audit_resource ( struct aa_profile * profile , unsigned int resource ,
2017-06-10 00:15:20 +03:00
unsigned long value , struct aa_label * peer ,
const char * info , int error )
2010-07-30 01:48:05 +04:00
{
2017-01-16 11:43:02 +03:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , OP_SETRLIMIT ) ;
2010-07-30 01:48:05 +04:00
2017-01-16 11:43:02 +03:00
aad ( & sa ) - > rlim . rlim = resource ;
aad ( & sa ) - > rlim . max = value ;
2017-06-10 00:15:20 +03:00
aad ( & sa ) - > peer = peer ;
aad ( & sa ) - > info = info ;
2017-01-16 11:43:02 +03:00
aad ( & sa ) - > error = error ;
2017-06-10 00:15:20 +03:00
2017-01-16 11:43:02 +03:00
return aa_audit ( AUDIT_APPARMOR_AUTO , profile , & sa , audit_cb ) ;
2010-07-30 01:48:05 +04:00
}
/**
* aa_map_resouce - map compiled policy resource to internal #
* @ resource : flattened policy resource number
*
* Returns : resource # for the current architecture .
*
* rlimit resource can vary based on architecture , map the compiled policy
* resource # to the internal representation for the architecture .
*/
int aa_map_resource ( int resource )
{
return rlim_map [ resource ] ;
}
2017-06-10 00:15:20 +03:00
static int profile_setrlimit ( struct aa_profile * profile , unsigned int resource ,
struct rlimit * new_rlim )
{
int e = 0 ;
if ( profile - > rlimits . mask & ( 1 < < resource ) & & new_rlim - > rlim_max >
profile - > rlimits . limits [ resource ] . rlim_max )
e = - EACCES ;
return audit_resource ( profile , resource , new_rlim - > rlim_max , NULL , NULL ,
e ) ;
}
2010-07-30 01:48:05 +04:00
/**
* aa_task_setrlimit - test permission to set an rlimit
2017-06-10 00:15:20 +03:00
* @ label - label confining the task ( NOT NULL )
2010-09-06 21:10:20 +04:00
* @ task - task the resource is being set on
2010-07-30 01:48:05 +04:00
* @ resource - the resource being set
* @ new_rlim - the new resource limit ( NOT NULL )
*
* Control raising the processes hard limit .
*
* Returns : 0 or error code if setting resource failed
*/
2017-06-10 00:15:20 +03:00
int aa_task_setrlimit ( struct aa_label * label , struct task_struct * task ,
2010-09-06 21:10:20 +04:00
unsigned int resource , struct rlimit * new_rlim )
2010-07-30 01:48:05 +04:00
{
2017-06-10 00:15:20 +03:00
struct aa_profile * profile ;
struct aa_label * peer ;
2010-07-30 01:48:05 +04:00
int error = 0 ;
2013-02-19 04:07:34 +04:00
rcu_read_lock ( ) ;
2017-06-10 00:15:20 +03:00
peer = aa_get_newest_cred_label ( __task_cred ( task ) ) ;
2013-02-19 04:07:34 +04:00
rcu_read_unlock ( ) ;
2010-09-06 21:10:20 +04:00
/* TODO: extend resource control to handle other (non current)
2013-02-19 04:07:34 +04:00
* profiles . AppArmor rules currently have the implicit assumption
* that the task is setting the resource of a task confined with
2015-11-06 23:17:30 +03:00
* the same profile or that the task setting the resource of another
* task has CAP_SYS_RESOURCE .
2010-09-06 21:10:20 +04:00
*/
2010-07-30 01:48:05 +04:00
2017-06-10 00:15:20 +03:00
if ( label ! = peer & &
! aa_capable ( label , CAP_SYS_RESOURCE , SECURITY_CAP_NOAUDIT ) )
error = fn_for_each ( label , profile ,
audit_resource ( profile , resource ,
new_rlim - > rlim_max , peer ,
" cap_sys_resoure " , - EACCES ) ) ;
else
error = fn_for_each_confined ( label , profile ,
profile_setrlimit ( profile , resource , new_rlim ) ) ;
aa_put_label ( peer ) ;
return error ;
2010-07-30 01:48:05 +04:00
}
/**
* __aa_transition_rlimits - apply new profile rlimits
2017-06-10 00:15:20 +03:00
* @ old_l : old label on task ( NOT NULL )
* @ new_l : new label with rlimits to apply ( NOT NULL )
2010-07-30 01:48:05 +04:00
*/
2017-06-10 00:15:20 +03:00
void __aa_transition_rlimits ( struct aa_label * old_l , struct aa_label * new_l )
2010-07-30 01:48:05 +04:00
{
unsigned int mask = 0 ;
struct rlimit * rlim , * initrlim ;
2017-06-10 00:15:20 +03:00
struct aa_profile * old , * new ;
struct label_it i ;
old = labels_profile ( old_l ) ;
new = labels_profile ( new_l ) ;
2010-07-30 01:48:05 +04:00
2017-06-10 00:15:20 +03:00
/* for any rlimits the profile controlled, reset the soft limit
* to the lesser of the tasks hard limit and the init tasks soft limit
2010-07-30 01:48:05 +04:00
*/
2017-06-10 00:15:20 +03:00
label_for_each_confined ( i , old_l , old ) {
if ( old - > rlimits . mask ) {
int j ;
for ( j = 0 , mask = 1 ; j < RLIM_NLIMITS ; j + + ,
mask < < = 1 ) {
if ( old - > rlimits . mask & mask ) {
rlim = current - > signal - > rlim + j ;
initrlim = init_task . signal - > rlim + j ;
rlim - > rlim_cur = min ( rlim - > rlim_max ,
initrlim - > rlim_cur ) ;
}
2010-07-30 01:48:05 +04:00
}
}
}
/* set any new hard limits as dictated by the new profile */
2017-06-10 00:15:20 +03:00
label_for_each_confined ( i , new_l , new ) {
int j ;
2010-07-30 01:48:05 +04:00
2017-06-10 00:15:20 +03:00
if ( ! new - > rlimits . mask )
continue ;
for ( j = 0 , mask = 1 ; j < RLIM_NLIMITS ; j + + , mask < < = 1 ) {
if ( ! ( new - > rlimits . mask & mask ) )
continue ;
rlim = current - > signal - > rlim + j ;
rlim - > rlim_max = min ( rlim - > rlim_max ,
new - > rlimits . limits [ j ] . rlim_max ) ;
/* soft limit should not exceed hard limit */
rlim - > rlim_cur = min ( rlim - > rlim_cur , rlim - > rlim_max ) ;
}
2010-07-30 01:48:05 +04:00
}
}