2009-02-05 17:18:15 +09:00
/*
* security / tomoyo / domain . c
*
* Implementation of the Domain - Based Mandatory Access Control .
*
* Copyright ( C ) 2005 - 2009 NTT DATA CORPORATION
*
* Version : 2.2 .0 - pre 2009 / 02 / 01
*
*/
# include "common.h"
# include "tomoyo.h"
# include "realpath.h"
# include <linux/binfmts.h>
/* Variables definitions.*/
/* The initial domain. */
struct tomoyo_domain_info tomoyo_kernel_domain ;
/* The list for "struct tomoyo_domain_info". */
LIST_HEAD ( tomoyo_domain_list ) ;
DECLARE_RWSEM ( tomoyo_domain_list_lock ) ;
/* Structure for "initialize_domain" and "no_initialize_domain" keyword. */
struct tomoyo_domain_initializer_entry {
struct list_head list ;
const struct tomoyo_path_info * domainname ; /* This may be NULL */
const struct tomoyo_path_info * program ;
bool is_deleted ;
bool is_not ; /* True if this entry is "no_initialize_domain". */
/* True if the domainname is tomoyo_get_last_name(). */
bool is_last_name ;
} ;
/* Structure for "keep_domain" and "no_keep_domain" keyword. */
struct tomoyo_domain_keeper_entry {
struct list_head list ;
const struct tomoyo_path_info * domainname ;
const struct tomoyo_path_info * program ; /* This may be NULL */
bool is_deleted ;
bool is_not ; /* True if this entry is "no_keep_domain". */
/* True if the domainname is tomoyo_get_last_name(). */
bool is_last_name ;
} ;
/* Structure for "alias" keyword. */
struct tomoyo_alias_entry {
struct list_head list ;
const struct tomoyo_path_info * original_name ;
const struct tomoyo_path_info * aliased_name ;
bool is_deleted ;
} ;
/**
* tomoyo_set_domain_flag - Set or clear domain ' s attribute flags .
*
* @ domain : Pointer to " struct tomoyo_domain_info " .
* @ is_delete : True if it is a delete request .
* @ flags : Flags to set or clear .
*
* Returns nothing .
*/
void tomoyo_set_domain_flag ( struct tomoyo_domain_info * domain ,
const bool is_delete , const u8 flags )
{
/* We need to serialize because this is bitfield operation. */
static DEFINE_SPINLOCK ( lock ) ;
/***** CRITICAL SECTION START *****/
spin_lock ( & lock ) ;
if ( ! is_delete )
domain - > flags | = flags ;
else
domain - > flags & = ~ flags ;
spin_unlock ( & lock ) ;
/***** CRITICAL SECTION END *****/
}
/**
* tomoyo_get_last_name - Get last component of a domainname .
*
* @ domain : Pointer to " struct tomoyo_domain_info " .
*
* Returns the last component of the domainname .
*/
const char * tomoyo_get_last_name ( const struct tomoyo_domain_info * domain )
{
const char * cp0 = domain - > domainname - > name ;
const char * cp1 = strrchr ( cp0 , ' ' ) ;
if ( cp1 )
return cp1 + 1 ;
return cp0 ;
}
/* The list for "struct tomoyo_domain_initializer_entry". */
static LIST_HEAD ( tomoyo_domain_initializer_list ) ;
static DECLARE_RWSEM ( tomoyo_domain_initializer_list_lock ) ;
/**
* tomoyo_update_domain_initializer_entry - Update " struct tomoyo_domain_initializer_entry " list .
*
* @ domainname : The name of domain . May be NULL .
* @ program : The name of program .
* @ is_not : True if it is " no_initialize_domain " entry .
* @ is_delete : True if it is a delete request .
*
* Returns 0 on success , negative value otherwise .
*/
static int tomoyo_update_domain_initializer_entry ( const char * domainname ,
const char * program ,
const bool is_not ,
const bool is_delete )
{
struct tomoyo_domain_initializer_entry * new_entry ;
struct tomoyo_domain_initializer_entry * ptr ;
const struct tomoyo_path_info * saved_program ;
const struct tomoyo_path_info * saved_domainname = NULL ;
int error = - ENOMEM ;
bool is_last_name = false ;
if ( ! tomoyo_is_correct_path ( program , 1 , - 1 , - 1 , __func__ ) )
return - EINVAL ; /* No patterns allowed. */
if ( domainname ) {
if ( ! tomoyo_is_domain_def ( domainname ) & &
tomoyo_is_correct_path ( domainname , 1 , - 1 , - 1 , __func__ ) )
is_last_name = true ;
else if ( ! tomoyo_is_correct_domain ( domainname , __func__ ) )
return - EINVAL ;
saved_domainname = tomoyo_save_name ( domainname ) ;
if ( ! saved_domainname )
return - ENOMEM ;
}
saved_program = tomoyo_save_name ( program ) ;
if ( ! saved_program )
return - ENOMEM ;
/***** EXCLUSIVE SECTION START *****/
down_write ( & tomoyo_domain_initializer_list_lock ) ;
list_for_each_entry ( ptr , & tomoyo_domain_initializer_list , list ) {
if ( ptr - > is_not ! = is_not | |
ptr - > domainname ! = saved_domainname | |
ptr - > program ! = saved_program )
continue ;
ptr - > is_deleted = is_delete ;
error = 0 ;
goto out ;
}
if ( is_delete ) {
error = - ENOENT ;
goto out ;
}
new_entry = tomoyo_alloc_element ( sizeof ( * new_entry ) ) ;
if ( ! new_entry )
goto out ;
new_entry - > domainname = saved_domainname ;
new_entry - > program = saved_program ;
new_entry - > is_not = is_not ;
new_entry - > is_last_name = is_last_name ;
list_add_tail ( & new_entry - > list , & tomoyo_domain_initializer_list ) ;
error = 0 ;
out :
up_write ( & tomoyo_domain_initializer_list_lock ) ;
/***** EXCLUSIVE SECTION END *****/
return error ;
}
/**
* tomoyo_read_domain_initializer_policy - Read " struct tomoyo_domain_initializer_entry " list .
*
* @ head : Pointer to " struct tomoyo_io_buffer " .
*
* Returns true on success , false otherwise .
*/
bool tomoyo_read_domain_initializer_policy ( struct tomoyo_io_buffer * head )
{
struct list_head * pos ;
bool done = true ;
down_read ( & tomoyo_domain_initializer_list_lock ) ;
list_for_each_cookie ( pos , head - > read_var2 ,
& tomoyo_domain_initializer_list ) {
const char * no ;
const char * from = " " ;
const char * domain = " " ;
struct tomoyo_domain_initializer_entry * ptr ;
ptr = list_entry ( pos , struct tomoyo_domain_initializer_entry ,
list ) ;
if ( ptr - > is_deleted )
continue ;
no = ptr - > is_not ? " no_ " : " " ;
if ( ptr - > domainname ) {
from = " from " ;
domain = ptr - > domainname - > name ;
}
if ( ! tomoyo_io_printf ( head ,
" %s " TOMOYO_KEYWORD_INITIALIZE_DOMAIN
" %s%s%s \n " , no , ptr - > program - > name , from ,
domain ) ) {
done = false ;
break ;
}
}
up_read ( & tomoyo_domain_initializer_list_lock ) ;
return done ;
}
/**
* tomoyo_write_domain_initializer_policy - Write " struct tomoyo_domain_initializer_entry " list .
*
* @ data : String to parse .
* @ is_not : True if it is " no_initialize_domain " entry .
* @ is_delete : True if it is a delete request .
*
* Returns 0 on success , negative value otherwise .
*/
int tomoyo_write_domain_initializer_policy ( char * data , const bool is_not ,
const bool is_delete )
{
char * cp = strstr ( data , " from " ) ;
if ( cp ) {
* cp = ' \0 ' ;
return tomoyo_update_domain_initializer_entry ( cp + 6 , data ,
is_not ,
is_delete ) ;
}
return tomoyo_update_domain_initializer_entry ( NULL , data , is_not ,
is_delete ) ;
}
/**
* tomoyo_is_domain_initializer - Check whether the given program causes domainname reinitialization .
*
* @ domainname : The name of domain .
* @ program : The name of program .
* @ last_name : The last component of @ domainname .
*
* Returns true if executing @ program reinitializes domain transition ,
* false otherwise .
*/
static bool tomoyo_is_domain_initializer ( const struct tomoyo_path_info *
domainname ,
const struct tomoyo_path_info * program ,
const struct tomoyo_path_info *
last_name )
{
struct tomoyo_domain_initializer_entry * ptr ;
bool flag = false ;
down_read ( & tomoyo_domain_initializer_list_lock ) ;
list_for_each_entry ( ptr , & tomoyo_domain_initializer_list , list ) {
if ( ptr - > is_deleted )
continue ;
if ( ptr - > domainname ) {
if ( ! ptr - > is_last_name ) {
if ( ptr - > domainname ! = domainname )
continue ;
} else {
if ( tomoyo_pathcmp ( ptr - > domainname , last_name ) )
continue ;
}
}
if ( tomoyo_pathcmp ( ptr - > program , program ) )
continue ;
if ( ptr - > is_not ) {
flag = false ;
break ;
}
flag = true ;
}
up_read ( & tomoyo_domain_initializer_list_lock ) ;
return flag ;
}
/* The list for "struct tomoyo_domain_keeper_entry". */
static LIST_HEAD ( tomoyo_domain_keeper_list ) ;
static DECLARE_RWSEM ( tomoyo_domain_keeper_list_lock ) ;
/**
* tomoyo_update_domain_keeper_entry - Update " struct tomoyo_domain_keeper_entry " list .
*
* @ domainname : The name of domain .
* @ program : The name of program . May be NULL .
* @ is_not : True if it is " no_keep_domain " entry .
* @ is_delete : True if it is a delete request .
*
* Returns 0 on success , negative value otherwise .
*/
static int tomoyo_update_domain_keeper_entry ( const char * domainname ,
const char * program ,
const bool is_not ,
const bool is_delete )
{
struct tomoyo_domain_keeper_entry * new_entry ;
struct tomoyo_domain_keeper_entry * ptr ;
const struct tomoyo_path_info * saved_domainname ;
const struct tomoyo_path_info * saved_program = NULL ;
static DEFINE_MUTEX ( lock ) ;
int error = - ENOMEM ;
bool is_last_name = false ;
if ( ! tomoyo_is_domain_def ( domainname ) & &
tomoyo_is_correct_path ( domainname , 1 , - 1 , - 1 , __func__ ) )
is_last_name = true ;
else if ( ! tomoyo_is_correct_domain ( domainname , __func__ ) )
return - EINVAL ;
if ( program ) {
if ( ! tomoyo_is_correct_path ( program , 1 , - 1 , - 1 , __func__ ) )
return - EINVAL ;
saved_program = tomoyo_save_name ( program ) ;
if ( ! saved_program )
return - ENOMEM ;
}
saved_domainname = tomoyo_save_name ( domainname ) ;
if ( ! saved_domainname )
return - ENOMEM ;
/***** EXCLUSIVE SECTION START *****/
down_write ( & tomoyo_domain_keeper_list_lock ) ;
list_for_each_entry ( ptr , & tomoyo_domain_keeper_list , list ) {
if ( ptr - > is_not ! = is_not | |
ptr - > domainname ! = saved_domainname | |
ptr - > program ! = saved_program )
continue ;
ptr - > is_deleted = is_delete ;
error = 0 ;
goto out ;
}
if ( is_delete ) {
error = - ENOENT ;
goto out ;
}
new_entry = tomoyo_alloc_element ( sizeof ( * new_entry ) ) ;
if ( ! new_entry )
goto out ;
new_entry - > domainname = saved_domainname ;
new_entry - > program = saved_program ;
new_entry - > is_not = is_not ;
new_entry - > is_last_name = is_last_name ;
list_add_tail ( & new_entry - > list , & tomoyo_domain_keeper_list ) ;
error = 0 ;
out :
up_write ( & tomoyo_domain_keeper_list_lock ) ;
/***** EXCLUSIVE SECTION END *****/
return error ;
}
/**
* tomoyo_write_domain_keeper_policy - Write " struct tomoyo_domain_keeper_entry " list .
*
* @ data : String to parse .
* @ is_not : True if it is " no_keep_domain " entry .
* @ is_delete : True if it is a delete request .
*
*/
int tomoyo_write_domain_keeper_policy ( char * data , const bool is_not ,
const bool is_delete )
{
char * cp = strstr ( data , " from " ) ;
if ( cp ) {
* cp = ' \0 ' ;
return tomoyo_update_domain_keeper_entry ( cp + 6 , data , is_not ,
is_delete ) ;
}
return tomoyo_update_domain_keeper_entry ( data , NULL , is_not , is_delete ) ;
}
/**
* tomoyo_read_domain_keeper_policy - Read " struct tomoyo_domain_keeper_entry " list .
*
* @ head : Pointer to " struct tomoyo_io_buffer " .
*
* Returns true on success , false otherwise .
*/
bool tomoyo_read_domain_keeper_policy ( struct tomoyo_io_buffer * head )
{
struct list_head * pos ;
2009-02-13 16:00:58 +09:00
bool done = true ;
2009-02-05 17:18:15 +09:00
down_read ( & tomoyo_domain_keeper_list_lock ) ;
list_for_each_cookie ( pos , head - > read_var2 ,
& tomoyo_domain_keeper_list ) {
struct tomoyo_domain_keeper_entry * ptr ;
const char * no ;
const char * from = " " ;
const char * program = " " ;
ptr = list_entry ( pos , struct tomoyo_domain_keeper_entry , list ) ;
if ( ptr - > is_deleted )
continue ;
no = ptr - > is_not ? " no_ " : " " ;
if ( ptr - > program ) {
from = " from " ;
program = ptr - > program - > name ;
}
if ( ! tomoyo_io_printf ( head ,
" %s " TOMOYO_KEYWORD_KEEP_DOMAIN
" %s%s%s \n " , no , program , from ,
ptr - > domainname - > name ) ) {
done = false ;
break ;
}
}
up_read ( & tomoyo_domain_keeper_list_lock ) ;
return done ;
}
/**
* tomoyo_is_domain_keeper - Check whether the given program causes domain transition suppression .
*
* @ domainname : The name of domain .
* @ program : The name of program .
* @ last_name : The last component of @ domainname .
*
* Returns true if executing @ program supresses domain transition ,
* false otherwise .
*/
static bool tomoyo_is_domain_keeper ( const struct tomoyo_path_info * domainname ,
const struct tomoyo_path_info * program ,
const struct tomoyo_path_info * last_name )
{
struct tomoyo_domain_keeper_entry * ptr ;
bool flag = false ;
down_read ( & tomoyo_domain_keeper_list_lock ) ;
list_for_each_entry ( ptr , & tomoyo_domain_keeper_list , list ) {
if ( ptr - > is_deleted )
continue ;
if ( ! ptr - > is_last_name ) {
if ( ptr - > domainname ! = domainname )
continue ;
} else {
if ( tomoyo_pathcmp ( ptr - > domainname , last_name ) )
continue ;
}
if ( ptr - > program & & tomoyo_pathcmp ( ptr - > program , program ) )
continue ;
if ( ptr - > is_not ) {
flag = false ;
break ;
}
flag = true ;
}
up_read ( & tomoyo_domain_keeper_list_lock ) ;
return flag ;
}
/* The list for "struct tomoyo_alias_entry". */
static LIST_HEAD ( tomoyo_alias_list ) ;
static DECLARE_RWSEM ( tomoyo_alias_list_lock ) ;
/**
* tomoyo_update_alias_entry - Update " struct tomoyo_alias_entry " list .
*
* @ original_name : The original program ' s real name .
* @ aliased_name : The symbolic program ' s symbolic link ' s name .
* @ is_delete : True if it is a delete request .
*
* Returns 0 on success , negative value otherwise .
*/
static int tomoyo_update_alias_entry ( const char * original_name ,
const char * aliased_name ,
const bool is_delete )
{
struct tomoyo_alias_entry * new_entry ;
struct tomoyo_alias_entry * ptr ;
const struct tomoyo_path_info * saved_original_name ;
const struct tomoyo_path_info * saved_aliased_name ;
int error = - ENOMEM ;
if ( ! tomoyo_is_correct_path ( original_name , 1 , - 1 , - 1 , __func__ ) | |
! tomoyo_is_correct_path ( aliased_name , 1 , - 1 , - 1 , __func__ ) )
return - EINVAL ; /* No patterns allowed. */
saved_original_name = tomoyo_save_name ( original_name ) ;
saved_aliased_name = tomoyo_save_name ( aliased_name ) ;
if ( ! saved_original_name | | ! saved_aliased_name )
return - ENOMEM ;
/***** EXCLUSIVE SECTION START *****/
down_write ( & tomoyo_alias_list_lock ) ;
list_for_each_entry ( ptr , & tomoyo_alias_list , list ) {
if ( ptr - > original_name ! = saved_original_name | |
ptr - > aliased_name ! = saved_aliased_name )
continue ;
ptr - > is_deleted = is_delete ;
error = 0 ;
goto out ;
}
if ( is_delete ) {
error = - ENOENT ;
goto out ;
}
new_entry = tomoyo_alloc_element ( sizeof ( * new_entry ) ) ;
if ( ! new_entry )
goto out ;
new_entry - > original_name = saved_original_name ;
new_entry - > aliased_name = saved_aliased_name ;
list_add_tail ( & new_entry - > list , & tomoyo_alias_list ) ;
error = 0 ;
out :
up_write ( & tomoyo_alias_list_lock ) ;
/***** EXCLUSIVE SECTION END *****/
return error ;
}
/**
* tomoyo_read_alias_policy - Read " struct tomoyo_alias_entry " list .
*
* @ head : Pointer to " struct tomoyo_io_buffer " .
*
* Returns true on success , false otherwise .
*/
bool tomoyo_read_alias_policy ( struct tomoyo_io_buffer * head )
{
struct list_head * pos ;
bool done = true ;
down_read ( & tomoyo_alias_list_lock ) ;
list_for_each_cookie ( pos , head - > read_var2 , & tomoyo_alias_list ) {
struct tomoyo_alias_entry * ptr ;
ptr = list_entry ( pos , struct tomoyo_alias_entry , list ) ;
if ( ptr - > is_deleted )
continue ;
if ( ! tomoyo_io_printf ( head , TOMOYO_KEYWORD_ALIAS " %s %s \n " ,
ptr - > original_name - > name ,
ptr - > aliased_name - > name ) ) {
done = false ;
break ;
}
}
up_read ( & tomoyo_alias_list_lock ) ;
return done ;
}
/**
* tomoyo_write_alias_policy - Write " struct tomoyo_alias_entry " list .
*
* @ data : String to parse .
* @ is_delete : True if it is a delete request .
*
* Returns 0 on success , negative value otherwise .
*/
int tomoyo_write_alias_policy ( char * data , const bool is_delete )
{
char * cp = strchr ( data , ' ' ) ;
if ( ! cp )
return - EINVAL ;
* cp + + = ' \0 ' ;
return tomoyo_update_alias_entry ( data , cp , is_delete ) ;
}
/* Domain create/delete/undelete handler. */
/* #define TOMOYO_DEBUG_DOMAIN_UNDELETE */
/**
* tomoyo_delete_domain - Delete a domain .
*
* @ domainname : The name of domain .
*
* Returns 0.
*/
int tomoyo_delete_domain ( char * domainname )
{
struct tomoyo_domain_info * domain ;
struct tomoyo_path_info name ;
name . name = domainname ;
tomoyo_fill_path_info ( & name ) ;
/***** EXCLUSIVE SECTION START *****/
down_write ( & tomoyo_domain_list_lock ) ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
printk ( KERN_DEBUG " tomoyo_delete_domain %s \n " , domainname ) ;
list_for_each_entry ( domain , & tomoyo_domain_list , list ) {
if ( tomoyo_pathcmp ( domain - > domainname , & name ) )
continue ;
printk ( KERN_DEBUG " List: %p %u \n " , domain , domain - > is_deleted ) ;
}
# endif
/* Is there an active domain? */
list_for_each_entry ( domain , & tomoyo_domain_list , list ) {
struct tomoyo_domain_info * domain2 ;
/* Never delete tomoyo_kernel_domain */
if ( domain = = & tomoyo_kernel_domain )
continue ;
if ( domain - > is_deleted | |
tomoyo_pathcmp ( domain - > domainname , & name ) )
continue ;
/* Mark already deleted domains as non undeletable. */
list_for_each_entry ( domain2 , & tomoyo_domain_list , list ) {
if ( ! domain2 - > is_deleted | |
tomoyo_pathcmp ( domain2 - > domainname , & name ) )
continue ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
if ( domain2 - > is_deleted ! = 255 )
printk ( KERN_DEBUG
" Marked %p as non undeletable \n " ,
domain2 ) ;
# endif
domain2 - > is_deleted = 255 ;
}
/* Delete and mark active domain as undeletable. */
domain - > is_deleted = 1 ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
printk ( KERN_DEBUG " Marked %p as undeletable \n " , domain ) ;
# endif
break ;
}
up_write ( & tomoyo_domain_list_lock ) ;
/***** EXCLUSIVE SECTION END *****/
return 0 ;
}
/**
* tomoyo_undelete_domain - Undelete a domain .
*
* @ domainname : The name of domain .
*
* Returns pointer to " struct tomoyo_domain_info " on success , NULL otherwise .
*/
struct tomoyo_domain_info * tomoyo_undelete_domain ( const char * domainname )
{
struct tomoyo_domain_info * domain ;
struct tomoyo_domain_info * candidate_domain = NULL ;
struct tomoyo_path_info name ;
name . name = domainname ;
tomoyo_fill_path_info ( & name ) ;
/***** EXCLUSIVE SECTION START *****/
down_write ( & tomoyo_domain_list_lock ) ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
printk ( KERN_DEBUG " tomoyo_undelete_domain %s \n " , domainname ) ;
list_for_each_entry ( domain , & tomoyo_domain_list , list ) {
if ( tomoyo_pathcmp ( domain - > domainname , & name ) )
continue ;
printk ( KERN_DEBUG " List: %p %u \n " , domain , domain - > is_deleted ) ;
}
# endif
list_for_each_entry ( domain , & tomoyo_domain_list , list ) {
if ( tomoyo_pathcmp ( & name , domain - > domainname ) )
continue ;
if ( ! domain - > is_deleted ) {
/* This domain is active. I can't undelete. */
candidate_domain = NULL ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
printk ( KERN_DEBUG " %p is active. I can't undelete. \n " ,
domain ) ;
# endif
break ;
}
/* Is this domain undeletable? */
if ( domain - > is_deleted = = 1 )
candidate_domain = domain ;
}
if ( candidate_domain ) {
candidate_domain - > is_deleted = 0 ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
printk ( KERN_DEBUG " %p was undeleted. \n " , candidate_domain ) ;
# endif
}
up_write ( & tomoyo_domain_list_lock ) ;
/***** EXCLUSIVE SECTION END *****/
return candidate_domain ;
}
/**
* tomoyo_find_or_assign_new_domain - Create a domain .
*
* @ domainname : The name of domain .
* @ profile : Profile number to assign if the domain was newly created .
*
* Returns pointer to " struct tomoyo_domain_info " on success , NULL otherwise .
*/
struct tomoyo_domain_info * tomoyo_find_or_assign_new_domain ( const char *
domainname ,
const u8 profile )
{
struct tomoyo_domain_info * domain = NULL ;
const struct tomoyo_path_info * saved_domainname ;
/***** EXCLUSIVE SECTION START *****/
down_write ( & tomoyo_domain_list_lock ) ;
domain = tomoyo_find_domain ( domainname ) ;
if ( domain )
goto out ;
if ( ! tomoyo_is_correct_domain ( domainname , __func__ ) )
goto out ;
saved_domainname = tomoyo_save_name ( domainname ) ;
if ( ! saved_domainname )
goto out ;
/* Can I reuse memory of deleted domain? */
list_for_each_entry ( domain , & tomoyo_domain_list , list ) {
struct task_struct * p ;
struct tomoyo_acl_info * ptr ;
bool flag ;
if ( ! domain - > is_deleted | |
domain - > domainname ! = saved_domainname )
continue ;
flag = false ;
/***** CRITICAL SECTION START *****/
read_lock ( & tasklist_lock ) ;
for_each_process ( p ) {
if ( tomoyo_real_domain ( p ) ! = domain )
continue ;
flag = true ;
break ;
}
read_unlock ( & tasklist_lock ) ;
/***** CRITICAL SECTION END *****/
if ( flag )
continue ;
# ifdef TOMOYO_DEBUG_DOMAIN_UNDELETE
printk ( KERN_DEBUG " Reusing %p %s \n " , domain ,
domain - > domainname - > name ) ;
# endif
list_for_each_entry ( ptr , & domain - > acl_info_list , list ) {
ptr - > type | = TOMOYO_ACL_DELETED ;
}
tomoyo_set_domain_flag ( domain , true , domain - > flags ) ;
domain - > profile = profile ;
domain - > quota_warned = false ;
mb ( ) ; /* Avoid out-of-order execution. */
domain - > is_deleted = 0 ;
goto out ;
}
/* No memory reusable. Create using new memory. */
domain = tomoyo_alloc_element ( sizeof ( * domain ) ) ;
if ( domain ) {
INIT_LIST_HEAD ( & domain - > acl_info_list ) ;
domain - > domainname = saved_domainname ;
domain - > profile = profile ;
list_add_tail ( & domain - > list , & tomoyo_domain_list ) ;
}
out :
up_write ( & tomoyo_domain_list_lock ) ;
/***** EXCLUSIVE SECTION END *****/
return domain ;
}
/**
* tomoyo_find_next_domain - Find a domain .
*
* @ bprm : Pointer to " struct linux_binprm " .
* @ next_domain : Pointer to pointer to " struct tomoyo_domain_info " .
*
* Returns 0 on success , negative value otherwise .
*/
int tomoyo_find_next_domain ( struct linux_binprm * bprm ,
struct tomoyo_domain_info * * next_domain )
{
/*
* This function assumes that the size of buffer returned by
* tomoyo_realpath ( ) = TOMOYO_MAX_PATHNAME_LEN .
*/
struct tomoyo_page_buffer * tmp = tomoyo_alloc ( sizeof ( * tmp ) ) ;
struct tomoyo_domain_info * old_domain = tomoyo_domain ( ) ;
struct tomoyo_domain_info * domain = NULL ;
const char * old_domain_name = old_domain - > domainname - > name ;
const char * original_name = bprm - > filename ;
char * new_domain_name = NULL ;
char * real_program_name = NULL ;
char * symlink_program_name = NULL ;
const u8 mode = tomoyo_check_flags ( old_domain , TOMOYO_MAC_FOR_FILE ) ;
const bool is_enforce = ( mode = = 3 ) ;
int retval = - ENOMEM ;
struct tomoyo_path_info r ; /* real name */
struct tomoyo_path_info s ; /* symlink name */
struct tomoyo_path_info l ; /* last name */
static bool initialized ;
if ( ! tmp )
goto out ;
if ( ! initialized ) {
/*
* Built - in initializers . This is needed because policies are
* not loaded until starting / sbin / init .
*/
tomoyo_update_domain_initializer_entry ( NULL , " /sbin/hotplug " ,
false , false ) ;
tomoyo_update_domain_initializer_entry ( NULL , " /sbin/modprobe " ,
false , false ) ;
initialized = true ;
}
/* Get tomoyo_realpath of program. */
retval = - ENOENT ;
/* I hope tomoyo_realpath() won't fail with -ENOMEM. */
real_program_name = tomoyo_realpath ( original_name ) ;
if ( ! real_program_name )
goto out ;
/* Get tomoyo_realpath of symbolic link. */
symlink_program_name = tomoyo_realpath_nofollow ( original_name ) ;
if ( ! symlink_program_name )
goto out ;
r . name = real_program_name ;
tomoyo_fill_path_info ( & r ) ;
s . name = symlink_program_name ;
tomoyo_fill_path_info ( & s ) ;
l . name = tomoyo_get_last_name ( old_domain ) ;
tomoyo_fill_path_info ( & l ) ;
/* Check 'alias' directive. */
if ( tomoyo_pathcmp ( & r , & s ) ) {
struct tomoyo_alias_entry * ptr ;
/* Is this program allowed to be called via symbolic links? */
down_read ( & tomoyo_alias_list_lock ) ;
list_for_each_entry ( ptr , & tomoyo_alias_list , list ) {
if ( ptr - > is_deleted | |
tomoyo_pathcmp ( & r , ptr - > original_name ) | |
tomoyo_pathcmp ( & s , ptr - > aliased_name ) )
continue ;
memset ( real_program_name , 0 , TOMOYO_MAX_PATHNAME_LEN ) ;
strncpy ( real_program_name , ptr - > aliased_name - > name ,
TOMOYO_MAX_PATHNAME_LEN - 1 ) ;
tomoyo_fill_path_info ( & r ) ;
break ;
}
up_read ( & tomoyo_alias_list_lock ) ;
}
/* Check execute permission. */
retval = tomoyo_check_exec_perm ( old_domain , & r , tmp ) ;
if ( retval < 0 )
goto out ;
new_domain_name = tmp - > buffer ;
if ( tomoyo_is_domain_initializer ( old_domain - > domainname , & r , & l ) ) {
/* Transit to the child of tomoyo_kernel_domain domain. */
snprintf ( new_domain_name , TOMOYO_MAX_PATHNAME_LEN + 1 ,
TOMOYO_ROOT_NAME " " " %s " , real_program_name ) ;
} else if ( old_domain = = & tomoyo_kernel_domain & &
! tomoyo_policy_loaded ) {
/*
* Needn ' t to transit from kernel domain before starting
* / sbin / init . But transit from kernel domain if executing
* initializers because they might start before / sbin / init .
*/
domain = old_domain ;
} else if ( tomoyo_is_domain_keeper ( old_domain - > domainname , & r , & l ) ) {
/* Keep current domain. */
domain = old_domain ;
} else {
/* Normal domain transition. */
snprintf ( new_domain_name , TOMOYO_MAX_PATHNAME_LEN + 1 ,
" %s %s " , old_domain_name , real_program_name ) ;
}
if ( domain | | strlen ( new_domain_name ) > = TOMOYO_MAX_PATHNAME_LEN )
goto done ;
down_read ( & tomoyo_domain_list_lock ) ;
domain = tomoyo_find_domain ( new_domain_name ) ;
up_read ( & tomoyo_domain_list_lock ) ;
if ( domain )
goto done ;
if ( is_enforce )
goto done ;
domain = tomoyo_find_or_assign_new_domain ( new_domain_name ,
old_domain - > profile ) ;
done :
if ( domain )
goto out ;
printk ( KERN_WARNING " TOMOYO-ERROR: Domain '%s' not defined. \n " ,
new_domain_name ) ;
if ( is_enforce )
retval = - EPERM ;
else
tomoyo_set_domain_flag ( old_domain , false ,
TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED ) ;
out :
tomoyo_free ( real_program_name ) ;
tomoyo_free ( symlink_program_name ) ;
* next_domain = domain ? domain : old_domain ;
tomoyo_free ( tmp ) ;
return retval ;
}