2010-05-17 05:12:46 +04:00
/*
* security / tomoyo / util . c
*
2011-07-14 09:46:51 +04:00
* Copyright ( C ) 2005 - 2011 NTT DATA CORPORATION
2010-05-17 05:12:46 +04:00
*/
# include <linux/slab.h>
# include "common.h"
/* Lock for protecting policy. */
DEFINE_MUTEX ( tomoyo_policy_lock ) ;
/* Has /sbin/init started? */
bool tomoyo_policy_loaded ;
2011-06-26 18:21:19 +04:00
/*
* Mapping table from " enum tomoyo_mac_index " to
* " enum tomoyo_mac_category_index " .
*/
const u8 tomoyo_index2category [ TOMOYO_MAX_MAC_INDEX ] = {
/* CONFIG::file group */
[ TOMOYO_MAC_FILE_EXECUTE ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_OPEN ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_CREATE ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_UNLINK ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_GETATTR ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_MKDIR ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_RMDIR ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_MKFIFO ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_MKSOCK ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_TRUNCATE ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_SYMLINK ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_MKBLOCK ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_MKCHAR ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_LINK ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_RENAME ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_CHMOD ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_CHOWN ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_CHGRP ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_IOCTL ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_CHROOT ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_MOUNT ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_UMOUNT ] = TOMOYO_MAC_CATEGORY_FILE ,
[ TOMOYO_MAC_FILE_PIVOT_ROOT ] = TOMOYO_MAC_CATEGORY_FILE ,
2011-09-10 10:23:54 +04:00
/* CONFIG::network group */
[ TOMOYO_MAC_NETWORK_INET_STREAM_BIND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_INET_DGRAM_BIND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_INET_DGRAM_SEND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_INET_RAW_BIND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_INET_RAW_SEND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
[ TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT ] =
TOMOYO_MAC_CATEGORY_NETWORK ,
2011-09-10 10:22:48 +04:00
/* CONFIG::misc group */
[ TOMOYO_MAC_ENVIRON ] = TOMOYO_MAC_CATEGORY_MISC ,
2011-06-26 18:21:19 +04:00
} ;
2011-06-26 18:21:50 +04:00
/**
* tomoyo_convert_time - Convert time_t to YYYY / MM / DD hh / mm / ss .
*
* @ time : Seconds since 1970 / 01 / 01 00 : 00 : 00.
* @ stamp : Pointer to " struct tomoyo_time " .
*
* Returns nothing .
*
* This function does not handle Y2038 problem .
*/
void tomoyo_convert_time ( time_t time , struct tomoyo_time * stamp )
{
static const u16 tomoyo_eom [ 2 ] [ 12 ] = {
{ 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334 , 365 } ,
{ 31 , 60 , 91 , 121 , 152 , 182 , 213 , 244 , 274 , 305 , 335 , 366 }
} ;
u16 y ;
u8 m ;
bool r ;
stamp - > sec = time % 60 ;
time / = 60 ;
stamp - > min = time % 60 ;
time / = 60 ;
stamp - > hour = time % 24 ;
time / = 24 ;
for ( y = 1970 ; ; y + + ) {
const unsigned short days = ( y & 3 ) ? 365 : 366 ;
if ( time < days )
break ;
time - = days ;
}
r = ( y & 3 ) = = 0 ;
for ( m = 0 ; m < 11 & & time > = tomoyo_eom [ r ] [ m ] ; m + + )
;
if ( m )
time - = tomoyo_eom [ r ] [ m - 1 ] ;
stamp - > year = y ;
stamp - > month = + + m ;
stamp - > day = + + time ;
}
2011-06-26 18:17:10 +04:00
/**
* tomoyo_permstr - Find permission keywords .
*
* @ string : String representation for permissions in foo / bar / buz format .
* @ keyword : Keyword to find from @ string /
*
* Returns ture if @ keyword was found in @ string , false otherwise .
*
* This function assumes that strncmp ( w1 , w2 , strlen ( w1 ) ) ! = 0 if w1 ! = w2 .
*/
bool tomoyo_permstr ( const char * string , const char * keyword )
{
const char * cp = strstr ( string , keyword ) ;
if ( cp )
return cp = = string | | * ( cp - 1 ) = = ' / ' ;
return false ;
}
/**
* tomoyo_read_token - Read a word from a line .
*
* @ param : Pointer to " struct tomoyo_acl_param " .
*
* Returns a word on success , " " otherwise .
*
* To allow the caller to skip NULL check , this function returns " " rather than
* NULL if there is no more words to read .
*/
char * tomoyo_read_token ( struct tomoyo_acl_param * param )
{
char * pos = param - > data ;
char * del = strchr ( pos , ' ' ) ;
if ( del )
* del + + = ' \0 ' ;
else
del = pos + strlen ( pos ) ;
param - > data = del ;
return pos ;
}
2011-09-10 10:25:58 +04:00
/**
* tomoyo_get_domainname - Read a domainname from a line .
*
* @ param : Pointer to " struct tomoyo_acl_param " .
*
* Returns a domainname on success , NULL otherwise .
*/
const struct tomoyo_path_info * tomoyo_get_domainname
( struct tomoyo_acl_param * param )
{
char * start = param - > data ;
char * pos = start ;
while ( * pos ) {
if ( * pos + + ! = ' ' | | * pos + + = = ' / ' )
continue ;
pos - = 2 ;
* pos + + = ' \0 ' ;
break ;
}
param - > data = pos ;
if ( tomoyo_correct_domain ( start ) )
return tomoyo_get_name ( start ) ;
return NULL ;
}
2010-05-17 05:12:46 +04:00
/**
* tomoyo_parse_ulong - Parse an " unsigned long " value .
*
* @ result : Pointer to " unsigned long " .
* @ str : Pointer to string to parse .
*
2011-06-26 18:16:36 +04:00
* Returns one of values in " enum tomoyo_value_type " .
2010-05-17 05:12:46 +04:00
*
* The @ src is updated to point the first character after the value
* on success .
*/
2011-07-08 08:21:37 +04:00
u8 tomoyo_parse_ulong ( unsigned long * result , char * * str )
2010-05-17 05:12:46 +04:00
{
const char * cp = * str ;
char * ep ;
int base = 10 ;
if ( * cp = = ' 0 ' ) {
char c = * ( cp + 1 ) ;
if ( c = = ' x ' | | c = = ' X ' ) {
base = 16 ;
cp + = 2 ;
} else if ( c > = ' 0 ' & & c < = ' 7 ' ) {
base = 8 ;
cp + + ;
}
}
* result = simple_strtoul ( cp , & ep , base ) ;
if ( cp = = ep )
2011-06-26 18:16:36 +04:00
return TOMOYO_VALUE_TYPE_INVALID ;
2010-05-17 05:12:46 +04:00
* str = ep ;
switch ( base ) {
case 16 :
return TOMOYO_VALUE_TYPE_HEXADECIMAL ;
case 8 :
return TOMOYO_VALUE_TYPE_OCTAL ;
default :
return TOMOYO_VALUE_TYPE_DECIMAL ;
}
}
/**
* tomoyo_print_ulong - Print an " unsigned long " value .
*
* @ buffer : Pointer to buffer .
* @ buffer_len : Size of @ buffer .
* @ value : An " unsigned long " value .
* @ type : Type of @ value .
*
* Returns nothing .
*/
void tomoyo_print_ulong ( char * buffer , const int buffer_len ,
const unsigned long value , const u8 type )
{
if ( type = = TOMOYO_VALUE_TYPE_DECIMAL )
snprintf ( buffer , buffer_len , " %lu " , value ) ;
else if ( type = = TOMOYO_VALUE_TYPE_OCTAL )
snprintf ( buffer , buffer_len , " 0%lo " , value ) ;
else if ( type = = TOMOYO_VALUE_TYPE_HEXADECIMAL )
snprintf ( buffer , buffer_len , " 0x%lX " , value ) ;
else
snprintf ( buffer , buffer_len , " type(%u) " , type ) ;
}
/**
* tomoyo_parse_name_union - Parse a tomoyo_name_union .
*
2011-06-26 18:17:10 +04:00
* @ param : Pointer to " struct tomoyo_acl_param " .
* @ ptr : Pointer to " struct tomoyo_name_union " .
2010-05-17 05:12:46 +04:00
*
* Returns true on success , false otherwise .
*/
2011-06-26 18:17:10 +04:00
bool tomoyo_parse_name_union ( struct tomoyo_acl_param * param ,
2010-05-17 05:12:46 +04:00
struct tomoyo_name_union * ptr )
{
2011-06-26 18:17:10 +04:00
char * filename ;
if ( param - > data [ 0 ] = = ' @ ' ) {
param - > data + + ;
ptr - > group = tomoyo_get_group ( param , TOMOYO_PATH_GROUP ) ;
2010-05-17 05:12:46 +04:00
return ptr - > group ! = NULL ;
}
2011-06-26 18:17:10 +04:00
filename = tomoyo_read_token ( param ) ;
if ( ! tomoyo_correct_word ( filename ) )
return false ;
2010-05-17 05:12:46 +04:00
ptr - > filename = tomoyo_get_name ( filename ) ;
return ptr - > filename ! = NULL ;
}
/**
* tomoyo_parse_number_union - Parse a tomoyo_number_union .
*
2011-06-26 18:17:10 +04:00
* @ param : Pointer to " struct tomoyo_acl_param " .
* @ ptr : Pointer to " struct tomoyo_number_union " .
2010-05-17 05:12:46 +04:00
*
* Returns true on success , false otherwise .
*/
2011-06-26 18:17:10 +04:00
bool tomoyo_parse_number_union ( struct tomoyo_acl_param * param ,
struct tomoyo_number_union * ptr )
2010-05-17 05:12:46 +04:00
{
2011-06-26 18:17:10 +04:00
char * data ;
2010-05-17 05:12:46 +04:00
u8 type ;
unsigned long v ;
2011-06-26 18:17:10 +04:00
memset ( ptr , 0 , sizeof ( * ptr ) ) ;
if ( param - > data [ 0 ] = = ' @ ' ) {
param - > data + + ;
ptr - > group = tomoyo_get_group ( param , TOMOYO_NUMBER_GROUP ) ;
return ptr - > group ! = NULL ;
2010-05-17 05:12:46 +04:00
}
2011-06-26 18:17:10 +04:00
data = tomoyo_read_token ( param ) ;
2010-05-17 05:12:46 +04:00
type = tomoyo_parse_ulong ( & v , & data ) ;
2011-06-26 18:17:10 +04:00
if ( type = = TOMOYO_VALUE_TYPE_INVALID )
2010-05-17 05:12:46 +04:00
return false ;
2011-06-26 18:17:10 +04:00
ptr - > values [ 0 ] = v ;
ptr - > value_type [ 0 ] = type ;
2010-05-17 05:12:46 +04:00
if ( ! * data ) {
2011-06-26 18:17:10 +04:00
ptr - > values [ 1 ] = v ;
ptr - > value_type [ 1 ] = type ;
2010-05-17 05:12:46 +04:00
return true ;
}
if ( * data + + ! = ' - ' )
return false ;
type = tomoyo_parse_ulong ( & v , & data ) ;
2011-06-26 18:17:10 +04:00
if ( type = = TOMOYO_VALUE_TYPE_INVALID | | * data | | ptr - > values [ 0 ] > v )
2010-05-17 05:12:46 +04:00
return false ;
2011-06-26 18:17:10 +04:00
ptr - > values [ 1 ] = v ;
ptr - > value_type [ 1 ] = type ;
2010-05-17 05:12:46 +04:00
return true ;
}
/**
2010-06-16 11:23:55 +04:00
* tomoyo_byte_range - Check whether the string is a \ ooo style octal value .
2010-05-17 05:12:46 +04:00
*
* @ str : Pointer to the string .
*
* Returns true if @ str is a \ ooo style octal value , false otherwise .
*
* TOMOYO uses \ ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF .
* This function verifies that \ ooo is in valid range .
*/
2010-06-16 11:23:55 +04:00
static inline bool tomoyo_byte_range ( const char * str )
2010-05-17 05:12:46 +04:00
{
return * str > = ' 0 ' & & * str + + < = ' 3 ' & &
* str > = ' 0 ' & & * str + + < = ' 7 ' & &
* str > = ' 0 ' & & * str < = ' 7 ' ;
}
/**
2010-06-16 11:23:55 +04:00
* tomoyo_alphabet_char - Check whether the character is an alphabet .
2010-05-17 05:12:46 +04:00
*
* @ c : The character to check .
*
* Returns true if @ c is an alphabet character , false otherwise .
*/
2010-06-16 11:23:55 +04:00
static inline bool tomoyo_alphabet_char ( const char c )
2010-05-17 05:12:46 +04:00
{
return ( c > = ' A ' & & c < = ' Z ' ) | | ( c > = ' a ' & & c < = ' z ' ) ;
}
/**
* tomoyo_make_byte - Make byte value from three octal characters .
*
* @ c1 : The first character .
* @ c2 : The second character .
* @ c3 : The third character .
*
* Returns byte value .
*/
static inline u8 tomoyo_make_byte ( const u8 c1 , const u8 c2 , const u8 c3 )
{
return ( ( c1 - ' 0 ' ) < < 6 ) + ( ( c2 - ' 0 ' ) < < 3 ) + ( c3 - ' 0 ' ) ;
}
2011-06-26 18:16:36 +04:00
/**
* tomoyo_valid - Check whether the character is a valid char .
*
* @ c : The character to check .
*
* Returns true if @ c is a valid character , false otherwise .
*/
static inline bool tomoyo_valid ( const unsigned char c )
{
return c > ' ' & & c < 127 ;
}
/**
* tomoyo_invalid - Check whether the character is an invalid char .
*
* @ c : The character to check .
*
* Returns true if @ c is an invalid character , false otherwise .
*/
static inline bool tomoyo_invalid ( const unsigned char c )
{
return c & & ( c < = ' ' | | c > = 127 ) ;
}
2010-05-17 05:12:46 +04:00
/**
* tomoyo_str_starts - Check whether the given string starts with the given keyword .
*
* @ src : Pointer to pointer to the string .
* @ find : Pointer to the keyword .
*
* Returns true if @ src starts with @ find , false otherwise .
*
* The @ src is updated to point the first character after the @ find
* if @ src starts with @ find .
*/
bool tomoyo_str_starts ( char * * src , const char * find )
{
const int len = strlen ( find ) ;
char * tmp = * src ;
if ( strncmp ( tmp , find , len ) )
return false ;
tmp + = len ;
* src = tmp ;
return true ;
}
/**
* tomoyo_normalize_line - Format string .
*
* @ buffer : The line to normalize .
*
* Leading and trailing whitespaces are removed .
* Multiple whitespaces are packed into single space .
*
* Returns nothing .
*/
void tomoyo_normalize_line ( unsigned char * buffer )
{
unsigned char * sp = buffer ;
unsigned char * dp = buffer ;
bool first = true ;
2010-06-16 11:23:55 +04:00
while ( tomoyo_invalid ( * sp ) )
2010-05-17 05:12:46 +04:00
sp + + ;
while ( * sp ) {
if ( ! first )
* dp + + = ' ' ;
first = false ;
2010-06-16 11:23:55 +04:00
while ( tomoyo_valid ( * sp ) )
2010-05-17 05:12:46 +04:00
* dp + + = * sp + + ;
2010-06-16 11:23:55 +04:00
while ( tomoyo_invalid ( * sp ) )
2010-05-17 05:12:46 +04:00
sp + + ;
}
* dp = ' \0 ' ;
}
/**
2010-06-16 11:23:55 +04:00
* tomoyo_correct_word2 - Validate a string .
2010-05-17 05:12:46 +04:00
*
2011-07-14 09:46:51 +04:00
* @ string : The string to check . Maybe non - ' \0 ' - terminated .
2010-06-03 15:37:26 +04:00
* @ len : Length of @ string .
2010-05-17 05:12:46 +04:00
*
2010-06-03 15:37:26 +04:00
* Check whether the given string follows the naming rules .
* Returns true if @ string follows the naming rules , false otherwise .
2010-05-17 05:12:46 +04:00
*/
2010-06-16 11:23:55 +04:00
static bool tomoyo_correct_word2 ( const char * string , size_t len )
2010-05-17 05:12:46 +04:00
{
2010-06-03 15:37:26 +04:00
const char * const start = string ;
2010-05-17 05:12:46 +04:00
bool in_repetition = false ;
unsigned char c ;
unsigned char d ;
unsigned char e ;
2010-06-03 15:37:26 +04:00
if ( ! len )
2010-05-17 05:12:46 +04:00
goto out ;
2010-06-03 15:37:26 +04:00
while ( len - - ) {
c = * string + + ;
2010-05-17 05:12:46 +04:00
if ( c = = ' \\ ' ) {
2010-06-03 15:37:26 +04:00
if ( ! len - - )
goto out ;
c = * string + + ;
2010-05-17 05:12:46 +04:00
switch ( c ) {
case ' \\ ' : /* "\\" */
continue ;
case ' $ ' : /* "\$" */
case ' + ' : /* "\+" */
case ' ? ' : /* "\?" */
case ' * ' : /* "\*" */
case ' @ ' : /* "\@" */
case ' x ' : /* "\x" */
case ' X ' : /* "\X" */
case ' a ' : /* "\a" */
case ' A ' : /* "\A" */
case ' - ' : /* "\-" */
continue ;
case ' { ' : /* "/\{" */
2010-06-03 15:37:26 +04:00
if ( string - 3 < start | | * ( string - 3 ) ! = ' / ' )
2010-05-17 05:12:46 +04:00
break ;
in_repetition = true ;
continue ;
case ' } ' : /* "\}/" */
2010-06-03 15:37:26 +04:00
if ( * string ! = ' / ' )
2010-05-17 05:12:46 +04:00
break ;
if ( ! in_repetition )
break ;
in_repetition = false ;
continue ;
case ' 0 ' : /* "\ooo" */
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
2010-06-03 15:37:26 +04:00
if ( ! len - - | | ! len - - )
2010-05-17 05:12:46 +04:00
break ;
2010-06-03 15:37:26 +04:00
d = * string + + ;
e = * string + + ;
if ( d < ' 0 ' | | d > ' 7 ' | | e < ' 0 ' | | e > ' 7 ' )
2010-05-17 05:12:46 +04:00
break ;
c = tomoyo_make_byte ( c , d , e ) ;
2012-01-15 06:05:59 +04:00
if ( c < = ' ' | | c > = 127 )
continue ;
2010-05-17 05:12:46 +04:00
}
goto out ;
} else if ( in_repetition & & c = = ' / ' ) {
goto out ;
2012-01-15 06:05:59 +04:00
} else if ( c < = ' ' | | c > = 127 ) {
2010-05-17 05:12:46 +04:00
goto out ;
}
}
if ( in_repetition )
goto out ;
return true ;
out :
return false ;
}
2010-06-03 15:37:26 +04:00
/**
2010-06-16 11:23:55 +04:00
* tomoyo_correct_word - Validate a string .
2010-06-03 15:37:26 +04:00
*
* @ string : The string to check .
*
* Check whether the given string follows the naming rules .
* Returns true if @ string follows the naming rules , false otherwise .
*/
2010-06-16 11:23:55 +04:00
bool tomoyo_correct_word ( const char * string )
2010-06-03 15:37:26 +04:00
{
2010-06-16 11:23:55 +04:00
return tomoyo_correct_word2 ( string , strlen ( string ) ) ;
2010-06-03 15:37:26 +04:00
}
/**
2010-06-16 11:23:55 +04:00
* tomoyo_correct_path - Validate a pathname .
2010-06-03 15:37:26 +04:00
*
* @ filename : The pathname to check .
*
* Check whether the given pathname follows the naming rules .
* Returns true if @ filename follows the naming rules , false otherwise .
*/
2010-06-16 11:23:55 +04:00
bool tomoyo_correct_path ( const char * filename )
2010-06-03 15:37:26 +04:00
{
2010-06-16 11:23:55 +04:00
return * filename = = ' / ' & & tomoyo_correct_word ( filename ) ;
2010-06-03 15:37:26 +04:00
}
2010-05-17 05:12:46 +04:00
/**
2010-06-16 11:23:55 +04:00
* tomoyo_correct_domain - Check whether the given domainname follows the naming rules .
2010-05-17 05:12:46 +04:00
*
2010-06-03 15:37:26 +04:00
* @ domainname : The domainname to check .
2010-05-17 05:12:46 +04:00
*
* Returns true if @ domainname follows the naming rules , false otherwise .
*/
2010-06-16 11:23:55 +04:00
bool tomoyo_correct_domain ( const unsigned char * domainname )
2010-05-17 05:12:46 +04:00
{
2011-06-26 18:19:52 +04:00
if ( ! domainname | | ! tomoyo_domain_def ( domainname ) )
return false ;
domainname = strchr ( domainname , ' ' ) ;
if ( ! domainname + + )
2010-05-17 05:12:46 +04:00
return true ;
2010-06-03 15:37:26 +04:00
while ( 1 ) {
const unsigned char * cp = strchr ( domainname , ' ' ) ;
if ( ! cp )
break ;
if ( * domainname ! = ' / ' | |
2011-05-12 01:40:51 +04:00
! tomoyo_correct_word2 ( domainname , cp - domainname ) )
2011-06-26 18:19:52 +04:00
return false ;
2010-06-03 15:37:26 +04:00
domainname = cp + 1 ;
}
2010-06-16 11:23:55 +04:00
return tomoyo_correct_path ( domainname ) ;
2010-05-17 05:12:46 +04:00
}
/**
2010-06-16 11:23:55 +04:00
* tomoyo_domain_def - Check whether the given token can be a domainname .
2010-05-17 05:12:46 +04:00
*
* @ buffer : The token to check .
*
* Returns true if @ buffer possibly be a domainname , false otherwise .
*/
2010-06-16 11:23:55 +04:00
bool tomoyo_domain_def ( const unsigned char * buffer )
2010-05-17 05:12:46 +04:00
{
2011-06-26 18:19:52 +04:00
const unsigned char * cp ;
int len ;
if ( * buffer ! = ' < ' )
return false ;
cp = strchr ( buffer , ' ' ) ;
if ( ! cp )
len = strlen ( buffer ) ;
else
len = cp - buffer ;
if ( buffer [ len - 1 ] ! = ' > ' | |
! tomoyo_correct_word2 ( buffer + 1 , len - 2 ) )
return false ;
return true ;
2010-05-17 05:12:46 +04:00
}
/**
* tomoyo_find_domain - Find a domain by the given name .
*
* @ domainname : The domainname to find .
*
* Returns pointer to " struct tomoyo_domain_info " if found , NULL otherwise .
*
* Caller holds tomoyo_read_lock ( ) .
*/
struct tomoyo_domain_info * tomoyo_find_domain ( const char * domainname )
{
struct tomoyo_domain_info * domain ;
struct tomoyo_path_info name ;
name . name = domainname ;
tomoyo_fill_path_info ( & name ) ;
list_for_each_entry_rcu ( domain , & tomoyo_domain_list , list ) {
if ( ! domain - > is_deleted & &
! tomoyo_pathcmp ( & name , domain - > domainname ) )
return domain ;
}
return NULL ;
}
/**
* tomoyo_const_part_length - Evaluate the initial length without a pattern in a token .
*
* @ filename : The string to evaluate .
*
* Returns the initial length without a pattern in @ filename .
*/
static int tomoyo_const_part_length ( const char * filename )
{
char c ;
int len = 0 ;
if ( ! filename )
return 0 ;
while ( ( c = * filename + + ) ! = ' \0 ' ) {
if ( c ! = ' \\ ' ) {
len + + ;
continue ;
}
c = * filename + + ;
switch ( c ) {
case ' \\ ' : /* "\\" */
len + = 2 ;
continue ;
case ' 0 ' : /* "\ooo" */
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
c = * filename + + ;
if ( c < ' 0 ' | | c > ' 7 ' )
break ;
c = * filename + + ;
if ( c < ' 0 ' | | c > ' 7 ' )
break ;
len + = 4 ;
continue ;
}
break ;
}
return len ;
}
/**
* tomoyo_fill_path_info - Fill in " struct tomoyo_path_info " members .
*
* @ ptr : Pointer to " struct tomoyo_path_info " to fill in .
*
* The caller sets " struct tomoyo_path_info " - > name .
*/
void tomoyo_fill_path_info ( struct tomoyo_path_info * ptr )
{
const char * name = ptr - > name ;
const int len = strlen ( name ) ;
ptr - > const_len = tomoyo_const_part_length ( name ) ;
ptr - > is_dir = len & & ( name [ len - 1 ] = = ' / ' ) ;
ptr - > is_patterned = ( ptr - > const_len < len ) ;
ptr - > hash = full_name_hash ( name , len ) ;
}
/**
* tomoyo_file_matches_pattern2 - Pattern matching without ' / ' character and " \ - " pattern .
*
* @ filename : The start of string to check .
* @ filename_end : The end of string to check .
* @ pattern : The start of pattern to compare .
* @ pattern_end : The end of pattern to compare .
*
* Returns true if @ filename matches @ pattern , false otherwise .
*/
static bool tomoyo_file_matches_pattern2 ( const char * filename ,
const char * filename_end ,
const char * pattern ,
const char * pattern_end )
{
while ( filename < filename_end & & pattern < pattern_end ) {
char c ;
if ( * pattern ! = ' \\ ' ) {
if ( * filename + + ! = * pattern + + )
return false ;
continue ;
}
c = * filename ;
pattern + + ;
switch ( * pattern ) {
int i ;
int j ;
case ' ? ' :
if ( c = = ' / ' ) {
return false ;
} else if ( c = = ' \\ ' ) {
if ( filename [ 1 ] = = ' \\ ' )
filename + + ;
2010-06-16 11:23:55 +04:00
else if ( tomoyo_byte_range ( filename + 1 ) )
2010-05-17 05:12:46 +04:00
filename + = 3 ;
else
return false ;
}
break ;
case ' \\ ' :
if ( c ! = ' \\ ' )
return false ;
if ( * + + filename ! = ' \\ ' )
return false ;
break ;
case ' + ' :
if ( ! isdigit ( c ) )
return false ;
break ;
case ' x ' :
if ( ! isxdigit ( c ) )
return false ;
break ;
case ' a ' :
2010-06-16 11:23:55 +04:00
if ( ! tomoyo_alphabet_char ( c ) )
2010-05-17 05:12:46 +04:00
return false ;
break ;
case ' 0 ' :
case ' 1 ' :
case ' 2 ' :
case ' 3 ' :
2010-06-16 11:23:55 +04:00
if ( c = = ' \\ ' & & tomoyo_byte_range ( filename + 1 )
2010-05-17 05:12:46 +04:00
& & strncmp ( filename + 1 , pattern , 3 ) = = 0 ) {
filename + = 3 ;
pattern + = 2 ;
break ;
}
return false ; /* Not matched. */
case ' * ' :
case ' @ ' :
for ( i = 0 ; i < = filename_end - filename ; i + + ) {
if ( tomoyo_file_matches_pattern2 (
filename + i , filename_end ,
pattern + 1 , pattern_end ) )
return true ;
c = filename [ i ] ;
if ( c = = ' . ' & & * pattern = = ' @ ' )
break ;
if ( c ! = ' \\ ' )
continue ;
if ( filename [ i + 1 ] = = ' \\ ' )
i + + ;
2010-06-16 11:23:55 +04:00
else if ( tomoyo_byte_range ( filename + i + 1 ) )
2010-05-17 05:12:46 +04:00
i + = 3 ;
else
break ; /* Bad pattern. */
}
return false ; /* Not matched. */
default :
j = 0 ;
c = * pattern ;
if ( c = = ' $ ' ) {
while ( isdigit ( filename [ j ] ) )
j + + ;
} else if ( c = = ' X ' ) {
while ( isxdigit ( filename [ j ] ) )
j + + ;
} else if ( c = = ' A ' ) {
2010-06-16 11:23:55 +04:00
while ( tomoyo_alphabet_char ( filename [ j ] ) )
2010-05-17 05:12:46 +04:00
j + + ;
}
for ( i = 1 ; i < = j ; i + + ) {
if ( tomoyo_file_matches_pattern2 (
filename + i , filename_end ,
pattern + 1 , pattern_end ) )
return true ;
}
return false ; /* Not matched or bad pattern. */
}
filename + + ;
pattern + + ;
}
while ( * pattern = = ' \\ ' & &
( * ( pattern + 1 ) = = ' * ' | | * ( pattern + 1 ) = = ' @ ' ) )
pattern + = 2 ;
return filename = = filename_end & & pattern = = pattern_end ;
}
/**
* tomoyo_file_matches_pattern - Pattern matching without ' / ' character .
*
* @ filename : The start of string to check .
* @ filename_end : The end of string to check .
* @ pattern : The start of pattern to compare .
* @ pattern_end : The end of pattern to compare .
*
* Returns true if @ filename matches @ pattern , false otherwise .
*/
static bool tomoyo_file_matches_pattern ( const char * filename ,
const char * filename_end ,
const char * pattern ,
const char * pattern_end )
{
const char * pattern_start = pattern ;
bool first = true ;
bool result ;
while ( pattern < pattern_end - 1 ) {
/* Split at "\-" pattern. */
if ( * pattern + + ! = ' \\ ' | | * pattern + + ! = ' - ' )
continue ;
result = tomoyo_file_matches_pattern2 ( filename ,
filename_end ,
pattern_start ,
pattern - 2 ) ;
if ( first )
result = ! result ;
if ( result )
return false ;
first = false ;
pattern_start = pattern ;
}
result = tomoyo_file_matches_pattern2 ( filename , filename_end ,
pattern_start , pattern_end ) ;
return first ? result : ! result ;
}
/**
* tomoyo_path_matches_pattern2 - Do pathname pattern matching .
*
* @ f : The start of string to check .
* @ p : The start of pattern to compare .
*
* Returns true if @ f matches @ p , false otherwise .
*/
static bool tomoyo_path_matches_pattern2 ( const char * f , const char * p )
{
const char * f_delimiter ;
const char * p_delimiter ;
while ( * f & & * p ) {
f_delimiter = strchr ( f , ' / ' ) ;
if ( ! f_delimiter )
f_delimiter = f + strlen ( f ) ;
p_delimiter = strchr ( p , ' / ' ) ;
if ( ! p_delimiter )
p_delimiter = p + strlen ( p ) ;
if ( * p = = ' \\ ' & & * ( p + 1 ) = = ' { ' )
goto recursive ;
if ( ! tomoyo_file_matches_pattern ( f , f_delimiter , p ,
p_delimiter ) )
return false ;
f = f_delimiter ;
if ( * f )
f + + ;
p = p_delimiter ;
if ( * p )
p + + ;
}
/* Ignore trailing "\*" and "\@" in @pattern. */
while ( * p = = ' \\ ' & &
( * ( p + 1 ) = = ' * ' | | * ( p + 1 ) = = ' @ ' ) )
p + = 2 ;
return ! * f & & ! * p ;
recursive :
/*
* The " \ { " pattern is permitted only after ' / ' character .
* This guarantees that below " *(p - 1) " is safe .
* Also , the " \ } " pattern is permitted only before ' / ' character
* so that " \ { " + " \ } " pair will not break the " \ - " operator .
*/
if ( * ( p - 1 ) ! = ' / ' | | p_delimiter < = p + 3 | | * p_delimiter ! = ' / ' | |
* ( p_delimiter - 1 ) ! = ' } ' | | * ( p_delimiter - 2 ) ! = ' \\ ' )
return false ; /* Bad pattern. */
do {
/* Compare current component with pattern. */
if ( ! tomoyo_file_matches_pattern ( f , f_delimiter , p + 2 ,
p_delimiter - 2 ) )
break ;
/* Proceed to next component. */
f = f_delimiter ;
if ( ! * f )
break ;
f + + ;
/* Continue comparison. */
if ( tomoyo_path_matches_pattern2 ( f , p_delimiter + 1 ) )
return true ;
f_delimiter = strchr ( f , ' / ' ) ;
} while ( f_delimiter ) ;
return false ; /* Not matched. */
}
/**
* tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern .
*
* @ filename : The filename to check .
* @ pattern : The pattern to compare .
*
* Returns true if matches , false otherwise .
*
* The following patterns are available .
* \ \ \ itself .
* \ ooo Octal representation of a byte .
* \ * Zero or more repetitions of characters other than ' / ' .
* \ @ Zero or more repetitions of characters other than ' / ' or ' . ' .
* \ ? 1 byte character other than ' / ' .
* \ $ One or more repetitions of decimal digits .
* \ + 1 decimal digit .
* \ X One or more repetitions of hexadecimal digits .
* \ x 1 hexadecimal digit .
* \ A One or more repetitions of alphabet characters .
* \ a 1 alphabet character .
*
* \ - Subtraction operator .
*
* / \ { dir \ } / ' / ' + ' One or more repetitions of dir / ' ( e . g . / dir / / dir / dir /
* / dir / dir / dir / ) .
*/
bool tomoyo_path_matches_pattern ( const struct tomoyo_path_info * filename ,
const struct tomoyo_path_info * pattern )
{
const char * f = filename - > name ;
const char * p = pattern - > name ;
const int len = pattern - > const_len ;
/* If @pattern doesn't contain pattern, I can use strcmp(). */
if ( ! pattern - > is_patterned )
return ! tomoyo_pathcmp ( filename , pattern ) ;
/* Don't compare directory and non-directory. */
if ( filename - > is_dir ! = pattern - > is_dir )
return false ;
/* Compare the initial length without patterns. */
if ( strncmp ( f , p , len ) )
return false ;
f + = len ;
p + = len ;
return tomoyo_path_matches_pattern2 ( f , p ) ;
}
/**
* tomoyo_get_exe - Get tomoyo_realpath ( ) of current process .
*
* Returns the tomoyo_realpath ( ) of current process on success , NULL otherwise .
*
* This function uses kzalloc ( ) , so the caller must call kfree ( )
* if this function didn ' t return NULL .
*/
const char * tomoyo_get_exe ( void )
{
struct mm_struct * mm = current - > mm ;
const char * cp = NULL ;
if ( ! mm )
return NULL ;
down_read ( & mm - > mmap_sem ) ;
2012-10-09 03:28:51 +04:00
if ( mm - > exe_file )
cp = tomoyo_realpath_from_path ( & mm - > exe_file - > f_path ) ;
2010-05-17 05:12:46 +04:00
up_read ( & mm - > mmap_sem ) ;
return cp ;
}
2010-06-03 15:38:44 +04:00
/**
* tomoyo_get_mode - Get MAC mode .
*
2011-06-26 18:19:52 +04:00
* @ ns : Pointer to " struct tomoyo_policy_namespace " .
2010-06-03 15:38:44 +04:00
* @ profile : Profile number .
* @ index : Index number of functionality .
*
* Returns mode .
*/
2011-06-26 18:19:52 +04:00
int tomoyo_get_mode ( const struct tomoyo_policy_namespace * ns , const u8 profile ,
const u8 index )
2010-06-03 15:38:44 +04:00
{
u8 mode ;
2011-09-10 10:22:48 +04:00
struct tomoyo_profile * p ;
2010-06-03 15:38:44 +04:00
if ( ! tomoyo_policy_loaded )
return TOMOYO_CONFIG_DISABLED ;
2011-09-10 10:22:48 +04:00
p = tomoyo_profile ( ns , profile ) ;
mode = p - > config [ index ] ;
2010-06-03 15:38:44 +04:00
if ( mode = = TOMOYO_CONFIG_USE_DEFAULT )
2011-09-10 10:22:48 +04:00
mode = p - > config [ tomoyo_index2category [ index ]
+ TOMOYO_MAX_MAC_INDEX ] ;
2010-06-03 15:38:44 +04:00
if ( mode = = TOMOYO_CONFIG_USE_DEFAULT )
2011-09-10 10:22:48 +04:00
mode = p - > default_config ;
2010-06-03 15:38:44 +04:00
return mode & 3 ;
}
2010-05-17 05:12:46 +04:00
/**
* tomoyo_init_request_info - Initialize " struct tomoyo_request_info " members .
*
* @ r : Pointer to " struct tomoyo_request_info " to initialize .
* @ domain : Pointer to " struct tomoyo_domain_info " . NULL for tomoyo_domain ( ) .
2010-06-03 15:38:44 +04:00
* @ index : Index number of functionality .
2010-05-17 05:12:46 +04:00
*
* Returns mode .
*/
int tomoyo_init_request_info ( struct tomoyo_request_info * r ,
2010-06-03 15:38:44 +04:00
struct tomoyo_domain_info * domain , const u8 index )
2010-05-17 05:12:46 +04:00
{
2010-06-03 15:38:44 +04:00
u8 profile ;
2010-05-17 05:12:46 +04:00
memset ( r , 0 , sizeof ( * r ) ) ;
if ( ! domain )
domain = tomoyo_domain ( ) ;
r - > domain = domain ;
2010-06-03 15:38:44 +04:00
profile = domain - > profile ;
r - > profile = profile ;
r - > type = index ;
2011-06-26 18:19:52 +04:00
r - > mode = tomoyo_get_mode ( domain - > ns , profile , index ) ;
2010-05-17 05:12:46 +04:00
return r - > mode ;
}
/**
* tomoyo_domain_quota_is_ok - Check for domain ' s quota .
*
* @ r : Pointer to " struct tomoyo_request_info " .
*
* Returns true if the domain is not exceeded quota , false otherwise .
*
* Caller holds tomoyo_read_lock ( ) .
*/
bool tomoyo_domain_quota_is_ok ( struct tomoyo_request_info * r )
{
unsigned int count = 0 ;
struct tomoyo_domain_info * domain = r - > domain ;
struct tomoyo_acl_info * ptr ;
if ( r - > mode ! = TOMOYO_CONFIG_LEARNING )
return false ;
if ( ! domain )
return true ;
list_for_each_entry_rcu ( ptr , & domain - > acl_info_list , list ) {
2011-06-26 18:15:31 +04:00
u16 perm ;
u8 i ;
2010-07-27 05:08:29 +04:00
if ( ptr - > is_deleted )
2010-06-12 15:46:22 +04:00
continue ;
2010-05-17 05:12:46 +04:00
switch ( ptr - > type ) {
case TOMOYO_TYPE_PATH_ACL :
perm = container_of ( ptr , struct tomoyo_path_acl , head )
- > perm ;
break ;
case TOMOYO_TYPE_PATH2_ACL :
perm = container_of ( ptr , struct tomoyo_path2_acl , head )
- > perm ;
break ;
case TOMOYO_TYPE_PATH_NUMBER_ACL :
perm = container_of ( ptr , struct tomoyo_path_number_acl ,
head ) - > perm ;
break ;
2010-06-16 11:23:55 +04:00
case TOMOYO_TYPE_MKDEV_ACL :
perm = container_of ( ptr , struct tomoyo_mkdev_acl ,
2010-05-17 05:12:46 +04:00
head ) - > perm ;
break ;
2011-10-11 09:06:41 +04:00
case TOMOYO_TYPE_INET_ACL :
perm = container_of ( ptr , struct tomoyo_inet_acl ,
head ) - > perm ;
break ;
case TOMOYO_TYPE_UNIX_ACL :
perm = container_of ( ptr , struct tomoyo_unix_acl ,
head ) - > perm ;
break ;
case TOMOYO_TYPE_MANUAL_TASK_ACL :
perm = 0 ;
break ;
2010-06-12 15:46:22 +04:00
default :
2011-06-26 18:15:31 +04:00
perm = 1 ;
2010-05-17 05:12:46 +04:00
}
2011-06-26 18:15:31 +04:00
for ( i = 0 ; i < 16 ; i + + )
if ( perm & ( 1 < < i ) )
count + + ;
2010-05-17 05:12:46 +04:00
}
2011-06-26 18:19:52 +04:00
if ( count < tomoyo_profile ( domain - > ns , domain - > profile ) - >
2011-06-26 18:18:21 +04:00
pref [ TOMOYO_PREF_MAX_LEARNING_ENTRY ] )
2010-05-17 05:12:46 +04:00
return true ;
2011-06-26 18:21:19 +04:00
if ( ! domain - > flags [ TOMOYO_DIF_QUOTA_WARNED ] ) {
domain - > flags [ TOMOYO_DIF_QUOTA_WARNED ] = true ;
/* r->granted = false; */
tomoyo_write_log ( r , " %s " , tomoyo_dif [ TOMOYO_DIF_QUOTA_WARNED ] ) ;
printk ( KERN_WARNING " WARNING: "
2011-06-26 18:18:21 +04:00
" Domain '%s' has too many ACLs to hold. "
2010-05-17 05:12:46 +04:00
" Stopped learning mode. \n " , domain - > domainname - > name ) ;
}
return false ;
}