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>
# 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 ) ;
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 ,
unsigned long value , int error )
{
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 ;
aad ( & sa ) - > error = error ;
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 ] ;
}
/**
* aa_task_setrlimit - test permission to set an rlimit
* @ profile - profile 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
*/
2010-09-06 21:10:20 +04:00
int aa_task_setrlimit ( struct aa_profile * profile , struct task_struct * task ,
unsigned int resource , struct rlimit * new_rlim )
2010-07-30 01:48:05 +04:00
{
2013-02-19 04:07:34 +04:00
struct aa_profile * task_profile ;
2010-07-30 01:48:05 +04:00
int error = 0 ;
2013-02-19 04:07:34 +04:00
rcu_read_lock ( ) ;
task_profile = aa_get_profile ( aa_cred_profile ( __task_cred ( task ) ) ) ;
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
*/
2015-11-06 23:17:30 +03:00
if ( ( profile ! = task_profile & &
aa_capable ( profile , CAP_SYS_RESOURCE , 1 ) ) | |
2010-09-06 21:10:20 +04:00
( profile - > rlimits . mask & ( 1 < < resource ) & &
new_rlim - > rlim_max > profile - > rlimits . limits [ resource ] . rlim_max ) )
error = - EACCES ;
2010-07-30 01:48:05 +04:00
2013-02-19 04:07:34 +04:00
aa_put_profile ( task_profile ) ;
2010-09-06 21:10:20 +04:00
return audit_resource ( profile , resource , new_rlim - > rlim_max , error ) ;
2010-07-30 01:48:05 +04:00
}
/**
* __aa_transition_rlimits - apply new profile rlimits
* @ old : old profile on task ( NOT NULL )
* @ new : new profile with rlimits to apply ( NOT NULL )
*/
void __aa_transition_rlimits ( struct aa_profile * old , struct aa_profile * new )
{
unsigned int mask = 0 ;
struct rlimit * rlim , * initrlim ;
int i ;
/* for any rlimits the profile controlled reset the soft limit
* to the less of the tasks hard limit and the init tasks soft limit
*/
if ( old - > rlimits . mask ) {
for ( i = 0 , mask = 1 ; i < RLIM_NLIMITS ; i + + , mask < < = 1 ) {
if ( old - > rlimits . mask & mask ) {
rlim = current - > signal - > rlim + i ;
initrlim = init_task . signal - > rlim + i ;
rlim - > rlim_cur = min ( rlim - > rlim_max ,
initrlim - > rlim_cur ) ;
}
}
}
/* set any new hard limits as dictated by the new profile */
if ( ! new - > rlimits . mask )
return ;
for ( i = 0 , mask = 1 ; i < RLIM_NLIMITS ; i + + , mask < < = 1 ) {
if ( ! ( new - > rlimits . mask & mask ) )
continue ;
rlim = current - > signal - > rlim + i ;
rlim - > rlim_max = min ( rlim - > rlim_max ,
new - > rlimits . limits [ i ] . rlim_max ) ;
/* soft limit should not exceed hard limit */
rlim - > rlim_cur = min ( rlim - > rlim_cur , rlim - > rlim_max ) ;
}
}