2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-07-30 01:48:00 +04:00
/*
* AppArmor security module
*
* This file contains AppArmor policy manipulation functions
*
* Copyright ( C ) 1998 - 2008 Novell / SUSE
* Copyright 2009 - 2010 Canonical Ltd .
*
* AppArmor policy is based around profiles , which contain the rules a
* task is confined by . Every task in the system has a profile attached
* to it determined either by matching " unconfined " tasks against the
* visible set of profiles or by following a profiles attachment rules .
*
* Each profile exists in a profile namespace which is a container of
* visible profiles . Each namespace contains a special " unconfined " profile ,
* which doesn ' t enforce any confinement on a task beyond DAC .
*
* Namespace and profile names can be written together in either
* of two syntaxes .
* : namespace : profile - used by kernel interfaces for easy detection
* namespace : //profile - used by policy
*
* Profile names can not start with : or @ or ^ and may not contain \ 0
*
* Reserved profile names
* unconfined - special automatically generated unconfined profile
* inherit - special name to indicate profile inheritance
* null - XXXX - YYYY - special automatically generated learning profiles
*
* Namespace names may not start with / or @ and may not contain \ 0 or :
* Reserved namespace names
* user - XXXX - user defined profiles
*
* a // in a profile or namespace name indicates a hierarchical name with the
* name before the // being the parent and the name after the child.
*
* Profile and namespace hierarchies serve two different but similar purposes .
* The namespace contains the set of visible profiles that are considered
* for attachment . The hierarchy of namespaces allows for virtualizing
* the namespace so that for example a chroot can have its own set of profiles
* which may define some local user namespaces .
* The profile hierarchy severs two distinct purposes ,
* - it allows for sub profiles or hats , which allows an application to run
* subprograms under its own profile with different restriction than it
* self , and not have it use the system profile .
* eg . if a mail program starts an editor , the policy might make the
* restrictions tighter on the editor tighter than the mail program ,
* and definitely different than general editor restrictions
* - it allows for binary hierarchy of profiles , so that execution history
* is preserved . This feature isn ' t exploited by AppArmor reference policy
* but is allowed . NOTE : this is currently suboptimal because profile
* aliasing is not currently implemented so that a profile for each
* level must be defined .
* eg . / bin / bash ///bin/ls as a name would indicate /bin/ls was started
* from / bin / bash
*
* A profile or namespace name that can contain one or more // separators
* is referred to as an hname ( hierarchical ) .
* eg . / bin / bash //bin/ls
*
* An fqname is a name that may contain both namespace and profile hnames .
* eg . : ns : / bin / bash //bin/ls
*
* NOTES :
* - locking of profile lists is currently fairly coarse . All profile
* lists within a namespace use the namespace lock .
* FIXME : move profile lists to using rcu_lists
*/
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/string.h>
2017-02-02 19:54:15 +03:00
# include <linux/cred.h>
2017-02-04 03:27:20 +03:00
# include <linux/rculist.h>
2017-01-16 11:42:50 +03:00
# include <linux/user_namespace.h>
2010-07-30 01:48:00 +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:00 +04:00
# include "include/file.h"
# include "include/ipc.h"
# include "include/match.h"
# include "include/path.h"
# include "include/policy.h"
2017-01-16 11:42:15 +03:00
# include "include/policy_ns.h"
2010-07-30 01:48:00 +04:00
# include "include/policy_unpack.h"
# include "include/resource.h"
2017-01-16 11:42:50 +03:00
int unprivileged_userns_apparmor_policy = 1 ;
2010-07-30 01:48:00 +04:00
2013-07-11 08:13:43 +04:00
const char * const aa_profile_mode_names [ ] = {
2010-07-30 01:48:00 +04:00
" enforce " ,
" complain " ,
" kill " ,
2013-07-11 08:12:43 +04:00
" unconfined " ,
2010-07-30 01:48:00 +04:00
} ;
/**
2017-06-09 18:14:28 +03:00
* __add_profile - add a profiles to list and label tree
2010-07-30 01:48:00 +04:00
* @ list : list to add it to ( NOT NULL )
* @ profile : the profile to add ( NOT NULL )
*
* refcount @ profile , should be put by __list_remove_profile
*
* Requires : namespace lock be held , or list not be shared
*/
2017-06-09 18:14:28 +03:00
static void __add_profile ( struct list_head * list , struct aa_profile * profile )
2010-07-30 01:48:00 +04:00
{
2017-06-09 18:14:28 +03:00
struct aa_label * l ;
AA_BUG ( ! list ) ;
AA_BUG ( ! profile ) ;
AA_BUG ( ! profile - > ns ) ;
AA_BUG ( ! mutex_is_locked ( & profile - > ns - > lock ) ) ;
2013-07-11 08:06:43 +04:00
list_add_rcu ( & profile - > base . list , list ) ;
2010-07-30 01:48:00 +04:00
/* get list reference */
aa_get_profile ( profile ) ;
2017-06-09 18:14:28 +03:00
l = aa_label_insert ( & profile - > ns - > labels , & profile - > label ) ;
AA_BUG ( l ! = & profile - > label ) ;
aa_put_label ( l ) ;
2010-07-30 01:48:00 +04:00
}
/**
* __list_remove_profile - remove a profile from the list it is on
* @ profile : the profile to remove ( NOT NULL )
*
* remove a profile from the list , warning generally removal should
* be done with __replace_profile as most profile removals are
* replacements to the unconfined profile .
*
* put @ profile list refcount
*
* Requires : namespace lock be held , or list not have been live
*/
static void __list_remove_profile ( struct aa_profile * profile )
{
2017-06-09 18:14:28 +03:00
AA_BUG ( ! profile ) ;
AA_BUG ( ! profile - > ns ) ;
AA_BUG ( ! mutex_is_locked ( & profile - > ns - > lock ) ) ;
2013-07-11 08:06:43 +04:00
list_del_rcu ( & profile - > base . list ) ;
aa_put_profile ( profile ) ;
2010-07-30 01:48:00 +04:00
}
/**
* __remove_profile - remove old profile , and children
* @ profile : profile to be replaced ( NOT NULL )
*
* Requires : namespace list lock be held , or list not be shared
*/
static void __remove_profile ( struct aa_profile * profile )
{
2017-06-09 18:14:28 +03:00
AA_BUG ( ! profile ) ;
AA_BUG ( ! profile - > ns ) ;
AA_BUG ( ! mutex_is_locked ( & profile - > ns - > lock ) ) ;
2010-07-30 01:48:00 +04:00
/* release any children lists first */
2017-01-16 11:42:15 +03:00
__aa_profile_list_release ( & profile - > base . profiles ) ;
2010-07-30 01:48:00 +04:00
/* released by free_profile */
2017-06-09 18:14:28 +03:00
aa_label_remove ( & profile - > label ) ;
2017-05-25 16:23:42 +03:00
__aafs_profile_rmdir ( profile ) ;
2010-07-30 01:48:00 +04:00
__list_remove_profile ( profile ) ;
}
/**
2017-01-16 11:42:15 +03:00
* __aa_profile_list_release - remove all profiles on the list and put refs
2010-07-30 01:48:00 +04:00
* @ head : list of profiles ( NOT NULL )
*
* Requires : namespace lock be held
*/
2017-01-16 11:42:15 +03:00
void __aa_profile_list_release ( struct list_head * head )
2010-07-30 01:48:00 +04:00
{
struct aa_profile * profile , * tmp ;
list_for_each_entry_safe ( profile , tmp , head , base . list )
__remove_profile ( profile ) ;
}
2017-01-16 03:49:28 +03:00
/**
* aa_free_data - free a data blob
* @ ptr : data to free
* @ arg : unused
*/
static void aa_free_data ( void * ptr , void * arg )
{
struct aa_data * data = ptr ;
2020-08-07 09:18:13 +03:00
kfree_sensitive ( data - > data ) ;
kfree_sensitive ( data - > key ) ;
kfree_sensitive ( data ) ;
2017-01-16 03:49:28 +03:00
}
2010-07-30 01:48:00 +04:00
/**
2013-07-11 08:11:43 +04:00
* aa_free_profile - free a profile
2010-07-30 01:48:00 +04:00
* @ profile : the profile to free ( MAYBE NULL )
*
* Free a profile , its hats and null_profile . All references to the profile ,
* its hats and null_profile must have been put .
*
* If the profile was referenced from a task context , free_profile ( ) will
* be called from an rcu callback routine , so we must not sleep here .
*/
2013-07-11 08:11:43 +04:00
void aa_free_profile ( struct aa_profile * profile )
2010-07-30 01:48:00 +04:00
{
2017-01-16 03:49:28 +03:00
struct rhashtable * rht ;
2018-02-08 23:37:19 +03:00
int i ;
2017-01-16 03:49:28 +03:00
2010-07-30 01:48:00 +04:00
AA_DEBUG ( " %s(%p) \n " , __func__ , profile ) ;
if ( ! profile )
return ;
/* free children profiles */
2017-01-16 11:42:14 +03:00
aa_policy_destroy ( & profile - > base ) ;
2013-07-11 08:06:43 +04:00
aa_put_profile ( rcu_access_pointer ( profile - > parent ) ) ;
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:16 +03:00
aa_put_ns ( profile - > ns ) ;
2020-08-07 09:18:13 +03:00
kfree_sensitive ( profile - > rename ) ;
2010-07-30 01:48:00 +04:00
aa_free_file_rules ( & profile - > file ) ;
aa_free_cap_rules ( & profile - > caps ) ;
aa_free_rlimit_rules ( & profile - > rlimits ) ;
2017-12-13 02:28:05 +03:00
for ( i = 0 ; i < profile - > xattr_count ; i + + )
2020-08-07 09:18:13 +03:00
kfree_sensitive ( profile - > xattrs [ i ] ) ;
kfree_sensitive ( profile - > xattrs ) ;
2018-11-02 08:28:17 +03:00
for ( i = 0 ; i < profile - > secmark_count ; i + + )
2020-08-07 09:18:13 +03:00
kfree_sensitive ( profile - > secmark [ i ] . label ) ;
kfree_sensitive ( profile - > secmark ) ;
kfree_sensitive ( profile - > dirname ) ;
2010-07-30 01:48:00 +04:00
aa_put_dfa ( profile - > xmatch ) ;
2012-02-16 19:07:53 +04:00
aa_put_dfa ( profile - > policy . dfa ) ;
2010-07-30 01:48:00 +04:00
2017-01-16 03:49:28 +03:00
if ( profile - > data ) {
rht = profile - > data ;
profile - > data = NULL ;
rhashtable_free_and_destroy ( rht , aa_free_data , NULL ) ;
2020-08-07 09:18:13 +03:00
kfree_sensitive ( rht ) ;
2017-01-16 03:49:28 +03:00
}
2020-08-07 09:18:13 +03:00
kfree_sensitive ( profile - > hash ) ;
2017-01-16 11:42:55 +03:00
aa_put_loaddata ( profile - > rawdata ) ;
2020-06-07 14:10:33 +03:00
aa_label_destroy ( & profile - > label ) ;
2010-07-30 01:48:00 +04:00
2020-08-07 09:18:13 +03:00
kfree_sensitive ( profile ) ;
2010-07-30 01:48:00 +04:00
}
2013-02-19 04:11:34 +04:00
/**
* aa_alloc_profile - allocate , initialize and return a new profile
* @ hname : name of the profile ( NOT NULL )
2017-01-16 11:42:35 +03:00
* @ gfp : allocation type
2013-02-19 04:11:34 +04:00
*
* Returns : refcount profile or NULL on failure
*/
2017-06-09 18:14:28 +03:00
struct aa_profile * aa_alloc_profile ( const char * hname , struct aa_proxy * proxy ,
gfp_t gfp )
2013-02-19 04:11:34 +04:00
{
struct aa_profile * profile ;
/* freed by free_profile - usually through aa_put_profile */
2021-09-30 01:05:26 +03:00
profile = kzalloc ( struct_size ( profile , label . vec , 2 ) , gfp ) ;
2013-02-19 04:11:34 +04:00
if ( ! profile )
return NULL ;
2017-01-16 11:42:35 +03:00
if ( ! aa_policy_init ( & profile - > base , NULL , hname , gfp ) )
2013-07-11 08:07:43 +04:00
goto fail ;
2017-08-01 03:36:45 +03:00
if ( ! aa_label_init ( & profile - > label , 1 , gfp ) )
2017-06-09 18:14:28 +03:00
goto fail ;
/* update being set needed by fs interface */
if ( ! proxy ) {
proxy = aa_alloc_proxy ( & profile - > label , gfp ) ;
if ( ! proxy )
goto fail ;
} else
aa_get_proxy ( proxy ) ;
profile - > label . proxy = proxy ;
profile - > label . hname = profile - > base . hname ;
profile - > label . flags | = FLAG_PROFILE ;
profile - > label . vec [ 0 ] = profile ;
2013-02-19 04:11:34 +04:00
/* refcount released by caller */
return profile ;
2013-07-11 08:07:43 +04:00
fail :
2017-06-09 18:14:28 +03:00
aa_free_profile ( profile ) ;
2013-07-11 08:07:43 +04:00
return NULL ;
2013-02-19 04:11:34 +04:00
}
2010-07-30 01:48:00 +04:00
/* TODO: profile accounting - setup in remove */
/**
2017-06-02 23:50:22 +03:00
* __strn_find_child - find a profile on @ head list using substring of @ name
2010-07-30 01:48:00 +04:00
* @ head : list to search ( NOT NULL )
* @ name : name of profile ( NOT NULL )
2017-06-02 23:50:22 +03:00
* @ len : length of @ name substring to match
2010-07-30 01:48:00 +04:00
*
2013-07-11 08:06:43 +04:00
* Requires : rcu_read_lock be held
2010-07-30 01:48:00 +04:00
*
* Returns : unrefcounted profile ptr , or NULL if not found
*/
2017-06-02 23:50:22 +03:00
static struct aa_profile * __strn_find_child ( struct list_head * head ,
const char * name , int len )
2010-07-30 01:48:00 +04:00
{
2017-06-02 23:50:22 +03:00
return ( struct aa_profile * ) __policy_strn_find ( head , name , len ) ;
2010-07-30 01:48:00 +04:00
}
/**
2017-06-02 23:50:22 +03:00
* __find_child - find a profile on @ head list with a name matching @ name
2010-07-30 01:48:00 +04:00
* @ head : list to search ( NOT NULL )
* @ name : name of profile ( NOT NULL )
*
2013-07-11 08:06:43 +04:00
* Requires : rcu_read_lock be held
2010-07-30 01:48:00 +04:00
*
* Returns : unrefcounted profile ptr , or NULL if not found
*/
2017-06-02 23:50:22 +03:00
static struct aa_profile * __find_child ( struct list_head * head , const char * name )
2010-07-30 01:48:00 +04:00
{
2017-06-02 23:50:22 +03:00
return __strn_find_child ( head , name , strlen ( name ) ) ;
2010-07-30 01:48:00 +04:00
}
/**
* aa_find_child - find a profile by @ name in @ parent
* @ parent : profile to search ( NOT NULL )
* @ name : profile name to search for ( NOT NULL )
*
* Returns : a refcounted profile or NULL if not found
*/
struct aa_profile * aa_find_child ( struct aa_profile * parent , const char * name )
{
struct aa_profile * profile ;
2013-07-11 08:06:43 +04:00
rcu_read_lock ( ) ;
2015-12-17 05:09:10 +03:00
do {
profile = __find_child ( & parent - > base . profiles , name ) ;
} while ( profile & & ! aa_get_profile_not0 ( profile ) ) ;
2013-07-11 08:06:43 +04:00
rcu_read_unlock ( ) ;
2010-07-30 01:48:00 +04:00
/* refcount released by caller */
return profile ;
}
/**
* __lookup_parent - lookup the parent of a profile of name @ hname
* @ ns : namespace to lookup profile in ( NOT NULL )
* @ hname : hierarchical profile name to find parent of ( NOT NULL )
*
* Lookups up the parent of a fully qualified profile name , the profile
* that matches hname does not need to exist , in general this
* is used to load a new profile .
*
2013-07-11 08:06:43 +04:00
* Requires : rcu_read_lock be held
2010-07-30 01:48:00 +04:00
*
* Returns : unrefcounted policy or NULL if not found
*/
2017-01-16 11:42:16 +03:00
static struct aa_policy * __lookup_parent ( struct aa_ns * ns ,
2010-07-30 01:48:00 +04:00
const char * hname )
{
struct aa_policy * policy ;
struct aa_profile * profile = NULL ;
char * split ;
policy = & ns - > base ;
for ( split = strstr ( hname , " // " ) ; split ; ) {
profile = __strn_find_child ( & policy - > profiles , hname ,
split - hname ) ;
if ( ! profile )
return NULL ;
policy = & profile - > base ;
hname = split + 2 ;
split = strstr ( hname , " // " ) ;
}
if ( ! profile )
return & ns - > base ;
return & profile - > base ;
}
/**
2017-01-16 11:42:21 +03:00
* __lookupn_profile - lookup the profile matching @ hname
2010-07-30 01:48:00 +04:00
* @ base : base list to start looking up profile name from ( NOT NULL )
* @ hname : hierarchical profile name ( NOT NULL )
2017-01-16 11:42:21 +03:00
* @ n : length of @ hname
2010-07-30 01:48:00 +04:00
*
2013-07-11 08:06:43 +04:00
* Requires : rcu_read_lock be held
2010-07-30 01:48:00 +04:00
*
* Returns : unrefcounted profile pointer or NULL if not found
*
* Do a relative name lookup , recursing through profile tree .
*/
2017-01-16 11:42:21 +03:00
static struct aa_profile * __lookupn_profile ( struct aa_policy * base ,
const char * hname , size_t n )
2010-07-30 01:48:00 +04:00
{
struct aa_profile * profile = NULL ;
2017-01-16 11:42:21 +03:00
const char * split ;
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:21 +03:00
for ( split = strnstr ( hname , " // " , n ) ; split ;
split = strnstr ( hname , " // " , n ) ) {
2010-07-30 01:48:00 +04:00
profile = __strn_find_child ( & base - > profiles , hname ,
split - hname ) ;
if ( ! profile )
return NULL ;
base = & profile - > base ;
2017-01-16 11:42:21 +03:00
n - = split + 2 - hname ;
2010-07-30 01:48:00 +04:00
hname = split + 2 ;
}
2017-01-16 11:42:21 +03:00
if ( n )
return __strn_find_child ( & base - > profiles , hname , n ) ;
return NULL ;
}
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:21 +03:00
static struct aa_profile * __lookup_profile ( struct aa_policy * base ,
const char * hname )
{
return __lookupn_profile ( base , hname , strlen ( hname ) ) ;
2010-07-30 01:48:00 +04:00
}
/**
2021-11-17 10:37:58 +03:00
* aa_lookupn_profile - find a profile by its full or partial name
2010-07-30 01:48:00 +04:00
* @ ns : the namespace to start from ( NOT NULL )
* @ hname : name to do lookup on . Does not contain namespace prefix ( NOT NULL )
2017-01-16 11:42:21 +03:00
* @ n : size of @ hname
2010-07-30 01:48:00 +04:00
*
* Returns : refcounted profile or NULL if not found
*/
2017-01-16 11:42:21 +03:00
struct aa_profile * aa_lookupn_profile ( struct aa_ns * ns , const char * hname ,
size_t n )
2010-07-30 01:48:00 +04:00
{
struct aa_profile * profile ;
2013-07-11 08:06:43 +04:00
rcu_read_lock ( ) ;
do {
2017-01-16 11:42:21 +03:00
profile = __lookupn_profile ( & ns - > base , hname , n ) ;
2013-07-11 08:06:43 +04:00
} while ( profile & & ! aa_get_profile_not0 ( profile ) ) ;
rcu_read_unlock ( ) ;
2010-07-30 01:48:00 +04:00
2012-05-16 22:00:05 +04:00
/* the unconfined profile is not in the regular profile list */
2017-01-16 11:42:21 +03:00
if ( ! profile & & strncmp ( hname , " unconfined " , n ) = = 0 )
2013-07-11 08:08:43 +04:00
profile = aa_get_newest_profile ( ns - > unconfined ) ;
2012-05-16 22:00:05 +04:00
2010-07-30 01:48:00 +04:00
/* refcount released by caller */
return profile ;
}
2017-01-16 11:42:21 +03:00
struct aa_profile * aa_lookup_profile ( struct aa_ns * ns , const char * hname )
{
return aa_lookupn_profile ( ns , hname , strlen ( hname ) ) ;
}
2017-01-16 11:42:24 +03:00
2017-06-09 18:14:28 +03:00
struct aa_profile * aa_fqlookupn_profile ( struct aa_label * base ,
2017-01-16 11:42:24 +03:00
const char * fqname , size_t n )
{
struct aa_profile * profile ;
struct aa_ns * ns ;
const char * name , * ns_name ;
size_t ns_len ;
name = aa_splitn_fqname ( fqname , n , & ns_name , & ns_len ) ;
if ( ns_name ) {
2017-06-09 18:14:28 +03:00
ns = aa_lookupn_ns ( labels_ns ( base ) , ns_name , ns_len ) ;
2017-01-16 11:42:24 +03:00
if ( ! ns )
return NULL ;
} else
2017-06-09 18:14:28 +03:00
ns = aa_get_ns ( labels_ns ( base ) ) ;
2017-01-16 11:42:24 +03:00
if ( name )
profile = aa_lookupn_profile ( ns , name , n - ( name - fqname ) ) ;
else if ( ns )
/* default profile for ns, currently unconfined */
profile = aa_get_newest_profile ( ns - > unconfined ) ;
else
profile = NULL ;
aa_put_ns ( ns ) ;
return profile ;
}
2017-08-16 18:59:57 +03:00
/**
* aa_new_null_profile - create or find a null - X learning profile
* @ parent : profile that caused this profile to be created ( NOT NULL )
* @ hat : true if the null - learning profile is a hat
* @ base : name to base the null profile off of
* @ gfp : type of allocation
*
* Find / Create a null - complain mode profile used in learning mode . The
* name of the profile is unique and follows the format of parent //null-XXX.
* where XXX is based on the @ name or if that fails or is not supplied
* a unique number
*
* null profiles are added to the profile list but the list does not
* hold a count on them so that they are automatically released when
* not in use .
*
* Returns : new refcounted profile else NULL on failure
*/
struct aa_profile * aa_new_null_profile ( struct aa_profile * parent , bool hat ,
const char * base , gfp_t gfp )
{
2017-08-16 15:40:49 +03:00
struct aa_profile * p , * profile ;
const char * bname ;
2017-11-16 02:25:30 +03:00
char * name = NULL ;
2017-08-16 18:59:57 +03:00
AA_BUG ( ! parent ) ;
if ( base ) {
name = kmalloc ( strlen ( parent - > base . hname ) + 8 + strlen ( base ) ,
gfp ) ;
if ( name ) {
sprintf ( name , " %s//null-%s " , parent - > base . hname , base ) ;
goto name ;
}
/* fall through to try shorter uniq */
}
name = kmalloc ( strlen ( parent - > base . hname ) + 2 + 7 + 8 , gfp ) ;
if ( ! name )
return NULL ;
sprintf ( name , " %s//null-%x " , parent - > base . hname ,
atomic_inc_return ( & parent - > ns - > uniq_null ) ) ;
name :
/* lookup to see if this is a dup creation */
2017-08-16 15:40:49 +03:00
bname = basename ( name ) ;
profile = aa_find_child ( parent , bname ) ;
2017-08-16 18:59:57 +03:00
if ( profile )
goto out ;
profile = aa_alloc_profile ( name , NULL , gfp ) ;
if ( ! profile )
goto fail ;
profile - > mode = APPARMOR_COMPLAIN ;
profile - > label . flags | = FLAG_NULL ;
if ( hat )
profile - > label . flags | = FLAG_HAT ;
profile - > path_flags = parent - > path_flags ;
/* released on free_profile */
rcu_assign_pointer ( profile - > parent , aa_get_profile ( parent ) ) ;
profile - > ns = aa_get_ns ( parent - > ns ) ;
profile - > file . dfa = aa_get_dfa ( nulldfa ) ;
profile - > policy . dfa = aa_get_dfa ( nulldfa ) ;
2017-11-21 10:24:09 +03:00
mutex_lock_nested ( & profile - > ns - > lock , profile - > ns - > level ) ;
2017-08-16 15:40:49 +03:00
p = __find_child ( & parent - > base . profiles , bname ) ;
if ( p ) {
aa_free_profile ( profile ) ;
profile = aa_get_profile ( p ) ;
} else {
__add_profile ( & parent - > base . profiles , profile ) ;
}
2017-08-16 18:59:57 +03:00
mutex_unlock ( & profile - > ns - > lock ) ;
/* refcount released by caller */
out :
kfree ( name ) ;
return profile ;
fail :
2017-11-16 02:25:30 +03:00
kfree ( name ) ;
2017-08-16 18:59:57 +03:00
aa_free_profile ( profile ) ;
return NULL ;
}
2010-07-30 01:48:00 +04:00
/**
* replacement_allowed - test to see if replacement is allowed
* @ profile : profile to test if it can be replaced ( MAYBE NULL )
* @ noreplace : true if replacement shouldn ' t be allowed but addition is okay
* @ info : Returns - info about why replacement failed ( NOT NULL )
*
* Returns : % 0 if replacement allowed else error code
*/
static int replacement_allowed ( struct aa_profile * profile , int noreplace ,
const char * * info )
{
if ( profile ) {
2017-06-09 18:14:28 +03:00
if ( profile - > label . flags & FLAG_IMMUTIBLE ) {
2019-04-16 17:42:18 +03:00
* info = " cannot replace immutable profile " ;
2010-07-30 01:48:00 +04:00
return - EPERM ;
} else if ( noreplace ) {
* info = " profile already exists " ;
return - EEXIST ;
}
}
return 0 ;
}
2017-01-16 11:42:54 +03:00
/* audit callback for net specific fields */
static void audit_cb ( struct audit_buffer * ab , void * va )
{
struct common_audit_data * sa = va ;
2017-01-16 11:43:02 +03:00
if ( aad ( sa ) - > iface . ns ) {
2017-01-16 11:42:54 +03:00
audit_log_format ( ab , " ns= " ) ;
2017-01-16 11:43:02 +03:00
audit_log_untrustedstring ( ab , aad ( sa ) - > iface . ns ) ;
2017-01-16 11:42:54 +03:00
}
}
2010-07-30 01:48:00 +04:00
/**
2017-06-09 18:14:28 +03:00
* audit_policy - Do auditing of policy changes
* @ label : label to check if it can manage policy
2010-07-30 01:48:00 +04:00
* @ op : policy operation being performed
2017-06-09 18:14:28 +03:00
* @ ns_name : name of namespace being manipulated
2010-07-30 01:48:00 +04:00
* @ name : name of profile being manipulated ( NOT NULL )
* @ info : any extra information to be audited ( MAYBE NULL )
* @ error : error code
*
* Returns : the error to be returned after audit is done
*/
2017-06-09 18:14:28 +03:00
static int audit_policy ( struct aa_label * label , const char * op ,
const char * ns_name , const char * name ,
2017-01-16 11:42:54 +03:00
const char * info , int error )
2010-07-30 01:48:00 +04:00
{
2017-01-16 11:43:02 +03:00
DEFINE_AUDIT_DATA ( sa , LSM_AUDIT_DATA_NONE , op ) ;
2017-06-09 18:14:28 +03:00
aad ( & sa ) - > iface . ns = ns_name ;
2017-01-16 11:43:02 +03:00
aad ( & sa ) - > name = name ;
aad ( & sa ) - > info = info ;
aad ( & sa ) - > error = error ;
2017-06-09 18:14:28 +03:00
aad ( & sa ) - > label = label ;
2017-01-16 11:43:02 +03:00
2017-06-09 18:14:28 +03:00
aa_audit_msg ( AUDIT_APPARMOR_STATUS , & sa , audit_cb ) ;
return error ;
2010-07-30 01:48:00 +04:00
}
2020-07-01 12:18:18 +03:00
/* don't call out to other LSMs in the stack for apparmor policy admin
* permissions
*/
static int policy_ns_capable ( struct aa_label * label ,
struct user_namespace * userns , int cap )
{
int err ;
/* check for MAC_ADMIN cap in cred */
err = cap_capable ( current_cred ( ) , userns , cap , CAP_OPT_NONE ) ;
if ( ! err )
err = aa_capable ( label , cap , CAP_OPT_NONE ) ;
return err ;
}
2017-01-16 11:42:50 +03:00
/**
2020-07-01 03:00:11 +03:00
* aa_policy_view_capable - check if viewing policy in at @ ns is allowed
* label : label that is trying to view policy in ns
* ns : namespace being viewed by @ label ( may be NULL if @ label ' s ns )
2017-01-16 11:42:50 +03:00
* Returns : true if viewing policy is allowed
*
* If @ ns is NULL then the namespace being viewed is assumed to be the
* tasks current namespace .
*/
2020-07-01 03:00:11 +03:00
bool aa_policy_view_capable ( struct aa_label * label , struct aa_ns * ns )
2016-06-23 04:01:08 +03:00
{
struct user_namespace * user_ns = current_user_ns ( ) ;
2020-07-01 03:00:11 +03:00
struct aa_ns * view_ns = labels_view ( label ) ;
2017-01-16 11:42:50 +03:00
bool root_in_user_ns = uid_eq ( current_euid ( ) , make_kuid ( user_ns , 0 ) ) | |
in_egroup_p ( make_kgid ( user_ns , 0 ) ) ;
2016-06-23 04:01:08 +03:00
bool response = false ;
2017-01-16 11:42:50 +03:00
if ( ! ns )
ns = view_ns ;
2016-06-23 04:01:08 +03:00
2017-01-16 11:42:50 +03:00
if ( root_in_user_ns & & aa_ns_visible ( view_ns , ns , true ) & &
( user_ns = = & init_user_ns | |
( unprivileged_userns_apparmor_policy ! = 0 & &
user_ns - > level = = view_ns - > level ) ) )
2016-06-23 04:01:08 +03:00
response = true ;
return response ;
}
2020-07-01 03:00:11 +03:00
bool aa_policy_admin_capable ( struct aa_label * label , struct aa_ns * ns )
2016-06-23 04:01:08 +03:00
{
2017-01-16 11:42:51 +03:00
struct user_namespace * user_ns = current_user_ns ( ) ;
2021-04-03 21:07:37 +03:00
bool capable = policy_ns_capable ( label , user_ns , CAP_MAC_ADMIN ) = = 0 ;
2017-01-16 11:42:51 +03:00
AA_DEBUG ( " cap_mac_admin? %d \n " , capable ) ;
AA_DEBUG ( " policy locked? %d \n " , aa_g_lock_policy ) ;
2020-07-01 03:00:11 +03:00
return aa_policy_view_capable ( label , ns ) & & capable & &
! aa_g_lock_policy ;
}
bool aa_current_policy_view_capable ( struct aa_ns * ns )
{
struct aa_label * label ;
bool res ;
label = __begin_current_label_crit_section ( ) ;
res = aa_policy_view_capable ( label , ns ) ;
__end_current_label_crit_section ( label ) ;
return res ;
}
bool aa_current_policy_admin_capable ( struct aa_ns * ns )
{
struct aa_label * label ;
bool res ;
label = __begin_current_label_crit_section ( ) ;
res = aa_policy_admin_capable ( label , ns ) ;
__end_current_label_crit_section ( label ) ;
return res ;
2016-06-23 04:01:08 +03:00
}
2010-07-30 01:48:00 +04:00
/**
* aa_may_manage_policy - can the current task manage policy
2017-06-09 18:14:28 +03:00
* @ label : label to check if it can manage policy
2010-07-30 01:48:00 +04:00
* @ op : the policy manipulation operation being done
*
2017-01-16 11:42:52 +03:00
* Returns : 0 if the task is allowed to manipulate policy else error
2010-07-30 01:48:00 +04:00
*/
2017-06-09 18:14:28 +03:00
int aa_may_manage_policy ( struct aa_label * label , struct aa_ns * ns , u32 mask )
2010-07-30 01:48:00 +04:00
{
2017-05-26 11:45:08 +03:00
const char * op ;
if ( mask & AA_MAY_REMOVE_POLICY )
op = OP_PROF_RM ;
else if ( mask & AA_MAY_REPLACE_POLICY )
op = OP_PROF_REPL ;
else
op = OP_PROF_LOAD ;
2010-07-30 01:48:00 +04:00
/* check if loading policy is locked out */
2017-01-16 11:42:52 +03:00
if ( aa_g_lock_policy )
2017-06-09 18:14:28 +03:00
return audit_policy ( label , op , NULL , NULL , " policy_locked " ,
2017-05-26 11:45:08 +03:00
- EACCES ) ;
2010-07-30 01:48:00 +04:00
2020-07-01 03:00:11 +03:00
if ( ! aa_policy_admin_capable ( label , ns ) )
2017-06-09 18:14:28 +03:00
return audit_policy ( label , op , NULL , NULL , " not policy admin " ,
2017-05-26 11:45:08 +03:00
- EACCES ) ;
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:52 +03:00
/* TODO: add fine grained mediation of policy loads */
return 0 ;
2010-07-30 01:48:00 +04:00
}
2013-07-11 08:05:43 +04:00
static struct aa_profile * __list_lookup_parent ( struct list_head * lh ,
struct aa_profile * profile )
{
2017-01-16 11:42:29 +03:00
const char * base = basename ( profile - > base . hname ) ;
2013-07-11 08:05:43 +04:00
long len = base - profile - > base . hname ;
struct aa_load_ent * ent ;
/* parent won't have trailing // so remove from len */
if ( len < = 2 )
return NULL ;
len - = 2 ;
list_for_each_entry ( ent , lh , list ) {
if ( ent - > new = = profile )
continue ;
if ( strncmp ( ent - > new - > base . hname , profile - > base . hname , len ) = =
0 & & ent - > new - > base . hname [ len ] = = 0 )
return ent - > new ;
}
return NULL ;
}
/**
* __replace_profile - replace @ old with @ new on a list
* @ old : profile to be replaced ( NOT NULL )
* @ new : profile to replace @ old with ( NOT NULL )
2017-01-16 11:42:19 +03:00
* @ share_proxy : transfer @ old - > proxy to @ new
2013-07-11 08:05:43 +04:00
*
* Will duplicate and refcount elements that @ new inherits from @ old
* and will inherit @ old children .
*
* refcount @ new for list , put @ old list refcount
*
* Requires : namespace list lock be held , or list not be shared
*/
2017-06-09 18:14:28 +03:00
static void __replace_profile ( struct aa_profile * old , struct aa_profile * new )
2013-07-11 08:05:43 +04:00
{
struct aa_profile * child , * tmp ;
if ( ! list_empty ( & old - > base . profiles ) ) {
LIST_HEAD ( lh ) ;
2013-07-11 08:06:43 +04:00
list_splice_init_rcu ( & old - > base . profiles , & lh , synchronize_rcu ) ;
2013-07-11 08:05:43 +04:00
list_for_each_entry_safe ( child , tmp , & lh , base . list ) {
struct aa_profile * p ;
list_del_init ( & child - > base . list ) ;
p = __find_child ( & new - > base . profiles , child - > base . name ) ;
if ( p ) {
/* @p replaces @child */
2017-06-09 18:14:28 +03:00
__replace_profile ( child , p ) ;
2013-07-11 08:05:43 +04:00
continue ;
}
/* inherit @child and its children */
/* TODO: update hname of inherited children */
/* list refcount transferred to @new */
2013-07-11 08:13:43 +04:00
p = aa_deref_parent ( child ) ;
2013-07-11 08:06:43 +04:00
rcu_assign_pointer ( child - > parent , aa_get_profile ( new ) ) ;
list_add_rcu ( & child - > base . list , & new - > base . profiles ) ;
aa_put_profile ( p ) ;
2013-07-11 08:05:43 +04:00
}
}
2013-07-11 08:06:43 +04:00
if ( ! rcu_access_pointer ( new - > parent ) ) {
2013-07-11 08:13:43 +04:00
struct aa_profile * parent = aa_deref_parent ( old ) ;
2013-07-11 08:06:43 +04:00
rcu_assign_pointer ( new - > parent , aa_get_profile ( parent ) ) ;
}
2017-06-09 18:14:28 +03:00
aa_label_replace ( & old - > label , & new - > label ) ;
/* migrate dents must come after label replacement b/c update */
2017-05-25 16:23:42 +03:00
__aafs_profile_migrate_dents ( old , new ) ;
2013-07-11 08:05:43 +04:00
if ( list_empty ( & new - > base . list ) ) {
/* new is not on a list already */
2013-07-11 08:06:43 +04:00
list_replace_rcu ( & old - > base . list , & new - > base . list ) ;
2013-07-11 08:05:43 +04:00
aa_get_profile ( new ) ;
aa_put_profile ( old ) ;
} else
__list_remove_profile ( old ) ;
}
/**
* __lookup_replace - lookup replacement information for a profile
* @ ns - namespace the lookup occurs in
* @ hname - name of profile to lookup
* @ noreplace - true if not replacing an existing profile
* @ p - Returns : profile to be replaced
* @ info - Returns : info string on why lookup failed
*
* Returns : profile to replace ( no ref ) on success else ptr error
*/
2017-01-16 11:42:16 +03:00
static int __lookup_replace ( struct aa_ns * ns , const char * hname ,
2013-07-11 08:05:43 +04:00
bool noreplace , struct aa_profile * * p ,
const char * * info )
{
* p = aa_get_profile ( __lookup_profile ( & ns - > base , hname ) ) ;
if ( * p ) {
int error = replacement_allowed ( * p , noreplace , info ) ;
if ( error ) {
* info = " profile can not be replaced " ;
return error ;
}
}
return 0 ;
}
2017-06-09 17:09:05 +03:00
static void share_name ( struct aa_profile * old , struct aa_profile * new )
{
aa_put_str ( new - > base . hname ) ;
aa_get_str ( old - > base . hname ) ;
new - > base . hname = old - > base . hname ;
new - > base . name = old - > base . name ;
2017-06-09 18:14:28 +03:00
new - > label . hname = old - > label . hname ;
2017-06-09 17:09:05 +03:00
}
2017-06-09 17:16:46 +03:00
/* Update to newest version of parent after previous replacements
* Returns : unrefcount newest version of parent
*/
static struct aa_profile * update_to_newest_parent ( struct aa_profile * new )
{
struct aa_profile * parent , * newest ;
parent = rcu_dereference_protected ( new - > parent ,
mutex_is_locked ( & new - > ns - > lock ) ) ;
newest = aa_get_newest_profile ( parent ) ;
/* parent replaced in this atomic set? */
if ( newest ! = parent ) {
aa_put_profile ( parent ) ;
rcu_assign_pointer ( new - > parent , newest ) ;
} else
aa_put_profile ( newest ) ;
return newest ;
}
2010-07-30 01:48:00 +04:00
/**
* aa_replace_profiles - replace profile ( s ) on the profile list
2017-06-04 22:22:22 +03:00
* @ policy_ns : namespace load is occurring on
2017-01-16 11:42:57 +03:00
* @ label : label that is attempting to load / replace policy
2017-05-26 11:45:08 +03:00
* @ mask : permission mask
2017-01-16 11:42:55 +03:00
* @ udata : serialized data stream ( NOT NULL )
2010-07-30 01:48:00 +04:00
*
* unpack and replace a profile on the profile list and uses of that profile
2017-01-27 15:36:47 +03:00
* by any task creds via invalidating the old version of the profile , which
* tasks will notice to update their own cred . If the profile does not exist
* on the profile list it is added .
2010-07-30 01:48:00 +04:00
*
* Returns : size of data consumed else error code on failure .
*/
2017-06-09 18:14:28 +03:00
ssize_t aa_replace_profiles ( struct aa_ns * policy_ns , struct aa_label * label ,
2017-05-26 11:45:08 +03:00
u32 mask , struct aa_loaddata * udata )
2010-07-30 01:48:00 +04:00
{
2019-03-10 03:58:10 +03:00
const char * ns_name = NULL , * info = NULL ;
2017-01-16 11:42:16 +03:00
struct aa_ns * ns = NULL ;
2013-07-11 08:05:43 +04:00
struct aa_load_ent * ent , * tmp ;
2017-05-09 10:08:41 +03:00
struct aa_loaddata * rawdata_ent ;
2017-05-26 11:45:08 +03:00
const char * op ;
2017-01-16 11:42:56 +03:00
ssize_t count , error ;
2013-07-11 08:05:43 +04:00
LIST_HEAD ( lh ) ;
2010-07-30 01:48:00 +04:00
2017-05-26 11:45:08 +03:00
op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD ;
2017-05-09 10:08:41 +03:00
aa_get_loaddata ( udata ) ;
2010-07-30 01:48:00 +04:00
/* released below */
2017-01-16 11:42:55 +03:00
error = aa_unpack ( udata , & lh , & ns_name ) ;
2013-07-11 08:05:43 +04:00
if ( error )
goto out ;
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:56 +03:00
/* ensure that profiles are all for the same ns
* TODO : update locking to remove this constaint . All profiles in
* the load set must succeed as a set or the load will
* fail . Sort ent list and take ns locks in hierarchy order
*/
count = 0 ;
list_for_each_entry ( ent , & lh , list ) {
if ( ns_name ) {
if ( ent - > ns_name & &
strcmp ( ent - > ns_name , ns_name ) ! = 0 ) {
info = " policy load has mixed namespaces " ;
error = - EACCES ;
goto fail ;
}
} else if ( ent - > ns_name ) {
if ( count ) {
info = " policy load has mixed namespaces " ;
error = - EACCES ;
goto fail ;
}
ns_name = ent - > ns_name ;
} else
count + + ;
2010-07-30 01:48:00 +04:00
}
2017-01-16 11:42:56 +03:00
if ( ns_name ) {
2017-06-09 18:14:28 +03:00
ns = aa_prepare_ns ( policy_ns ? policy_ns : labels_ns ( label ) ,
2017-06-04 22:22:22 +03:00
ns_name ) ;
2017-01-16 11:42:56 +03:00
if ( IS_ERR ( ns ) ) {
2017-04-06 16:55:22 +03:00
op = OP_PROF_LOAD ;
2017-01-16 11:42:56 +03:00
info = " failed to prepare namespace " ;
error = PTR_ERR ( ns ) ;
ns = NULL ;
2017-04-06 16:55:22 +03:00
ent = NULL ;
2017-01-16 11:42:56 +03:00
goto fail ;
}
} else
2017-06-09 18:14:28 +03:00
ns = aa_get_ns ( policy_ns ? policy_ns : labels_ns ( label ) ) ;
2010-07-30 01:48:00 +04:00
2017-11-21 10:24:09 +03:00
mutex_lock_nested ( & ns - > lock , ns - > level ) ;
2017-05-09 10:08:41 +03:00
/* check for duplicate rawdata blobs: space and file dedup */
2021-02-01 14:43:18 +03:00
if ( ! list_empty ( & ns - > rawdata_list ) ) {
list_for_each_entry ( rawdata_ent , & ns - > rawdata_list , list ) {
if ( aa_rawdata_eq ( rawdata_ent , udata ) ) {
struct aa_loaddata * tmp ;
tmp = __aa_get_loaddata ( rawdata_ent ) ;
/* check we didn't fail the race */
if ( tmp ) {
aa_put_loaddata ( udata ) ;
udata = tmp ;
break ;
}
2017-05-09 10:08:41 +03:00
}
}
}
2013-07-11 08:05:43 +04:00
/* setup parent and ns info */
list_for_each_entry ( ent , & lh , list ) {
struct aa_policy * policy ;
2017-05-09 10:08:41 +03:00
2021-02-01 14:43:18 +03:00
if ( aa_g_export_binary )
ent - > new - > rawdata = aa_get_loaddata ( udata ) ;
2017-05-26 11:45:08 +03:00
error = __lookup_replace ( ns , ent - > new - > base . hname ,
! ( mask & AA_MAY_REPLACE_POLICY ) ,
2013-07-11 08:05:43 +04:00
& ent - > old , & info ) ;
if ( error )
goto fail_lock ;
if ( ent - > new - > rename ) {
error = __lookup_replace ( ns , ent - > new - > rename ,
2017-06-09 18:14:28 +03:00
! ( mask & AA_MAY_REPLACE_POLICY ) ,
& ent - > rename , & info ) ;
2013-07-11 08:05:43 +04:00
if ( error )
goto fail_lock ;
2010-07-30 01:48:00 +04:00
}
2013-07-11 08:05:43 +04:00
/* released when @new is freed */
2017-01-16 11:42:16 +03:00
ent - > new - > ns = aa_get_ns ( ns ) ;
2013-07-11 08:05:43 +04:00
if ( ent - > old | | ent - > rename )
continue ;
/* no ref on policy only use inside lock */
policy = __lookup_parent ( ns , ent - > new - > base . hname ) ;
if ( ! policy ) {
struct aa_profile * p ;
p = __list_lookup_parent ( & lh , ent - > new ) ;
if ( ! p ) {
error = - ENOENT ;
info = " parent does not exist " ;
goto fail_lock ;
}
2013-07-11 08:06:43 +04:00
rcu_assign_pointer ( ent - > new - > parent , aa_get_profile ( p ) ) ;
} else if ( policy ! = & ns - > base ) {
2013-07-11 08:05:43 +04:00
/* released on profile replacement or free_profile */
2013-07-11 08:06:43 +04:00
struct aa_profile * p = ( struct aa_profile * ) policy ;
rcu_assign_pointer ( ent - > new - > parent , aa_get_profile ( p ) ) ;
}
2013-07-11 08:05:43 +04:00
}
2010-07-30 01:48:00 +04:00
2013-07-11 08:13:43 +04:00
/* create new fs entries for introspection if needed */
2021-02-01 14:43:18 +03:00
if ( ! udata - > dents [ AAFS_LOADDATA_DIR ] & & aa_g_export_binary ) {
2017-05-09 10:08:41 +03:00
error = __aa_fs_create_rawdata ( ns , udata ) ;
if ( error ) {
info = " failed to create raw_data dir and files " ;
ent = NULL ;
goto fail_lock ;
}
}
2013-07-11 08:13:43 +04:00
list_for_each_entry ( ent , & lh , list ) {
2017-06-09 17:24:18 +03:00
if ( ! ent - > old ) {
2013-07-11 08:13:43 +04:00
struct dentry * parent ;
if ( rcu_access_pointer ( ent - > new - > parent ) ) {
struct aa_profile * p ;
p = aa_deref_parent ( ent - > new ) ;
parent = prof_child_dir ( p ) ;
} else
parent = ns_subprofs_dir ( ent - > new - > ns ) ;
2017-05-25 16:23:42 +03:00
error = __aafs_profile_mkdir ( ent - > new , parent ) ;
2013-07-11 08:13:43 +04:00
}
if ( error ) {
2017-06-09 17:24:18 +03:00
info = " failed to create " ;
2013-07-11 08:13:43 +04:00
goto fail_lock ;
}
}
/* Done with checks that may fail - do actual replacement */
2017-05-09 10:08:41 +03:00
__aa_bump_ns_revision ( ns ) ;
2021-02-01 14:43:18 +03:00
if ( aa_g_export_binary )
__aa_loaddata_update ( udata , ns - > revision ) ;
2013-07-11 08:05:43 +04:00
list_for_each_entry_safe ( ent , tmp , & lh , list ) {
list_del_init ( & ent - > list ) ;
op = ( ! ent - > old & & ! ent - > rename ) ? OP_PROF_LOAD : OP_PROF_REPL ;
2021-02-01 14:43:18 +03:00
if ( ent - > old & & ent - > old - > rawdata = = ent - > new - > rawdata & &
ent - > new - > rawdata ) {
2017-05-09 10:08:41 +03:00
/* dedup actual profile replacement */
2017-06-09 18:14:28 +03:00
audit_policy ( label , op , ns_name , ent - > new - > base . hname ,
2017-05-09 10:08:41 +03:00
" same as current profile, skipping " ,
error ) ;
2018-04-14 08:33:10 +03:00
/* break refcount cycle with proxy. */
aa_put_proxy ( ent - > new - > label . proxy ) ;
ent - > new - > label . proxy = NULL ;
2017-05-09 10:08:41 +03:00
goto skip ;
}
/*
* TODO : finer dedup based on profile range in data . Load set
* can differ but profile may remain unchanged
*/
2017-06-09 18:14:28 +03:00
audit_policy ( label , op , ns_name , ent - > new - > base . hname , NULL ,
error ) ;
2013-07-11 08:05:43 +04:00
if ( ent - > old ) {
2017-06-09 17:09:05 +03:00
share_name ( ent - > old , ent - > new ) ;
2017-06-09 18:14:28 +03:00
__replace_profile ( ent - > old , ent - > new ) ;
2013-07-11 08:13:43 +04:00
} else {
2017-06-09 17:16:46 +03:00
struct list_head * lh ;
if ( rcu_access_pointer ( ent - > new - > parent ) ) {
struct aa_profile * parent ;
parent = update_to_newest_parent ( ent - > new ) ;
lh = & parent - > base . profiles ;
} else
lh = & ns - > base . profiles ;
2017-06-09 18:14:28 +03:00
__add_profile ( lh , ent - > new ) ;
2013-07-11 08:13:43 +04:00
}
2017-05-09 10:08:41 +03:00
skip :
2013-07-11 08:05:43 +04:00
aa_load_ent_free ( ent ) ;
2010-07-30 01:48:00 +04:00
}
2017-06-09 18:14:28 +03:00
__aa_labelset_update_subtree ( ns ) ;
2013-07-11 08:06:43 +04:00
mutex_unlock ( & ns - > lock ) ;
2010-07-30 01:48:00 +04:00
out :
2017-01-16 11:42:16 +03:00
aa_put_ns ( ns ) ;
2017-05-09 10:08:41 +03:00
aa_put_loaddata ( udata ) ;
2019-03-10 03:58:10 +03:00
kfree ( ns_name ) ;
2013-07-11 08:05:43 +04:00
2010-07-30 01:48:00 +04:00
if ( error )
return error ;
2017-01-16 11:42:55 +03:00
return udata - > size ;
2010-07-30 01:48:00 +04:00
2013-07-11 08:05:43 +04:00
fail_lock :
2013-07-11 08:06:43 +04:00
mutex_unlock ( & ns - > lock ) ;
2013-07-11 08:05:43 +04:00
2016-04-17 00:16:50 +03:00
/* audit cause of failure */
2017-05-09 10:08:41 +03:00
op = ( ent & & ! ent - > old ) ? OP_PROF_LOAD : OP_PROF_REPL ;
2017-01-16 11:42:56 +03:00
fail :
2017-06-09 18:14:28 +03:00
audit_policy ( label , op , ns_name , ent ? ent - > new - > base . hname : NULL ,
info , error ) ;
2016-04-17 00:16:50 +03:00
/* audit status that rest of profiles in the atomic set failed too */
info = " valid profile in failed atomic policy load " ;
list_for_each_entry ( tmp , & lh , list ) {
if ( tmp = = ent ) {
info = " unchecked profile in failed atomic policy load " ;
/* skip entry that caused failure */
continue ;
}
2017-04-06 16:55:22 +03:00
op = ( ! tmp - > old ) ? OP_PROF_LOAD : OP_PROF_REPL ;
2017-06-09 18:14:28 +03:00
audit_policy ( label , op , ns_name , tmp - > new - > base . hname , info ,
error ) ;
2016-04-17 00:16:50 +03:00
}
2013-07-11 08:05:43 +04:00
list_for_each_entry_safe ( ent , tmp , & lh , list ) {
list_del_init ( & ent - > list ) ;
aa_load_ent_free ( ent ) ;
}
2010-07-30 01:48:00 +04:00
goto out ;
}
/**
* aa_remove_profiles - remove profile ( s ) from the system
2017-06-04 22:22:22 +03:00
* @ policy_ns : namespace the remove is being done from
2017-06-09 18:14:28 +03:00
* @ subj : label attempting to remove policy
2010-07-30 01:48:00 +04:00
* @ fqname : name of the profile or namespace to remove ( NOT NULL )
* @ size : size of the name
*
* Remove a profile or sub namespace from the current namespace , so that
* they can not be found anymore and mark them as replaced by unconfined
*
2018-04-12 13:34:34 +03:00
* NOTE : removing confinement does not restore rlimits to preconfinement values
2010-07-30 01:48:00 +04:00
*
* Returns : size of data consume else error code if fails
*/
2017-06-09 18:14:28 +03:00
ssize_t aa_remove_profiles ( struct aa_ns * policy_ns , struct aa_label * subj ,
2017-01-16 11:42:57 +03:00
char * fqname , size_t size )
2010-07-30 01:48:00 +04:00
{
2017-06-04 22:22:22 +03:00
struct aa_ns * ns = NULL ;
2010-07-30 01:48:00 +04:00
struct aa_profile * profile = NULL ;
const char * name = fqname , * info = NULL ;
2017-06-03 03:44:27 +03:00
const char * ns_name = NULL ;
2010-07-30 01:48:00 +04:00
ssize_t error = 0 ;
if ( * fqname = = 0 ) {
info = " no profile specified " ;
error = - ENOENT ;
goto fail ;
}
if ( fqname [ 0 ] = = ' : ' ) {
2017-06-03 03:44:27 +03:00
size_t ns_len ;
name = aa_splitn_fqname ( fqname , size , & ns_name , & ns_len ) ;
2013-02-21 13:14:17 +04:00
/* released below */
2017-06-09 18:14:28 +03:00
ns = aa_lookupn_ns ( policy_ns ? policy_ns : labels_ns ( subj ) ,
ns_name , ns_len ) ;
2013-02-21 13:14:17 +04:00
if ( ! ns ) {
info = " namespace does not exist " ;
error = - ENOENT ;
goto fail ;
2010-07-30 01:48:00 +04:00
}
} else
/* released below */
2017-06-09 18:14:28 +03:00
ns = aa_get_ns ( policy_ns ? policy_ns : labels_ns ( subj ) ) ;
2010-07-30 01:48:00 +04:00
if ( ! name ) {
/* remove namespace - can only happen if fqname[0] == ':' */
2017-11-21 10:24:09 +03:00
mutex_lock_nested ( & ns - > parent - > lock , ns - > level ) ;
2017-05-09 10:08:41 +03:00
__aa_bump_ns_revision ( ns ) ;
2020-01-02 16:31:22 +03:00
__aa_remove_ns ( ns ) ;
2013-07-11 08:06:43 +04:00
mutex_unlock ( & ns - > parent - > lock ) ;
2010-07-30 01:48:00 +04:00
} else {
/* remove profile */
2017-11-21 10:24:09 +03:00
mutex_lock_nested ( & ns - > lock , ns - > level ) ;
2010-07-30 01:48:00 +04:00
profile = aa_get_profile ( __lookup_profile ( & ns - > base , name ) ) ;
if ( ! profile ) {
error = - ENOENT ;
info = " profile does not exist " ;
goto fail_ns_lock ;
}
name = profile - > base . hname ;
2020-01-02 16:31:22 +03:00
__aa_bump_ns_revision ( ns ) ;
2010-07-30 01:48:00 +04:00
__remove_profile ( profile ) ;
2017-06-09 18:14:28 +03:00
__aa_labelset_update_subtree ( ns ) ;
2013-07-11 08:06:43 +04:00
mutex_unlock ( & ns - > lock ) ;
2010-07-30 01:48:00 +04:00
}
/* don't fail removal if audit fails */
2017-01-16 11:43:02 +03:00
( void ) audit_policy ( subj , OP_PROF_RM , ns_name , name , info ,
2017-01-16 11:42:57 +03:00
error ) ;
2017-01-16 11:42:16 +03:00
aa_put_ns ( ns ) ;
2010-07-30 01:48:00 +04:00
aa_put_profile ( profile ) ;
return size ;
fail_ns_lock :
2013-07-11 08:06:43 +04:00
mutex_unlock ( & ns - > lock ) ;
2017-01-16 11:42:16 +03:00
aa_put_ns ( ns ) ;
2010-07-30 01:48:00 +04:00
fail :
2017-01-16 11:43:02 +03:00
( void ) audit_policy ( subj , OP_PROF_RM , ns_name , name , info ,
2017-01-16 11:42:57 +03:00
error ) ;
2010-07-30 01:48:00 +04:00
return error ;
}