2005-04-16 15:20:36 -07:00
/*
* Implementation of the multi - level security ( MLS ) policy .
*
* Author : Stephen Smalley , < sds @ epoch . ncsc . mil >
*/
/*
* Updated : Trusted Computer Solutions , Inc . < dgoeddel @ trustedcs . com >
*
* Support for enhanced MLS infrastructure .
*
2006-02-24 15:44:05 -06:00
* Copyright ( C ) 2004 - 2006 Trusted Computer Solutions , Inc .
2005-04-16 15:20:36 -07:00
*/
2006-08-04 23:17:57 -07:00
/*
* Updated : Hewlett - Packard < paul . moore @ hp . com >
*
2006-11-29 13:18:18 -05:00
* Added support to import / export the MLS label from NetLabel
2006-08-04 23:17:57 -07:00
*
* ( c ) Copyright Hewlett - Packard Development Company , L . P . , 2006
*/
2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/errno.h>
2006-11-29 13:18:18 -05:00
# include <net/netlabel.h>
2005-07-28 01:07:37 -07:00
# include "sidtab.h"
2005-04-16 15:20:36 -07:00
# include "mls.h"
# include "policydb.h"
# include "services.h"
/*
* Return the length in bytes for the MLS fields of the
* security context string representation of ` context ' .
*/
int mls_compute_context_len ( struct context * context )
{
int i , l , len , range ;
2005-09-03 15:55:16 -07:00
struct ebitmap_node * node ;
2005-04-16 15:20:36 -07:00
if ( ! selinux_mls_enabled )
return 0 ;
len = 1 ; /* for the beginning ":" */
for ( l = 0 ; l < 2 ; l + + ) {
range = 0 ;
len + = strlen ( policydb . p_sens_val_to_name [ context - > range . level [ l ] . sens - 1 ] ) ;
2005-09-03 15:55:16 -07:00
ebitmap_for_each_bit ( & context - > range . level [ l ] . cat , node , i ) {
if ( ebitmap_node_get_bit ( node , i ) ) {
2005-04-16 15:20:36 -07:00
if ( range ) {
range + + ;
continue ;
}
2005-09-03 15:55:16 -07:00
len + = strlen ( policydb . p_cat_val_to_name [ i ] ) + 1 ;
2005-04-16 15:20:36 -07:00
range + + ;
} else {
if ( range > 1 )
2005-09-03 15:55:16 -07:00
len + = strlen ( policydb . p_cat_val_to_name [ i - 1 ] ) + 1 ;
2005-04-16 15:20:36 -07:00
range = 0 ;
}
}
/* Handle case where last category is the end of range */
if ( range > 1 )
2005-09-03 15:55:16 -07:00
len + = strlen ( policydb . p_cat_val_to_name [ i - 1 ] ) + 1 ;
2005-04-16 15:20:36 -07:00
if ( l = = 0 ) {
if ( mls_level_eq ( & context - > range . level [ 0 ] ,
& context - > range . level [ 1 ] ) )
break ;
else
len + + ;
}
}
return len ;
}
/*
* Write the security context string representation of
* the MLS fields of ` context ' into the string ` * scontext ' .
* Update ` * scontext ' to point to the end of the MLS fields .
*/
void mls_sid_to_context ( struct context * context ,
char * * scontext )
{
char * scontextp ;
int i , l , range , wrote_sep ;
2005-09-03 15:55:16 -07:00
struct ebitmap_node * node ;
2005-04-16 15:20:36 -07:00
if ( ! selinux_mls_enabled )
return ;
scontextp = * scontext ;
* scontextp = ' : ' ;
scontextp + + ;
for ( l = 0 ; l < 2 ; l + + ) {
range = 0 ;
wrote_sep = 0 ;
strcpy ( scontextp ,
policydb . p_sens_val_to_name [ context - > range . level [ l ] . sens - 1 ] ) ;
scontextp + = strlen ( policydb . p_sens_val_to_name [ context - > range . level [ l ] . sens - 1 ] ) ;
/* categories */
2005-09-03 15:55:16 -07:00
ebitmap_for_each_bit ( & context - > range . level [ l ] . cat , node , i ) {
if ( ebitmap_node_get_bit ( node , i ) ) {
2005-04-16 15:20:36 -07:00
if ( range ) {
range + + ;
continue ;
}
if ( ! wrote_sep ) {
* scontextp + + = ' : ' ;
wrote_sep = 1 ;
} else
* scontextp + + = ' , ' ;
2005-09-03 15:55:16 -07:00
strcpy ( scontextp , policydb . p_cat_val_to_name [ i ] ) ;
scontextp + = strlen ( policydb . p_cat_val_to_name [ i ] ) ;
2005-04-16 15:20:36 -07:00
range + + ;
} else {
if ( range > 1 ) {
if ( range > 2 )
* scontextp + + = ' . ' ;
else
* scontextp + + = ' , ' ;
2005-09-03 15:55:16 -07:00
strcpy ( scontextp , policydb . p_cat_val_to_name [ i - 1 ] ) ;
scontextp + = strlen ( policydb . p_cat_val_to_name [ i - 1 ] ) ;
2005-04-16 15:20:36 -07:00
}
range = 0 ;
}
}
/* Handle case where last category is the end of range */
if ( range > 1 ) {
if ( range > 2 )
* scontextp + + = ' . ' ;
else
* scontextp + + = ' , ' ;
2005-09-03 15:55:16 -07:00
strcpy ( scontextp , policydb . p_cat_val_to_name [ i - 1 ] ) ;
scontextp + = strlen ( policydb . p_cat_val_to_name [ i - 1 ] ) ;
2005-04-16 15:20:36 -07:00
}
if ( l = = 0 ) {
if ( mls_level_eq ( & context - > range . level [ 0 ] ,
& context - > range . level [ 1 ] ) )
break ;
else {
* scontextp = ' - ' ;
scontextp + + ;
}
}
}
* scontext = scontextp ;
return ;
}
/*
* Return 1 if the MLS fields in the security context
* structure ` c ' are valid . Return 0 otherwise .
*/
int mls_context_isvalid ( struct policydb * p , struct context * c )
{
struct level_datum * levdatum ;
struct user_datum * usrdatum ;
2005-09-03 15:55:16 -07:00
struct ebitmap_node * node ;
2005-04-16 15:20:36 -07:00
int i , l ;
if ( ! selinux_mls_enabled )
return 1 ;
/*
* MLS range validity checks : high must dominate low , low level must
* be valid ( category set < - > sensitivity check ) , and high level must
* be valid ( category set < - > sensitivity check )
*/
if ( ! mls_level_dom ( & c - > range . level [ 1 ] , & c - > range . level [ 0 ] ) )
/* High does not dominate low. */
return 0 ;
for ( l = 0 ; l < 2 ; l + + ) {
if ( ! c - > range . level [ l ] . sens | | c - > range . level [ l ] . sens > p - > p_levels . nprim )
return 0 ;
levdatum = hashtab_search ( p - > p_levels . table ,
p - > p_sens_val_to_name [ c - > range . level [ l ] . sens - 1 ] ) ;
if ( ! levdatum )
return 0 ;
2005-09-03 15:55:16 -07:00
ebitmap_for_each_bit ( & c - > range . level [ l ] . cat , node , i ) {
if ( ebitmap_node_get_bit ( node , i ) ) {
2005-04-16 15:20:36 -07:00
if ( i > p - > p_cats . nprim )
return 0 ;
2005-09-03 15:55:16 -07:00
if ( ! ebitmap_get_bit ( & levdatum - > level - > cat , i ) )
2005-04-16 15:20:36 -07:00
/*
* Category may not be associated with
* sensitivity in low level .
*/
return 0 ;
}
}
}
if ( c - > role = = OBJECT_R_VAL )
return 1 ;
/*
* User must be authorized for the MLS range .
*/
if ( ! c - > user | | c - > user > p - > p_users . nprim )
return 0 ;
usrdatum = p - > user_val_to_struct [ c - > user - 1 ] ;
if ( ! mls_range_contains ( usrdatum - > range , c - > range ) )
return 0 ; /* user may not be associated with range */
return 1 ;
}
/*
* Set the MLS fields in the security context structure
* ` context ' based on the string representation in
* the string ` * scontext ' . Update ` * scontext ' to
* point to the end of the string representation of
* the MLS fields .
*
* This function modifies the string in place , inserting
* NULL characters to terminate the MLS fields .
2005-07-28 01:07:37 -07:00
*
* If a def_sid is provided and no MLS field is present ,
* copy the MLS field of the associated default context .
* Used for upgraded to MLS systems where objects may lack
* MLS fields .
*
* Policy read - lock must be held for sidtab lookup .
*
2005-04-16 15:20:36 -07:00
*/
int mls_context_to_sid ( char oldc ,
char * * scontext ,
2005-07-28 01:07:37 -07:00
struct context * context ,
struct sidtab * s ,
u32 def_sid )
2005-04-16 15:20:36 -07:00
{
char delim ;
char * scontextp , * p , * rngptr ;
struct level_datum * levdatum ;
struct cat_datum * catdatum , * rngdatum ;
int l , rc = - EINVAL ;
2005-11-08 21:34:32 -08:00
if ( ! selinux_mls_enabled ) {
if ( def_sid ! = SECSID_NULL & & oldc )
2006-04-18 22:21:04 -07:00
* scontext + = strlen ( * scontext ) + 1 ;
2005-04-16 15:20:36 -07:00
return 0 ;
2005-11-08 21:34:32 -08:00
}
2005-04-16 15:20:36 -07:00
2005-07-28 01:07:37 -07:00
/*
* No MLS component to the security context , try and map to
* default if provided .
*/
if ( ! oldc ) {
struct context * defcon ;
if ( def_sid = = SECSID_NULL )
goto out ;
defcon = sidtab_search ( s , def_sid ) ;
if ( ! defcon )
goto out ;
2006-12-12 13:02:41 -06:00
rc = mls_context_cpy ( context , defcon ) ;
2005-04-16 15:20:36 -07:00
goto out ;
2005-07-28 01:07:37 -07:00
}
2005-04-16 15:20:36 -07:00
/* Extract low sensitivity. */
scontextp = p = * scontext ;
while ( * p & & * p ! = ' : ' & & * p ! = ' - ' )
p + + ;
delim = * p ;
if ( delim ! = 0 )
* p + + = 0 ;
for ( l = 0 ; l < 2 ; l + + ) {
levdatum = hashtab_search ( policydb . p_levels . table , scontextp ) ;
if ( ! levdatum ) {
rc = - EINVAL ;
goto out ;
}
context - > range . level [ l ] . sens = levdatum - > level - > sens ;
if ( delim = = ' : ' ) {
/* Extract category set. */
while ( 1 ) {
scontextp = p ;
while ( * p & & * p ! = ' , ' & & * p ! = ' - ' )
p + + ;
delim = * p ;
if ( delim ! = 0 )
* p + + = 0 ;
/* Separate into range if exists */
if ( ( rngptr = strchr ( scontextp , ' . ' ) ) ! = NULL ) {
/* Remove '.' */
* rngptr + + = 0 ;
}
catdatum = hashtab_search ( policydb . p_cats . table ,
scontextp ) ;
if ( ! catdatum ) {
rc = - EINVAL ;
goto out ;
}
rc = ebitmap_set_bit ( & context - > range . level [ l ] . cat ,
catdatum - > value - 1 , 1 ) ;
if ( rc )
goto out ;
/* If range, set all categories in range */
if ( rngptr ) {
int i ;
rngdatum = hashtab_search ( policydb . p_cats . table , rngptr ) ;
if ( ! rngdatum ) {
rc = - EINVAL ;
goto out ;
}
if ( catdatum - > value > = rngdatum - > value ) {
rc = - EINVAL ;
goto out ;
}
for ( i = catdatum - > value ; i < rngdatum - > value ; i + + ) {
rc = ebitmap_set_bit ( & context - > range . level [ l ] . cat , i , 1 ) ;
if ( rc )
goto out ;
}
}
if ( delim ! = ' , ' )
break ;
}
}
if ( delim = = ' - ' ) {
/* Extract high sensitivity. */
scontextp = p ;
while ( * p & & * p ! = ' : ' )
p + + ;
delim = * p ;
if ( delim ! = 0 )
* p + + = 0 ;
} else
break ;
}
if ( l = = 0 ) {
context - > range . level [ 1 ] . sens = context - > range . level [ 0 ] . sens ;
rc = ebitmap_cpy ( & context - > range . level [ 1 ] . cat ,
& context - > range . level [ 0 ] . cat ) ;
if ( rc )
goto out ;
}
* scontext = + + p ;
rc = 0 ;
out :
return rc ;
}
2006-02-24 15:44:05 -06:00
/*
* Set the MLS fields in the security context structure
* ` context ' based on the string representation in
* the string ` str ' . This function will allocate temporary memory with the
* given constraints of gfp_mask .
*/
int mls_from_string ( char * str , struct context * context , gfp_t gfp_mask )
{
char * tmpstr , * freestr ;
int rc ;
if ( ! selinux_mls_enabled )
return - EINVAL ;
/* we need freestr because mls_context_to_sid will change
the value of tmpstr */
tmpstr = freestr = kstrdup ( str , gfp_mask ) ;
if ( ! tmpstr ) {
rc = - ENOMEM ;
} else {
rc = mls_context_to_sid ( ' : ' , & tmpstr , context ,
NULL , SECSID_NULL ) ;
kfree ( freestr ) ;
}
return rc ;
}
2005-04-16 15:20:36 -07:00
/*
* Copies the MLS range ` range ' into ` context ' .
*/
static inline int mls_range_set ( struct context * context ,
struct mls_range * range )
{
int l , rc = 0 ;
/* Copy the MLS range into the context */
for ( l = 0 ; l < 2 ; l + + ) {
context - > range . level [ l ] . sens = range - > level [ l ] . sens ;
rc = ebitmap_cpy ( & context - > range . level [ l ] . cat ,
& range - > level [ l ] . cat ) ;
if ( rc )
break ;
}
return rc ;
}
int mls_setup_user_range ( struct context * fromcon , struct user_datum * user ,
struct context * usercon )
{
if ( selinux_mls_enabled ) {
struct mls_level * fromcon_sen = & ( fromcon - > range . level [ 0 ] ) ;
struct mls_level * fromcon_clr = & ( fromcon - > range . level [ 1 ] ) ;
struct mls_level * user_low = & ( user - > range . level [ 0 ] ) ;
struct mls_level * user_clr = & ( user - > range . level [ 1 ] ) ;
struct mls_level * user_def = & ( user - > dfltlevel ) ;
struct mls_level * usercon_sen = & ( usercon - > range . level [ 0 ] ) ;
struct mls_level * usercon_clr = & ( usercon - > range . level [ 1 ] ) ;
/* Honor the user's default level if we can */
if ( mls_level_between ( user_def , fromcon_sen , fromcon_clr ) ) {
* usercon_sen = * user_def ;
} else if ( mls_level_between ( fromcon_sen , user_def , user_clr ) ) {
* usercon_sen = * fromcon_sen ;
} else if ( mls_level_between ( fromcon_clr , user_low , user_def ) ) {
* usercon_sen = * user_low ;
} else
return - EINVAL ;
/* Lower the clearance of available contexts
if the clearance of " fromcon " is lower than
that of the user ' s default clearance ( but
only if the " fromcon " clearance dominates
the user ' s computed sensitivity level ) */
if ( mls_level_dom ( user_clr , fromcon_clr ) ) {
* usercon_clr = * fromcon_clr ;
} else if ( mls_level_dom ( fromcon_clr , user_clr ) ) {
* usercon_clr = * user_clr ;
} else
return - EINVAL ;
}
return 0 ;
}
/*
* Convert the MLS fields in the security context
* structure ` c ' from the values specified in the
* policy ` oldp ' to the values specified in the policy ` newp ' .
*/
int mls_convert_context ( struct policydb * oldp ,
struct policydb * newp ,
struct context * c )
{
struct level_datum * levdatum ;
struct cat_datum * catdatum ;
struct ebitmap bitmap ;
2005-09-03 15:55:16 -07:00
struct ebitmap_node * node ;
2005-04-16 15:20:36 -07:00
int l , i ;
if ( ! selinux_mls_enabled )
return 0 ;
for ( l = 0 ; l < 2 ; l + + ) {
levdatum = hashtab_search ( newp - > p_levels . table ,
oldp - > p_sens_val_to_name [ c - > range . level [ l ] . sens - 1 ] ) ;
if ( ! levdatum )
return - EINVAL ;
c - > range . level [ l ] . sens = levdatum - > level - > sens ;
ebitmap_init ( & bitmap ) ;
2005-09-03 15:55:16 -07:00
ebitmap_for_each_bit ( & c - > range . level [ l ] . cat , node , i ) {
if ( ebitmap_node_get_bit ( node , i ) ) {
2005-04-16 15:20:36 -07:00
int rc ;
catdatum = hashtab_search ( newp - > p_cats . table ,
2005-09-03 15:55:16 -07:00
oldp - > p_cat_val_to_name [ i ] ) ;
2005-04-16 15:20:36 -07:00
if ( ! catdatum )
return - EINVAL ;
rc = ebitmap_set_bit ( & bitmap , catdatum - > value - 1 , 1 ) ;
if ( rc )
return rc ;
}
}
ebitmap_destroy ( & c - > range . level [ l ] . cat ) ;
c - > range . level [ l ] . cat = bitmap ;
}
return 0 ;
}
int mls_compute_sid ( struct context * scontext ,
struct context * tcontext ,
u16 tclass ,
u32 specified ,
struct context * newcontext )
{
2006-09-25 23:31:59 -07:00
struct range_trans * rtr ;
2005-04-16 15:20:36 -07:00
if ( ! selinux_mls_enabled )
return 0 ;
switch ( specified ) {
case AVTAB_TRANSITION :
2006-09-25 23:31:59 -07:00
/* Look for a range transition rule. */
for ( rtr = policydb . range_tr ; rtr ; rtr = rtr - > next ) {
if ( rtr - > source_type = = scontext - > type & &
rtr - > target_type = = tcontext - > type & &
rtr - > target_class = = tclass ) {
/* Set the range from the rule */
return mls_range_set ( newcontext ,
& rtr - > target_range ) ;
2005-04-16 15:20:36 -07:00
}
}
/* Fallthrough */
case AVTAB_CHANGE :
if ( tclass = = SECCLASS_PROCESS )
/* Use the process MLS attributes. */
2006-12-12 13:02:41 -06:00
return mls_context_cpy ( newcontext , scontext ) ;
2005-04-16 15:20:36 -07:00
else
/* Use the process effective MLS attributes. */
2006-12-12 13:02:41 -06:00
return mls_context_cpy_low ( newcontext , scontext ) ;
2005-04-16 15:20:36 -07:00
case AVTAB_MEMBER :
/* Only polyinstantiate the MLS attributes if
the type is being polyinstantiated */
if ( newcontext - > type ! = tcontext - > type ) {
/* Use the process effective MLS attributes. */
2006-12-12 13:02:41 -06:00
return mls_context_cpy_low ( newcontext , scontext ) ;
2005-04-16 15:20:36 -07:00
} else {
/* Use the related object MLS attributes. */
2006-12-12 13:02:41 -06:00
return mls_context_cpy ( newcontext , tcontext ) ;
2005-04-16 15:20:36 -07:00
}
default :
return - EINVAL ;
}
return - EINVAL ;
}
2006-11-29 13:18:18 -05:00
# ifdef CONFIG_NETLABEL
2006-08-04 23:17:57 -07:00
/**
2006-11-29 13:18:18 -05:00
* mls_export_netlbl_lvl - Export the MLS sensitivity levels to NetLabel
2006-08-04 23:17:57 -07:00
* @ context : the security context
2006-11-29 13:18:18 -05:00
* @ secattr : the NetLabel security attributes
2006-08-04 23:17:57 -07:00
*
* Description :
2006-11-29 13:18:18 -05:00
* Given the security context copy the low MLS sensitivity level into the
* NetLabel MLS sensitivity level field .
2006-08-04 23:17:57 -07:00
*
*/
2006-11-29 13:18:18 -05:00
void mls_export_netlbl_lvl ( struct context * context ,
struct netlbl_lsm_secattr * secattr )
2006-08-04 23:17:57 -07:00
{
if ( ! selinux_mls_enabled )
return ;
2006-11-29 13:18:18 -05:00
secattr - > mls_lvl = context - > range . level [ 0 ] . sens - 1 ;
secattr - > flags | = NETLBL_SECATTR_MLS_LVL ;
2006-08-04 23:17:57 -07:00
}
/**
2006-11-29 13:18:18 -05:00
* mls_import_netlbl_lvl - Import the NetLabel MLS sensitivity levels
2006-08-04 23:17:57 -07:00
* @ context : the security context
2006-11-29 13:18:18 -05:00
* @ secattr : the NetLabel security attributes
2006-08-04 23:17:57 -07:00
*
* Description :
2006-11-29 13:18:18 -05:00
* Given the security context and the NetLabel security attributes , copy the
* NetLabel MLS sensitivity level into the context .
2006-08-04 23:17:57 -07:00
*
*/
2006-11-29 13:18:18 -05:00
void mls_import_netlbl_lvl ( struct context * context ,
struct netlbl_lsm_secattr * secattr )
2006-08-04 23:17:57 -07:00
{
if ( ! selinux_mls_enabled )
return ;
2006-11-29 13:18:18 -05:00
context - > range . level [ 0 ] . sens = secattr - > mls_lvl + 1 ;
context - > range . level [ 1 ] . sens = context - > range . level [ 0 ] . sens ;
2006-08-04 23:17:57 -07:00
}
/**
2006-11-29 13:18:18 -05:00
* mls_export_netlbl_cat - Export the MLS categories to NetLabel
2006-08-04 23:17:57 -07:00
* @ context : the security context
2006-11-29 13:18:18 -05:00
* @ secattr : the NetLabel security attributes
2006-08-04 23:17:57 -07:00
*
* Description :
2006-11-29 13:18:18 -05:00
* Given the security context copy the low MLS categories into the NetLabel
* MLS category field . Returns zero on success , negative values on failure .
2006-08-04 23:17:57 -07:00
*
*/
2006-11-29 13:18:18 -05:00
int mls_export_netlbl_cat ( struct context * context ,
struct netlbl_lsm_secattr * secattr )
2006-08-04 23:17:57 -07:00
{
2006-11-29 13:18:18 -05:00
int rc ;
2006-08-04 23:17:57 -07:00
2006-11-29 13:18:18 -05:00
if ( ! selinux_mls_enabled )
2006-08-04 23:17:57 -07:00
return 0 ;
2006-11-29 13:18:18 -05:00
rc = ebitmap_netlbl_export ( & context - > range . level [ 0 ] . cat ,
& secattr - > mls_cat ) ;
if ( rc = = 0 & & secattr - > mls_cat ! = NULL )
secattr - > flags | = NETLBL_SECATTR_MLS_CAT ;
2006-08-04 23:17:57 -07:00
return rc ;
}
/**
2006-11-29 13:18:18 -05:00
* mls_import_netlbl_cat - Import the MLS categories from NetLabel
2006-08-04 23:17:57 -07:00
* @ context : the security context
2006-11-29 13:18:18 -05:00
* @ secattr : the NetLabel security attributes
2006-08-04 23:17:57 -07:00
*
* Description :
2006-11-29 13:18:18 -05:00
* Copy the NetLabel security attributes into the SELinux context ; since the
* NetLabel security attribute only contains a single MLS category use it for
* both the low and high categories of the context . Returns zero on success ,
* negative values on failure .
2006-08-04 23:17:57 -07:00
*
*/
2006-11-29 13:18:18 -05:00
int mls_import_netlbl_cat ( struct context * context ,
struct netlbl_lsm_secattr * secattr )
2006-08-04 23:17:57 -07:00
{
2006-11-29 13:18:18 -05:00
int rc ;
2006-08-04 23:17:57 -07:00
if ( ! selinux_mls_enabled )
return 0 ;
2006-11-29 13:18:18 -05:00
rc = ebitmap_netlbl_import ( & context - > range . level [ 0 ] . cat ,
secattr - > mls_cat ) ;
if ( rc ! = 0 )
goto import_netlbl_cat_failure ;
rc = ebitmap_cpy ( & context - > range . level [ 1 ] . cat ,
& context - > range . level [ 0 ] . cat ) ;
if ( rc ! = 0 )
goto import_netlbl_cat_failure ;
2006-08-04 23:17:57 -07:00
return 0 ;
2006-11-29 13:18:18 -05:00
import_netlbl_cat_failure :
2006-08-04 23:17:57 -07:00
ebitmap_destroy ( & context - > range . level [ 0 ] . cat ) ;
ebitmap_destroy ( & context - > range . level [ 1 ] . cat ) ;
return rc ;
}
2006-11-29 13:18:18 -05:00
# endif /* CONFIG_NETLABEL */