2005-04-17 02:20:36 +04:00
/*
* Implementation of the access vector table type .
*
* Author : Stephen Smalley , < sds @ epoch . ncsc . mil >
*/
/* Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
*
2008-04-19 01:38:28 +04:00
* Added conditional policy language extensions
2005-04-17 02:20:36 +04:00
*
* Copyright ( C ) 2003 Tresys Technology , LLC
* This program is free software ; you can redistribute it and / or modify
2008-04-19 01:38:28 +04:00
* it under the terms of the GNU General Public License as published by
2005-04-17 02:20:36 +04:00
* the Free Software Foundation , version 2.
2007-08-24 06:55:11 +04:00
*
* Updated : Yuichi Nakamura < ynakam @ hitachisoft . jp >
2008-04-19 01:38:28 +04:00
* Tuned number of hash slots for avtab to reduce memory usage
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/errno.h>
# include "avtab.h"
# include "policydb.h"
2006-12-07 07:33:20 +03:00
static struct kmem_cache * avtab_node_cachep ;
2005-04-17 02:20:36 +04:00
2007-08-24 06:55:11 +04:00
static inline int avtab_hash ( struct avtab_key * keyp , u16 mask )
{
return ( ( keyp - > target_class + ( keyp - > target_type < < 2 ) +
( keyp - > source_type < < 9 ) ) & mask ) ;
}
2005-04-17 02:20:36 +04:00
static struct avtab_node *
avtab_insert_node ( struct avtab * h , int hvalue ,
2008-04-19 01:38:28 +04:00
struct avtab_node * prev , struct avtab_node * cur ,
2005-04-17 02:20:36 +04:00
struct avtab_key * key , struct avtab_datum * datum )
{
2008-04-19 01:38:28 +04:00
struct avtab_node * newnode ;
2007-02-10 12:45:03 +03:00
newnode = kmem_cache_zalloc ( avtab_node_cachep , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( newnode = = NULL )
return NULL ;
newnode - > key = * key ;
newnode - > datum = * datum ;
if ( prev ) {
newnode - > next = prev - > next ;
prev - > next = newnode ;
} else {
newnode - > next = h - > htable [ hvalue ] ;
h - > htable [ hvalue ] = newnode ;
}
h - > nel + + ;
return newnode ;
}
static int avtab_insert ( struct avtab * h , struct avtab_key * key , struct avtab_datum * datum )
{
int hvalue ;
struct avtab_node * prev , * cur , * newnode ;
2005-09-04 02:55:16 +04:00
u16 specified = key - > specified & ~ ( AVTAB_ENABLED | AVTAB_ENABLED_OLD ) ;
2005-04-17 02:20:36 +04:00
2007-08-24 06:55:11 +04:00
if ( ! h | | ! h - > htable )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2007-08-24 06:55:11 +04:00
hvalue = avtab_hash ( key , h - > mask ) ;
2005-04-17 02:20:36 +04:00
for ( prev = NULL , cur = h - > htable [ hvalue ] ;
cur ;
prev = cur , cur = cur - > next ) {
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class = = cur - > key . target_class & &
2005-09-04 02:55:16 +04:00
( specified & cur - > key . specified ) )
2005-04-17 02:20:36 +04:00
return - EEXIST ;
if ( key - > source_type < cur - > key . source_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type < cur - > key . target_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class < cur - > key . target_class )
break ;
}
newnode = avtab_insert_node ( h , hvalue , prev , cur , key , datum ) ;
2008-04-19 01:38:28 +04:00
if ( ! newnode )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
return 0 ;
}
/* Unlike avtab_insert(), this function allow multiple insertions of the same
* key / specified mask into the table , as needed by the conditional avtab .
* It also returns a pointer to the node inserted .
*/
struct avtab_node *
2008-04-19 01:38:28 +04:00
avtab_insert_nonunique ( struct avtab * h , struct avtab_key * key , struct avtab_datum * datum )
2005-04-17 02:20:36 +04:00
{
int hvalue ;
2008-07-21 03:50:20 +04:00
struct avtab_node * prev , * cur ;
2005-09-04 02:55:16 +04:00
u16 specified = key - > specified & ~ ( AVTAB_ENABLED | AVTAB_ENABLED_OLD ) ;
2005-04-17 02:20:36 +04:00
2007-08-24 06:55:11 +04:00
if ( ! h | | ! h - > htable )
2005-04-17 02:20:36 +04:00
return NULL ;
2007-08-24 06:55:11 +04:00
hvalue = avtab_hash ( key , h - > mask ) ;
2005-04-17 02:20:36 +04:00
for ( prev = NULL , cur = h - > htable [ hvalue ] ;
cur ;
prev = cur , cur = cur - > next ) {
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class = = cur - > key . target_class & &
2005-09-04 02:55:16 +04:00
( specified & cur - > key . specified ) )
2005-04-17 02:20:36 +04:00
break ;
if ( key - > source_type < cur - > key . source_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type < cur - > key . target_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class < cur - > key . target_class )
break ;
}
2008-07-21 03:50:20 +04:00
return avtab_insert_node ( h , hvalue , prev , cur , key , datum ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:55:16 +04:00
struct avtab_datum * avtab_search ( struct avtab * h , struct avtab_key * key )
2005-04-17 02:20:36 +04:00
{
int hvalue ;
struct avtab_node * cur ;
2005-09-04 02:55:16 +04:00
u16 specified = key - > specified & ~ ( AVTAB_ENABLED | AVTAB_ENABLED_OLD ) ;
2005-04-17 02:20:36 +04:00
2007-08-24 06:55:11 +04:00
if ( ! h | | ! h - > htable )
2005-04-17 02:20:36 +04:00
return NULL ;
2007-08-24 06:55:11 +04:00
hvalue = avtab_hash ( key , h - > mask ) ;
2005-04-17 02:20:36 +04:00
for ( cur = h - > htable [ hvalue ] ; cur ; cur = cur - > next ) {
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class = = cur - > key . target_class & &
2005-09-04 02:55:16 +04:00
( specified & cur - > key . specified ) )
2005-04-17 02:20:36 +04:00
return & cur - > datum ;
if ( key - > source_type < cur - > key . source_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type < cur - > key . target_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class < cur - > key . target_class )
break ;
}
return NULL ;
}
/* This search function returns a node pointer, and can be used in
* conjunction with avtab_search_next_node ( )
*/
struct avtab_node *
2005-09-04 02:55:16 +04:00
avtab_search_node ( struct avtab * h , struct avtab_key * key )
2005-04-17 02:20:36 +04:00
{
int hvalue ;
struct avtab_node * cur ;
2005-09-04 02:55:16 +04:00
u16 specified = key - > specified & ~ ( AVTAB_ENABLED | AVTAB_ENABLED_OLD ) ;
2005-04-17 02:20:36 +04:00
2007-08-24 06:55:11 +04:00
if ( ! h | | ! h - > htable )
2005-04-17 02:20:36 +04:00
return NULL ;
2007-08-24 06:55:11 +04:00
hvalue = avtab_hash ( key , h - > mask ) ;
2005-04-17 02:20:36 +04:00
for ( cur = h - > htable [ hvalue ] ; cur ; cur = cur - > next ) {
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class = = cur - > key . target_class & &
2005-09-04 02:55:16 +04:00
( specified & cur - > key . specified ) )
2005-04-17 02:20:36 +04:00
return cur ;
if ( key - > source_type < cur - > key . source_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type < cur - > key . target_type )
break ;
if ( key - > source_type = = cur - > key . source_type & &
key - > target_type = = cur - > key . target_type & &
key - > target_class < cur - > key . target_class )
break ;
}
return NULL ;
}
struct avtab_node *
avtab_search_node_next ( struct avtab_node * node , int specified )
{
struct avtab_node * cur ;
if ( ! node )
return NULL ;
2005-09-04 02:55:16 +04:00
specified & = ~ ( AVTAB_ENABLED | AVTAB_ENABLED_OLD ) ;
2005-04-17 02:20:36 +04:00
for ( cur = node - > next ; cur ; cur = cur - > next ) {
if ( node - > key . source_type = = cur - > key . source_type & &
node - > key . target_type = = cur - > key . target_type & &
node - > key . target_class = = cur - > key . target_class & &
2005-09-04 02:55:16 +04:00
( specified & cur - > key . specified ) )
2005-04-17 02:20:36 +04:00
return cur ;
if ( node - > key . source_type < cur - > key . source_type )
break ;
if ( node - > key . source_type = = cur - > key . source_type & &
node - > key . target_type < cur - > key . target_type )
break ;
if ( node - > key . source_type = = cur - > key . source_type & &
node - > key . target_type = = cur - > key . target_type & &
node - > key . target_class < cur - > key . target_class )
break ;
}
return NULL ;
}
void avtab_destroy ( struct avtab * h )
{
int i ;
struct avtab_node * cur , * temp ;
if ( ! h | | ! h - > htable )
return ;
2007-08-24 06:55:11 +04:00
for ( i = 0 ; i < h - > nslot ; i + + ) {
2005-04-17 02:20:36 +04:00
cur = h - > htable [ i ] ;
2008-08-07 04:18:20 +04:00
while ( cur ) {
2005-04-17 02:20:36 +04:00
temp = cur ;
cur = cur - > next ;
kmem_cache_free ( avtab_node_cachep , temp ) ;
}
h - > htable [ i ] = NULL ;
}
2007-08-24 06:55:11 +04:00
kfree ( h - > htable ) ;
2005-04-17 02:20:36 +04:00
h - > htable = NULL ;
2007-08-24 06:55:11 +04:00
h - > nslot = 0 ;
h - > mask = 0 ;
2005-04-17 02:20:36 +04:00
}
int avtab_init ( struct avtab * h )
{
2007-08-24 06:55:11 +04:00
h - > htable = NULL ;
h - > nel = 0 ;
return 0 ;
}
int avtab_alloc ( struct avtab * h , u32 nrules )
{
u16 mask = 0 ;
u32 shift = 0 ;
u32 work = nrules ;
u32 nslot = 0 ;
if ( nrules = = 0 )
goto avtab_alloc_out ;
2005-04-17 02:20:36 +04:00
2007-08-24 06:55:11 +04:00
while ( work ) {
work = work > > 1 ;
shift + + ;
}
if ( shift > 2 )
shift = shift - 2 ;
nslot = 1 < < shift ;
2010-10-14 01:50:19 +04:00
if ( nslot > MAX_AVTAB_HASH_BUCKETS )
nslot = MAX_AVTAB_HASH_BUCKETS ;
2007-08-24 06:55:11 +04:00
mask = nslot - 1 ;
h - > htable = kcalloc ( nslot , sizeof ( * ( h - > htable ) ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! h - > htable )
return - ENOMEM ;
2007-08-24 06:55:11 +04:00
avtab_alloc_out :
2005-04-17 02:20:36 +04:00
h - > nel = 0 ;
2007-08-24 06:55:11 +04:00
h - > nslot = nslot ;
h - > mask = mask ;
2008-02-26 12:42:02 +03:00
printk ( KERN_DEBUG " SELinux: %d avtab hash slots, %d rules. \n " ,
h - > nslot , nrules ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
void avtab_hash_eval ( struct avtab * h , char * tag )
{
int i , chain_len , slots_used , max_chain_len ;
2007-08-24 06:55:11 +04:00
unsigned long long chain2_len_sum ;
2005-04-17 02:20:36 +04:00
struct avtab_node * cur ;
slots_used = 0 ;
max_chain_len = 0 ;
2007-08-24 06:55:11 +04:00
chain2_len_sum = 0 ;
for ( i = 0 ; i < h - > nslot ; i + + ) {
2005-04-17 02:20:36 +04:00
cur = h - > htable [ i ] ;
if ( cur ) {
slots_used + + ;
chain_len = 0 ;
while ( cur ) {
chain_len + + ;
cur = cur - > next ;
}
if ( chain_len > max_chain_len )
max_chain_len = chain_len ;
2007-08-24 06:55:11 +04:00
chain2_len_sum + = chain_len * chain_len ;
2005-04-17 02:20:36 +04:00
}
}
2008-04-17 19:52:44 +04:00
printk ( KERN_DEBUG " SELinux: %s: %d entries and %d/%d buckets used, "
2008-05-14 19:27:45 +04:00
" longest chain length %d sum of chain length^2 %llu \n " ,
2007-08-24 06:55:11 +04:00
tag , h - > nel , slots_used , h - > nslot , max_chain_len ,
chain2_len_sum ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:55:16 +04:00
static uint16_t spec_order [ ] = {
AVTAB_ALLOWED ,
AVTAB_AUDITDENY ,
AVTAB_AUDITALLOW ,
AVTAB_TRANSITION ,
AVTAB_CHANGE ,
AVTAB_MEMBER
} ;
2007-11-07 18:08:00 +03:00
int avtab_read_item ( struct avtab * a , void * fp , struct policydb * pol ,
2008-04-19 01:38:28 +04:00
int ( * insertf ) ( struct avtab * a , struct avtab_key * k ,
2005-09-04 02:55:16 +04:00
struct avtab_datum * d , void * p ) ,
void * p )
2005-04-17 02:20:36 +04:00
{
2005-09-04 02:55:17 +04:00
__le16 buf16 [ 4 ] ;
u16 enabled ;
__le32 buf32 [ 7 ] ;
2007-11-07 18:08:00 +03:00
u32 items , items2 , val , vers = pol - > policyvers ;
2005-09-04 02:55:16 +04:00
struct avtab_key key ;
struct avtab_datum datum ;
int i , rc ;
2007-11-07 18:08:00 +03:00
unsigned set ;
2005-09-04 02:55:16 +04:00
memset ( & key , 0 , sizeof ( struct avtab_key ) ) ;
memset ( & datum , 0 , sizeof ( struct avtab_datum ) ) ;
if ( vers < POLICYDB_VERSION_AVTAB ) {
rc = next_entry ( buf32 , fp , sizeof ( u32 ) ) ;
2010-06-12 22:50:35 +04:00
if ( rc ) {
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: truncated entry \n " ) ;
2010-06-12 22:50:35 +04:00
return rc ;
2005-09-04 02:55:16 +04:00
}
items2 = le32_to_cpu ( buf32 [ 0 ] ) ;
if ( items2 > ARRAY_SIZE ( buf32 ) ) {
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: entry overflow \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2005-09-04 02:55:16 +04:00
}
rc = next_entry ( buf32 , fp , sizeof ( u32 ) * items2 ) ;
2010-06-12 22:50:35 +04:00
if ( rc ) {
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: truncated entry \n " ) ;
2010-06-12 22:50:35 +04:00
return rc ;
2005-09-04 02:55:16 +04:00
}
items = 0 ;
2005-04-17 02:20:36 +04:00
2005-09-04 02:55:16 +04:00
val = le32_to_cpu ( buf32 [ items + + ] ) ;
key . source_type = ( u16 ) val ;
if ( key . source_type ! = val ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: truncated source type \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-09-04 02:55:16 +04:00
}
val = le32_to_cpu ( buf32 [ items + + ] ) ;
key . target_type = ( u16 ) val ;
if ( key . target_type ! = val ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: truncated target type \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-09-04 02:55:16 +04:00
}
val = le32_to_cpu ( buf32 [ items + + ] ) ;
key . target_class = ( u16 ) val ;
if ( key . target_class ! = val ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: truncated target class \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-09-04 02:55:16 +04:00
}
val = le32_to_cpu ( buf32 [ items + + ] ) ;
enabled = ( val & AVTAB_ENABLED_OLD ) ? AVTAB_ENABLED : 0 ;
if ( ! ( val & ( AVTAB_AV | AVTAB_TYPE ) ) ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: null entry \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-09-04 02:55:16 +04:00
}
if ( ( val & AVTAB_AV ) & &
( val & AVTAB_TYPE ) ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: entry has both access vectors and types \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-09-04 02:55:16 +04:00
}
2006-01-06 11:11:23 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( spec_order ) ; i + + ) {
2005-09-04 02:55:16 +04:00
if ( val & spec_order [ i ] ) {
key . specified = spec_order [ i ] | enabled ;
datum . data = le32_to_cpu ( buf32 [ items + + ] ) ;
rc = insertf ( a , & key , & datum , p ) ;
2008-04-19 01:38:28 +04:00
if ( rc )
return rc ;
2005-09-04 02:55:16 +04:00
}
}
if ( items ! = items2 ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: entry only had %d items, expected %d \n " , items2 , items ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2005-09-04 02:55:16 +04:00
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:55:16 +04:00
rc = next_entry ( buf16 , fp , sizeof ( u16 ) * 4 ) ;
2010-06-12 22:50:35 +04:00
if ( rc ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: truncated entry \n " ) ;
2010-06-12 22:50:35 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:55:16 +04:00
2005-04-17 02:20:36 +04:00
items = 0 ;
2005-09-04 02:55:16 +04:00
key . source_type = le16_to_cpu ( buf16 [ items + + ] ) ;
key . target_type = le16_to_cpu ( buf16 [ items + + ] ) ;
key . target_class = le16_to_cpu ( buf16 [ items + + ] ) ;
key . specified = le16_to_cpu ( buf16 [ items + + ] ) ;
2007-11-07 18:08:00 +03:00
if ( ! policydb_type_isvalid ( pol , key . source_type ) | |
! policydb_type_isvalid ( pol , key . target_type ) | |
! policydb_class_isvalid ( pol , key . target_class ) ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: invalid type or class \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2007-11-07 18:08:00 +03:00
}
set = 0 ;
for ( i = 0 ; i < ARRAY_SIZE ( spec_order ) ; i + + ) {
if ( key . specified & spec_order [ i ] )
set + + ;
}
if ( ! set | | set > 1 ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: more than one specifier \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2007-11-07 18:08:00 +03:00
}
2005-09-04 02:55:16 +04:00
rc = next_entry ( buf32 , fp , sizeof ( u32 ) ) ;
2010-06-12 22:50:35 +04:00
if ( rc ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: truncated entry \n " ) ;
2010-06-12 22:50:35 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
2005-09-04 02:55:16 +04:00
datum . data = le32_to_cpu ( * buf32 ) ;
2007-11-07 18:08:00 +03:00
if ( ( key . specified & AVTAB_TYPE ) & &
! policydb_type_isvalid ( pol , datum . data ) ) {
2008-04-17 19:52:44 +04:00
printk ( KERN_ERR " SELinux: avtab: invalid type \n " ) ;
2010-06-12 22:50:35 +04:00
return - EINVAL ;
2007-11-07 18:08:00 +03:00
}
2005-09-04 02:55:16 +04:00
return insertf ( a , & key , & datum , p ) ;
}
2005-04-17 02:20:36 +04:00
2005-09-04 02:55:16 +04:00
static int avtab_insertf ( struct avtab * a , struct avtab_key * k ,
struct avtab_datum * d , void * p )
{
return avtab_insert ( a , k , d ) ;
2005-04-17 02:20:36 +04:00
}
2007-11-07 18:08:00 +03:00
int avtab_read ( struct avtab * a , void * fp , struct policydb * pol )
2005-04-17 02:20:36 +04:00
{
int rc ;
2005-09-04 02:55:17 +04:00
__le32 buf [ 1 ] ;
2005-04-17 02:20:36 +04:00
u32 nel , i ;
rc = next_entry ( buf , fp , sizeof ( u32 ) ) ;
if ( rc < 0 ) {
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: truncated table \n " ) ;
2005-04-17 02:20:36 +04:00
goto bad ;
}
nel = le32_to_cpu ( buf [ 0 ] ) ;
if ( ! nel ) {
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: table is empty \n " ) ;
2005-04-17 02:20:36 +04:00
rc = - EINVAL ;
goto bad ;
}
2007-08-24 06:55:11 +04:00
rc = avtab_alloc ( a , nel ) ;
if ( rc )
goto bad ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < nel ; i + + ) {
2007-11-07 18:08:00 +03:00
rc = avtab_read_item ( a , fp , pol , avtab_insertf , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( rc ) {
if ( rc = = - ENOMEM )
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: out of memory \n " ) ;
2005-09-04 02:55:16 +04:00
else if ( rc = = - EEXIST )
2008-02-26 12:42:02 +03:00
printk ( KERN_ERR " SELinux: avtab: duplicate entry \n " ) ;
2010-06-12 22:50:35 +04:00
2005-04-17 02:20:36 +04:00
goto bad ;
}
}
rc = 0 ;
out :
return rc ;
bad :
avtab_destroy ( a ) ;
goto out ;
}
2010-10-14 01:50:25 +04:00
int avtab_write_item ( struct policydb * p , struct avtab_node * cur , void * fp )
{
__le16 buf16 [ 4 ] ;
__le32 buf32 [ 1 ] ;
int rc ;
buf16 [ 0 ] = cpu_to_le16 ( cur - > key . source_type ) ;
buf16 [ 1 ] = cpu_to_le16 ( cur - > key . target_type ) ;
buf16 [ 2 ] = cpu_to_le16 ( cur - > key . target_class ) ;
buf16 [ 3 ] = cpu_to_le16 ( cur - > key . specified ) ;
rc = put_entry ( buf16 , sizeof ( u16 ) , 4 , fp ) ;
if ( rc )
return rc ;
buf32 [ 0 ] = cpu_to_le32 ( cur - > datum . data ) ;
rc = put_entry ( buf32 , sizeof ( u32 ) , 1 , fp ) ;
if ( rc )
return rc ;
return 0 ;
}
int avtab_write ( struct policydb * p , struct avtab * a , void * fp )
{
unsigned int i ;
int rc = 0 ;
struct avtab_node * cur ;
__le32 buf [ 1 ] ;
buf [ 0 ] = cpu_to_le32 ( a - > nel ) ;
rc = put_entry ( buf , sizeof ( u32 ) , 1 , fp ) ;
if ( rc )
return rc ;
for ( i = 0 ; i < a - > nslot ; i + + ) {
for ( cur = a - > htable [ i ] ; cur ; cur = cur - > next ) {
rc = avtab_write_item ( p , cur , fp ) ;
if ( rc )
return rc ;
}
}
return rc ;
}
2005-04-17 02:20:36 +04:00
void avtab_cache_init ( void )
{
avtab_node_cachep = kmem_cache_create ( " avtab_node " ,
sizeof ( struct avtab_node ) ,
2007-07-20 05:11:58 +04:00
0 , SLAB_PANIC , NULL ) ;
2005-04-17 02:20:36 +04:00
}
void avtab_cache_destroy ( void )
{
2008-04-19 01:38:28 +04:00
kmem_cache_destroy ( avtab_node_cachep ) ;
2005-04-17 02:20:36 +04:00
}