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 .
*
* 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 .
*
*
* 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"
# include "include/context.h"
# 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-01-16 11:42:15 +03:00
/* requires profile list write lock held */
2017-01-16 11:42:19 +03:00
void __aa_update_proxy ( struct aa_profile * orig , struct aa_profile * new )
2010-07-30 01:48:00 +04:00
{
2017-01-16 11:42:15 +03:00
struct aa_profile * tmp ;
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:19 +03:00
tmp = rcu_dereference_protected ( orig - > proxy - > profile ,
2017-01-16 11:42:15 +03:00
mutex_is_locked ( & orig - > ns - > lock ) ) ;
2017-01-16 11:42:19 +03:00
rcu_assign_pointer ( orig - > proxy - > profile , aa_get_profile ( new ) ) ;
2017-01-16 11:42:18 +03:00
orig - > flags | = PFLAG_STALE ;
2017-01-16 11:42:15 +03:00
aa_put_profile ( tmp ) ;
2010-07-30 01:48:00 +04:00
}
/**
* __list_add_profile - add a profile to a list
* @ 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
*/
static void __list_add_profile ( struct list_head * list ,
struct aa_profile * profile )
{
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 ) ;
}
/**
* __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 )
{
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 )
{
/* 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-01-16 11:42:19 +03:00
__aa_update_proxy ( profile , profile - > ns - > unconfined ) ;
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 ) ;
}
2013-07-11 08:07:43 +04:00
2017-01-16 11:42:19 +03:00
static void free_proxy ( struct aa_proxy * p )
2013-07-11 08:07:43 +04:00
{
2017-01-16 11:42:19 +03:00
if ( p ) {
2013-09-29 19:39:22 +04:00
/* r->profile will not be updated any more as r is dead */
2017-01-16 11:42:19 +03:00
aa_put_profile ( rcu_dereference_protected ( p - > profile , true ) ) ;
kzfree ( p ) ;
2013-07-11 08:07:43 +04:00
}
}
2017-01-16 11:42:19 +03:00
void aa_free_proxy_kref ( struct kref * kref )
2013-07-11 08:07:43 +04:00
{
2017-01-16 11:42:19 +03:00
struct aa_proxy * p = container_of ( kref , struct aa_proxy , count ) ;
free_proxy ( p ) ;
2013-07-11 08:07:43 +04:00
}
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 ;
kzfree ( data - > data ) ;
kzfree ( data - > key ) ;
kzfree ( data ) ;
}
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 ;
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 ) ;
2010-07-30 01:48:00 +04:00
kzfree ( profile - > rename ) ;
aa_free_file_rules ( & profile - > file ) ;
aa_free_cap_rules ( & profile - > caps ) ;
aa_free_rlimit_rules ( & profile - > rlimits ) ;
2013-07-11 08:13:43 +04:00
kzfree ( 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 ) ;
2017-01-16 11:42:19 +03:00
aa_put_proxy ( profile - > proxy ) ;
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 ) ;
kzfree ( rht ) ;
}
2013-10-14 22:44:34 +04:00
kzfree ( profile - > hash ) ;
2017-01-16 11:42:55 +03:00
aa_put_loaddata ( profile - > rawdata ) ;
2010-07-30 01:48:00 +04:00
kzfree ( profile ) ;
}
2013-07-11 08:06:43 +04:00
/**
* aa_free_profile_rcu - free aa_profile by rcu ( called by aa_free_profile_kref )
* @ head : rcu_head callback for freeing of a profile ( NOT NULL )
*/
static void aa_free_profile_rcu ( struct rcu_head * head )
{
2013-07-11 08:10:43 +04:00
struct aa_profile * p = container_of ( head , struct aa_profile , rcu ) ;
if ( p - > flags & PFLAG_NS_COUNT )
2017-01-16 11:42:16 +03:00
aa_free_ns ( p - > ns ) ;
2013-07-11 08:10:43 +04:00
else
2013-07-11 08:11:43 +04:00
aa_free_profile ( p ) ;
2013-07-11 08:06:43 +04:00
}
2010-07-30 01:48:00 +04:00
/**
* aa_free_profile_kref - free aa_profile by kref ( called by aa_put_profile )
* @ kr : kref callback for freeing of a profile ( NOT NULL )
*/
void aa_free_profile_kref ( struct kref * kref )
{
2013-07-11 08:08:43 +04:00
struct aa_profile * p = container_of ( kref , struct aa_profile , count ) ;
2013-07-11 08:10:43 +04:00
call_rcu ( & p - > rcu , aa_free_profile_rcu ) ;
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-01-16 11:42:35 +03:00
struct aa_profile * aa_alloc_profile ( const char * hname , gfp_t gfp )
2013-02-19 04:11:34 +04:00
{
struct aa_profile * profile ;
/* freed by free_profile - usually through aa_put_profile */
2017-01-16 11:42:35 +03:00
profile = kzalloc ( sizeof ( * profile ) , gfp ) ;
2013-02-19 04:11:34 +04:00
if ( ! profile )
return NULL ;
2017-01-16 11:42:35 +03:00
profile - > proxy = kzalloc ( sizeof ( struct aa_proxy ) , gfp ) ;
2017-01-16 11:42:19 +03:00
if ( ! profile - > proxy )
2013-07-11 08:07:43 +04:00
goto fail ;
2017-01-16 11:42:19 +03:00
kref_init ( & profile - > proxy - > count ) ;
2013-07-11 08:07:43 +04:00
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 ;
2013-07-11 08:08:43 +04:00
kref_init ( & profile - > count ) ;
2013-02-19 04:11:34 +04:00
/* refcount released by caller */
return profile ;
2013-07-11 08:07:43 +04:00
fail :
2017-01-16 11:42:19 +03:00
kzfree ( profile - > proxy ) ;
2013-07-11 08:07:43 +04:00
kzfree ( profile ) ;
return NULL ;
2013-02-19 04:11:34 +04:00
}
/**
2017-01-16 11:42:36 +03:00
* aa_new_null_profile - create or find a null - X learning profile
2013-02-19 04:11:34 +04:00
* @ parent : profile that caused this profile to be created ( NOT NULL )
* @ hat : true if the null - learning profile is a hat
2017-01-16 11:42:36 +03:00
* @ base : name to base the null profile off of
* @ gfp : type of allocation
2013-02-19 04:11:34 +04:00
*
2017-01-16 11:42:36 +03:00
* 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
2013-02-19 04:11:34 +04:00
*
* 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
*/
2017-01-16 11:42:36 +03:00
struct aa_profile * aa_new_null_profile ( struct aa_profile * parent , bool hat ,
const char * base , gfp_t gfp )
2013-02-19 04:11:34 +04:00
{
2017-01-16 11:42:36 +03:00
struct aa_profile * profile ;
2013-02-19 04:11:34 +04:00
char * name ;
2017-01-16 11:42:36 +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 ) ;
2013-02-19 04:11:34 +04:00
if ( ! name )
2017-01-16 11:42:36 +03:00
return NULL ;
sprintf ( name , " %s//null-%x " , parent - > base . hname ,
atomic_inc_return ( & parent - > ns - > uniq_null ) ) ;
2013-02-19 04:11:34 +04:00
2017-01-16 11:42:36 +03:00
name :
/* lookup to see if this is a dup creation */
profile = aa_find_child ( parent , basename ( name ) ) ;
if ( profile )
goto out ;
profile = aa_alloc_profile ( name , gfp ) ;
2013-02-19 04:11:34 +04:00
if ( ! profile )
goto fail ;
profile - > mode = APPARMOR_COMPLAIN ;
2017-01-16 11:42:36 +03:00
profile - > flags | = PFLAG_NULL ;
2013-02-19 04:11:34 +04:00
if ( hat )
profile - > flags | = PFLAG_HAT ;
2017-01-16 11:42:36 +03:00
profile - > path_flags = parent - > path_flags ;
2013-02-19 04:11:34 +04:00
/* released on free_profile */
2013-07-11 08:06:43 +04:00
rcu_assign_pointer ( profile - > parent , aa_get_profile ( parent ) ) ;
2017-01-16 11:42:16 +03:00
profile - > ns = aa_get_ns ( parent - > ns ) ;
2017-01-16 11:42:42 +03:00
profile - > file . dfa = aa_get_dfa ( nulldfa ) ;
profile - > policy . dfa = aa_get_dfa ( nulldfa ) ;
2013-02-19 04:11:34 +04:00
2013-07-11 08:06:43 +04:00
mutex_lock ( & profile - > ns - > lock ) ;
2013-02-19 04:11:34 +04:00
__list_add_profile ( & parent - > base . profiles , profile ) ;
2013-07-11 08:06:43 +04:00
mutex_unlock ( & profile - > ns - > lock ) ;
2013-02-19 04:11:34 +04:00
/* refcount released by caller */
2017-01-16 11:42:36 +03:00
out :
kfree ( name ) ;
2013-02-19 04:11:34 +04:00
return profile ;
fail :
2017-01-16 11:42:36 +03:00
kfree ( name ) ;
aa_free_profile ( profile ) ;
2013-02-19 04:11:34 +04:00
return NULL ;
}
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
}
/**
* aa_lookup_profile - find a profile by its full or partial name
* @ 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
struct aa_profile * aa_fqlookupn_profile ( struct aa_profile * base ,
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-03 03:44:27 +03:00
ns = aa_lookupn_ns ( base - > ns , ns_name , ns_len ) ;
2017-01-16 11:42:24 +03:00
if ( ! ns )
return NULL ;
} else
ns = aa_get_ns ( base - > ns ) ;
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 ;
}
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 ) {
if ( profile - > flags & PFLAG_IMMUTABLE ) {
* info = " cannot replace immutible profile " ;
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
/**
* aa_audit_policy - Do auditing of policy changes
2017-01-16 11:42:49 +03:00
* @ profile : profile to check if it can manage policy
2010-07-30 01:48:00 +04:00
* @ op : policy operation being performed
* @ gfp : memory allocation flags
2017-01-16 11:42:54 +03:00
* @ nsname : name of the ns being manipulated ( MAY BE NULL )
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-01-16 11:43:02 +03:00
static int audit_policy ( struct aa_profile * profile , const char * op ,
2017-01-16 11:42:54 +03:00
const char * nsname , const char * name ,
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 ) ;
aad ( & sa ) - > iface . ns = nsname ;
aad ( & sa ) - > name = name ;
aad ( & sa ) - > info = info ;
aad ( & sa ) - > error = error ;
return aa_audit ( AUDIT_APPARMOR_STATUS , profile , & sa , audit_cb ) ;
2010-07-30 01:48:00 +04:00
}
2017-01-16 11:42:50 +03:00
/**
* policy_view_capable - check if viewing policy in at @ ns is allowed
* ns : namespace being viewed by current task ( may be NULL )
* Returns : true if viewing policy is allowed
*
* If @ ns is NULL then the namespace being viewed is assumed to be the
* tasks current namespace .
*/
bool policy_view_capable ( struct aa_ns * ns )
2016-06-23 04:01:08 +03:00
{
struct user_namespace * user_ns = current_user_ns ( ) ;
2017-01-16 11:42:50 +03:00
struct aa_ns * view_ns = aa_get_current_ns ( ) ;
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 ;
2017-01-16 11:42:50 +03:00
aa_put_ns ( view_ns ) ;
2016-06-23 04:01:08 +03:00
return response ;
}
2017-01-16 11:42:51 +03:00
bool policy_admin_capable ( 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 ( ) ;
bool capable = ns_capable ( user_ns , CAP_MAC_ADMIN ) ;
AA_DEBUG ( " cap_mac_admin? %d \n " , capable ) ;
AA_DEBUG ( " policy locked? %d \n " , aa_g_lock_policy ) ;
return policy_view_capable ( ns ) & & capable & & ! aa_g_lock_policy ;
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-01-16 11:42:52 +03:00
* @ profile : profile 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-05-26 11:45:08 +03:00
int aa_may_manage_policy ( struct aa_profile * profile , 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-05-26 11:45:08 +03:00
return audit_policy ( profile , op , NULL , NULL , " policy_locked " ,
- EACCES ) ;
2010-07-30 01:48:00 +04:00
2017-01-16 11:42:52 +03:00
if ( ! policy_admin_capable ( ns ) )
2017-05-26 11:45:08 +03:00
return audit_policy ( profile , op , NULL , NULL , " not policy admin " ,
- 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
*/
2013-07-11 08:07:43 +04:00
static void __replace_profile ( struct aa_profile * old , struct aa_profile * new ,
2017-01-16 11:42:19 +03:00
bool share_proxy )
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-01-16 11:42:19 +03:00
__replace_profile ( child , p , share_proxy ) ;
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-01-16 11:42:19 +03:00
__aa_update_proxy ( old , new ) ;
if ( share_proxy ) {
aa_put_proxy ( new - > proxy ) ;
new - > proxy = aa_get_proxy ( old - > proxy ) ;
} else if ( ! rcu_access_pointer ( new - > proxy - > profile ) )
/* aafs interface uses proxy */
rcu_assign_pointer ( new - > proxy - > profile ,
2013-07-11 08:13:43 +04:00
aa_get_profile ( new ) ) ;
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 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-16 11:43:00 +03:00
* by any aa_task_ctx . If the profile does not exist on the profile list
2010-07-30 01:48:00 +04:00
* it is added .
*
* Returns : size of data consumed else error code on failure .
*/
2017-06-04 22:22:22 +03:00
ssize_t aa_replace_profiles ( struct aa_ns * policy_ns , struct aa_profile * profile ,
2017-05-26 11:45:08 +03:00
u32 mask , struct aa_loaddata * udata )
2010-07-30 01:48:00 +04:00
{
2016-04-17 00:16:50 +03:00
const char * ns_name , * 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-04 22:22:22 +03:00
ns = aa_prepare_ns ( policy_ns ? policy_ns : profile - > ns ,
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-04 22:22:22 +03:00
ns = aa_get_ns ( policy_ns ? policy_ns : profile - > ns ) ;
2010-07-30 01:48:00 +04:00
2013-07-11 08:06:43 +04:00
mutex_lock ( & ns - > lock ) ;
2017-05-09 10:08:41 +03:00
/* check for duplicate rawdata blobs: space and file dedup */
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 ;
}
}
}
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
2017-01-16 11:42:55 +03:00
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-05-26 11:45:08 +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 */
2017-05-09 10:08:41 +03:00
if ( ! udata - > dents [ AAFS_LOADDATA_DIR ] ) {
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 ) {
if ( ent - > old ) {
/* inherit old interface files */
/* if (ent->rename)
TODO : support rename */
/* } else if (ent->rename) {
TODO : support rename */
} else {
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 ) {
info = " failed to create " ;
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 ) ;
__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 ;
2017-05-09 10:08:41 +03:00
if ( ent - > old & & ent - > old - > rawdata = = ent - > new - > rawdata ) {
/* dedup actual profile replacement */
audit_policy ( profile , op , ns_name , ent - > new - > base . hname ,
" same as current profile, skipping " ,
error ) ;
goto skip ;
}
/*
* TODO : finer dedup based on profile range in data . Load set
* can differ but profile may remain unchanged
*/
2017-01-16 11:43:02 +03:00
audit_policy ( profile , op , NULL , 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 ) ;
2013-07-11 08:07:43 +04:00
__replace_profile ( ent - > old , ent - > new , 1 ) ;
2013-07-11 08:13:43 +04:00
if ( ent - > rename ) {
2017-01-16 11:42:19 +03:00
/* aafs interface uses proxy */
struct aa_proxy * r = ent - > new - > proxy ;
2013-07-11 08:13:43 +04:00
rcu_assign_pointer ( r - > profile ,
aa_get_profile ( ent - > new ) ) ;
2013-07-11 08:07:43 +04:00
__replace_profile ( ent - > rename , ent - > new , 0 ) ;
2013-07-11 08:13:43 +04:00
}
2013-07-11 08:05:43 +04:00
} else if ( ent - > rename ) {
2017-01-16 11:42:19 +03:00
/* aafs interface uses proxy */
rcu_assign_pointer ( ent - > new - > proxy - > profile ,
2013-07-11 08:13:43 +04:00
aa_get_profile ( ent - > new ) ) ;
2013-07-11 08:07:43 +04:00
__replace_profile ( ent - > rename , ent - > new , 0 ) ;
2013-07-11 08:05:43 +04:00
} else if ( ent - > new - > parent ) {
2013-07-11 08:06:43 +04:00
struct aa_profile * parent , * newest ;
2013-07-11 08:13:43 +04:00
parent = aa_deref_parent ( ent - > new ) ;
2013-07-11 08:07:43 +04:00
newest = aa_get_newest_profile ( parent ) ;
2013-07-11 08:06:43 +04:00
2013-07-11 08:05:43 +04:00
/* parent replaced in this atomic set? */
2013-07-11 08:06:43 +04:00
if ( newest ! = parent ) {
aa_get_profile ( newest ) ;
rcu_assign_pointer ( ent - > new - > parent , newest ) ;
2016-04-16 23:59:02 +03:00
aa_put_profile ( parent ) ;
2016-04-12 02:55:10 +03:00
}
2017-01-16 11:42:19 +03:00
/* aafs interface uses proxy */
rcu_assign_pointer ( ent - > new - > proxy - > profile ,
2013-07-11 08:13:43 +04:00
aa_get_profile ( ent - > new ) ) ;
2016-04-12 02:57:19 +03:00
__list_add_profile ( & newest - > base . profiles , ent - > new ) ;
2016-04-12 02:55:10 +03:00
aa_put_profile ( newest ) ;
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 ;
__list_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
}
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 ) ;
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-04-06 16:55:22 +03:00
audit_policy ( profile , op , ns_name , ent ? ent - > new - > base . hname : NULL ,
2017-01-16 11:42:57 +03:00
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-01-16 11:43:02 +03:00
audit_policy ( profile , op , ns_name ,
2017-01-16 11:42:49 +03:00
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-01-16 11:42:57 +03:00
* @ subj : profile 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
*
* NOTE : removing confinement does not restore rlimits to preconfinemnet values
*
* Returns : size of data consume else error code if fails
*/
2017-06-04 22:22:22 +03:00
ssize_t aa_remove_profiles ( struct aa_ns * policy_ns , struct aa_profile * 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-04 22:22:22 +03:00
ns = aa_lookupn_ns ( policy_ns ? policy_ns : subj - > ns , 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-04 22:22:22 +03:00
ns = aa_get_ns ( policy_ns ? policy_ns : subj - > ns ) ;
2010-07-30 01:48:00 +04:00
if ( ! name ) {
/* remove namespace - can only happen if fqname[0] == ':' */
2013-07-11 08:06:43 +04:00
mutex_lock ( & ns - > parent - > lock ) ;
2017-01-16 11:42:16 +03:00
__aa_remove_ns ( ns ) ;
2017-05-09 10:08:41 +03:00
__aa_bump_ns_revision ( 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 */
2013-07-11 08:06:43 +04:00
mutex_lock ( & ns - > lock ) ;
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 ;
__remove_profile ( profile ) ;
2017-05-09 10:08:41 +03:00
__aa_bump_ns_revision ( 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 ;
}