Commit 44c3b591 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/selinux-2.6:
  security: compile capabilities by default
  selinux: make selinux_set_mnt_opts() static
  SELinux: Add warning messages on network denial due to error
  SELinux: Add network ingress and egress control permission checks
  NetLabel: Add auditing to the static labeling mechanism
  NetLabel: Introduce static network labels for unlabeled connections
  SELinux: Allow NetLabel to directly cache SIDs
  SELinux: Enable dynamic enable/disable of the network access checks
  SELinux: Better integration between peer labeling subsystems
  SELinux: Add a new peer class and permissions to the Flask definitions
  SELinux: Add a capabilities bitmap to SELinux policy version 22
  SELinux: Add a network node caching mechanism similar to the sel_netif_*() functions
  SELinux: Only store the network interface's ifindex
  SELinux: Convert the netif code to use ifindex values
  NetLabel: Add IP address family information to the netlbl_skbuff_getattr() function
  NetLabel: Add secid token support to the NetLabel secattr struct
  NetLabel: Consolidate the LSM domain mapping/hashing locks
  NetLabel: Cleanup the LSM domain hash functions
  NetLabel: Remove unneeded RCU read locks
parents 3b470ac4 f71ea9dd
...@@ -115,6 +115,8 @@ ...@@ -115,6 +115,8 @@
#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */ #define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */
#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */ #define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */
#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */ #define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
#define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799 #define AUDIT_LAST_KERN_ANOM_MSG 1799
......
...@@ -120,16 +120,35 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid); ...@@ -120,16 +120,35 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
int selinux_string_to_sid(char *str, u32 *sid); int selinux_string_to_sid(char *str, u32 *sid);
/** /**
* selinux_relabel_packet_permission - check permission to relabel a packet * selinux_secmark_relabel_packet_permission - secmark permission check
* @sid: ID value to be applied to network packet (via SECMARK, most likely) * @sid: SECMARK ID value to be applied to network packet
* *
* Returns 0 if the current task is allowed to label packets with the * Returns 0 if the current task is allowed to set the SECMARK label of
* supplied security ID. Note that it is implicit that the packet is always * packets with the supplied security ID. Note that it is implicit that
* being relabeled from the default unlabled value, and that the access * the packet is always being relabeled from the default unlabeled value,
* control decision is made in the AVC. * and that the access control decision is made in the AVC.
*/ */
int selinux_relabel_packet_permission(u32 sid); int selinux_secmark_relabel_packet_permission(u32 sid);
/**
* selinux_secmark_refcount_inc - increments the secmark use counter
*
* SELinux keeps track of the current SECMARK targets in use so it knows
* when to apply SECMARK label access checks to network packets. This
* function incements this reference count to indicate that a new SECMARK
* target has been configured.
*/
void selinux_secmark_refcount_inc(void);
/**
* selinux_secmark_refcount_dec - decrements the secmark use counter
*
* SELinux keeps track of the current SECMARK targets in use so it knows
* when to apply SECMARK label access checks to network packets. This
* function decements this reference count to indicate that one of the
* existing SECMARK targets has been removed/flushed.
*/
void selinux_secmark_refcount_dec(void);
#else #else
static inline int selinux_audit_rule_init(u32 field, u32 op, static inline int selinux_audit_rule_init(u32 field, u32 op,
...@@ -184,11 +203,21 @@ static inline int selinux_string_to_sid(const char *str, u32 *sid) ...@@ -184,11 +203,21 @@ static inline int selinux_string_to_sid(const char *str, u32 *sid)
return 0; return 0;
} }
static inline int selinux_relabel_packet_permission(u32 sid) static inline int selinux_secmark_relabel_packet_permission(u32 sid)
{ {
return 0; return 0;
} }
static inline void selinux_secmark_refcount_inc(void)
{
return;
}
static inline void selinux_secmark_refcount_dec(void)
{
return;
}
#endif /* CONFIG_SECURITY_SELINUX */ #endif /* CONFIG_SECURITY_SELINUX */
#endif /* _LINUX_SELINUX_H */ #endif /* _LINUX_SELINUX_H */
...@@ -67,7 +67,11 @@ ...@@ -67,7 +67,11 @@
* NetLabel NETLINK protocol * NetLabel NETLINK protocol
*/ */
#define NETLBL_PROTO_VERSION 1 /* NetLabel NETLINK protocol version
* 1: initial version
* 2: added static labels for unlabeled connections
*/
#define NETLBL_PROTO_VERSION 2
/* NetLabel NETLINK types/families */ /* NetLabel NETLINK types/families */
#define NETLBL_NLTYPE_NONE 0 #define NETLBL_NLTYPE_NONE 0
...@@ -105,17 +109,49 @@ struct netlbl_dom_map; ...@@ -105,17 +109,49 @@ struct netlbl_dom_map;
/* Domain mapping operations */ /* Domain mapping operations */
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info); int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
/* LSM security attributes */ /*
* LSM security attributes
*/
/**
* struct netlbl_lsm_cache - NetLabel LSM security attribute cache
* @refcount: atomic reference counter
* @free: LSM supplied function to free the cache data
* @data: LSM supplied cache data
*
* Description:
* This structure is provided for LSMs which wish to make use of the NetLabel
* caching mechanism to store LSM specific data/attributes in the NetLabel
* cache. If the LSM has to perform a lot of translation from the NetLabel
* security attributes into it's own internal representation then the cache
* mechanism can provide a way to eliminate some or all of that translation
* overhead on a cache hit.
*
*/
struct netlbl_lsm_cache { struct netlbl_lsm_cache {
atomic_t refcount; atomic_t refcount;
void (*free) (const void *data); void (*free) (const void *data);
void *data; void *data;
}; };
/* The catmap bitmap field MUST be a power of two in length and large
/**
* struct netlbl_lsm_secattr_catmap - NetLabel LSM secattr category bitmap
* @startbit: the value of the lowest order bit in the bitmap
* @bitmap: the category bitmap
* @next: pointer to the next bitmap "node" or NULL
*
* Description:
* This structure is used to represent category bitmaps. Due to the large
* number of categories supported by most labeling protocols it is not
* practical to transfer a full bitmap internally so NetLabel adopts a sparse
* bitmap structure modeled after SELinux's ebitmap structure.
* The catmap bitmap field MUST be a power of two in length and large
* enough to hold at least 240 bits. Special care (i.e. check the code!) * enough to hold at least 240 bits. Special care (i.e. check the code!)
* should be used when changing these values as the LSM implementation * should be used when changing these values as the LSM implementation
* probably has functions which rely on the sizes of these types to speed * probably has functions which rely on the sizes of these types to speed
* processing. */ * processing.
*
*/
#define NETLBL_CATMAP_MAPTYPE u64 #define NETLBL_CATMAP_MAPTYPE u64
#define NETLBL_CATMAP_MAPCNT 4 #define NETLBL_CATMAP_MAPCNT 4
#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8) #define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8)
...@@ -127,22 +163,48 @@ struct netlbl_lsm_secattr_catmap { ...@@ -127,22 +163,48 @@ struct netlbl_lsm_secattr_catmap {
NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT];
struct netlbl_lsm_secattr_catmap *next; struct netlbl_lsm_secattr_catmap *next;
}; };
/**
* struct netlbl_lsm_secattr - NetLabel LSM security attributes
* @flags: indicate which attributes are contained in this structure
* @type: indicate the NLTYPE of the attributes
* @domain: the NetLabel LSM domain
* @cache: NetLabel LSM specific cache
* @attr.mls: MLS sensitivity label
* @attr.mls.cat: MLS category bitmap
* @attr.mls.lvl: MLS sensitivity level
* @attr.secid: LSM specific secid token
*
* Description:
* This structure is used to pass security attributes between NetLabel and the
* LSM modules. The flags field is used to specify which fields within the
* struct are valid and valid values can be created by bitwise OR'ing the
* NETLBL_SECATTR_* defines. The domain field is typically set by the LSM to
* specify domain specific configuration settings and is not usually used by
* NetLabel itself when returning security attributes to the LSM.
*
*/
#define NETLBL_SECATTR_NONE 0x00000000 #define NETLBL_SECATTR_NONE 0x00000000
#define NETLBL_SECATTR_DOMAIN 0x00000001 #define NETLBL_SECATTR_DOMAIN 0x00000001
#define NETLBL_SECATTR_CACHE 0x00000002 #define NETLBL_SECATTR_CACHE 0x00000002
#define NETLBL_SECATTR_MLS_LVL 0x00000004 #define NETLBL_SECATTR_MLS_LVL 0x00000004
#define NETLBL_SECATTR_MLS_CAT 0x00000008 #define NETLBL_SECATTR_MLS_CAT 0x00000008
#define NETLBL_SECATTR_SECID 0x00000010
#define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \ #define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \
NETLBL_SECATTR_MLS_CAT) NETLBL_SECATTR_MLS_CAT | \
NETLBL_SECATTR_SECID)
struct netlbl_lsm_secattr { struct netlbl_lsm_secattr {
u32 flags; u32 flags;
u32 type;
char *domain; char *domain;
u32 mls_lvl;
struct netlbl_lsm_secattr_catmap *mls_cat;
struct netlbl_lsm_cache *cache; struct netlbl_lsm_cache *cache;
union {
struct {
struct netlbl_lsm_secattr_catmap *cat;
u32 lvl;
} mls;
u32 secid;
} attr;
}; };
/* /*
...@@ -231,10 +293,7 @@ static inline void netlbl_secattr_catmap_free( ...@@ -231,10 +293,7 @@ static inline void netlbl_secattr_catmap_free(
*/ */
static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
{ {
secattr->flags = 0; memset(secattr, 0, sizeof(*secattr));
secattr->domain = NULL;
secattr->mls_cat = NULL;
secattr->cache = NULL;
} }
/** /**
...@@ -248,11 +307,11 @@ static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) ...@@ -248,11 +307,11 @@ static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
*/ */
static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
{ {
if (secattr->cache)
netlbl_secattr_cache_free(secattr->cache);
kfree(secattr->domain); kfree(secattr->domain);
if (secattr->mls_cat) if (secattr->flags & NETLBL_SECATTR_CACHE)
netlbl_secattr_catmap_free(secattr->mls_cat); netlbl_secattr_cache_free(secattr->cache);
if (secattr->flags & NETLBL_SECATTR_MLS_CAT)
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
} }
/** /**
...@@ -300,7 +359,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap, ...@@ -300,7 +359,7 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
gfp_t flags); gfp_t flags);
/* /*
* LSM protocol operations * LSM protocol operations (NetLabel LSM/kernel API)
*/ */
int netlbl_enabled(void); int netlbl_enabled(void);
int netlbl_sock_setattr(struct sock *sk, int netlbl_sock_setattr(struct sock *sk,
...@@ -308,6 +367,7 @@ int netlbl_sock_setattr(struct sock *sk, ...@@ -308,6 +367,7 @@ int netlbl_sock_setattr(struct sock *sk,
int netlbl_sock_getattr(struct sock *sk, int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
int netlbl_skbuff_getattr(const struct sk_buff *skb, int netlbl_skbuff_getattr(const struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
void netlbl_skbuff_err(struct sk_buff *skb, int error); void netlbl_skbuff_err(struct sk_buff *skb, int error);
...@@ -360,6 +420,7 @@ static inline int netlbl_sock_getattr(struct sock *sk, ...@@ -360,6 +420,7 @@ static inline int netlbl_sock_getattr(struct sock *sk,
return -ENOSYS; return -ENOSYS;
} }
static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
return -ENOSYS; return -ENOSYS;
......
...@@ -348,6 +348,7 @@ static int cipso_v4_cache_check(const unsigned char *key, ...@@ -348,6 +348,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
atomic_inc(&entry->lsm_data->refcount); atomic_inc(&entry->lsm_data->refcount);
secattr->cache = entry->lsm_data; secattr->cache = entry->lsm_data;
secattr->flags |= NETLBL_SECATTR_CACHE; secattr->flags |= NETLBL_SECATTR_CACHE;
secattr->type = NETLBL_NLTYPE_CIPSOV4;
if (prev_entry == NULL) { if (prev_entry == NULL) {
spin_unlock_bh(&cipso_v4_cache[bkt].lock); spin_unlock_bh(&cipso_v4_cache[bkt].lock);
return 0; return 0;
...@@ -865,7 +866,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def, ...@@ -865,7 +866,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
} }
for (;;) { for (;;) {
host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat, host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
host_spot + 1); host_spot + 1);
if (host_spot < 0) if (host_spot < 0)
break; break;
...@@ -948,7 +949,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def, ...@@ -948,7 +949,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
return -EPERM; return -EPERM;
break; break;
} }
ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
host_spot, host_spot,
GFP_ATOMIC); GFP_ATOMIC);
if (ret_val != 0) if (ret_val != 0)
...@@ -1014,7 +1015,8 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def, ...@@ -1014,7 +1015,8 @@ static int cipso_v4_map_cat_enum_hton(const struct cipso_v4_doi *doi_def,
u32 cat_iter = 0; u32 cat_iter = 0;
for (;;) { for (;;) {
cat = netlbl_secattr_catmap_walk(secattr->mls_cat, cat + 1); cat = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
cat + 1);
if (cat < 0) if (cat < 0)
break; break;
if ((cat_iter + 2) > net_cat_len) if ((cat_iter + 2) > net_cat_len)
...@@ -1049,7 +1051,7 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def, ...@@ -1049,7 +1051,7 @@ static int cipso_v4_map_cat_enum_ntoh(const struct cipso_v4_doi *doi_def,
u32 iter; u32 iter;
for (iter = 0; iter < net_cat_len; iter += 2) { for (iter = 0; iter < net_cat_len; iter += 2) {
ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat, ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
ntohs(get_unaligned((__be16 *)&net_cat[iter])), ntohs(get_unaligned((__be16 *)&net_cat[iter])),
GFP_ATOMIC); GFP_ATOMIC);
if (ret_val != 0) if (ret_val != 0)
...@@ -1130,7 +1132,8 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, ...@@ -1130,7 +1132,8 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
return -ENOSPC; return -ENOSPC;
for (;;) { for (;;) {
iter = netlbl_secattr_catmap_walk(secattr->mls_cat, iter + 1); iter = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
iter + 1);
if (iter < 0) if (iter < 0)
break; break;
cat_size += (iter == 0 ? 0 : sizeof(u16)); cat_size += (iter == 0 ? 0 : sizeof(u16));
...@@ -1138,7 +1141,8 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def, ...@@ -1138,7 +1141,8 @@ static int cipso_v4_map_cat_rng_hton(const struct cipso_v4_doi *doi_def,
return -ENOSPC; return -ENOSPC;
array[array_cnt++] = iter; array[array_cnt++] = iter;
iter = netlbl_secattr_catmap_walk_rng(secattr->mls_cat, iter); iter = netlbl_secattr_catmap_walk_rng(secattr->attr.mls.cat,
iter);
if (iter < 0) if (iter < 0)
return -EFAULT; return -EFAULT;
cat_size += sizeof(u16); cat_size += sizeof(u16);
...@@ -1191,7 +1195,7 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def, ...@@ -1191,7 +1195,7 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
else else
cat_low = 0; cat_low = 0;
ret_val = netlbl_secattr_catmap_setrng(secattr->mls_cat, ret_val = netlbl_secattr_catmap_setrng(secattr->attr.mls.cat,
cat_low, cat_low,
cat_high, cat_high,
GFP_ATOMIC); GFP_ATOMIC);
...@@ -1251,7 +1255,9 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def, ...@@ -1251,7 +1255,9 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0) if ((secattr->flags & NETLBL_SECATTR_MLS_LVL) == 0)
return -EPERM; return -EPERM;
ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); ret_val = cipso_v4_map_lvl_hton(doi_def,
secattr->attr.mls.lvl,
&level);
if (ret_val != 0) if (ret_val != 0)
return ret_val; return ret_val;
...@@ -1303,12 +1309,13 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, ...@@ -1303,12 +1309,13 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
if (ret_val != 0) if (ret_val != 0)
return ret_val; return ret_val;
secattr->mls_lvl = level; secattr->attr.mls.lvl = level;
secattr->flags |= NETLBL_SECATTR_MLS_LVL; secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) { if (tag_len > 4) {
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); secattr->attr.mls.cat =
if (secattr->mls_cat == NULL) netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->attr.mls.cat == NULL)
return -ENOMEM; return -ENOMEM;
ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def, ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
...@@ -1316,7 +1323,7 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def, ...@@ -1316,7 +1323,7 @@ static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
tag_len - 4, tag_len - 4,
secattr); secattr);
if (ret_val != 0) { if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->mls_cat); netlbl_secattr_catmap_free(secattr->attr.mls.cat);
return ret_val; return ret_val;
} }
...@@ -1350,7 +1357,9 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def, ...@@ -1350,7 +1357,9 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
return -EPERM; return -EPERM;
ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); ret_val = cipso_v4_map_lvl_hton(doi_def,
secattr->attr.mls.lvl,
&level);
if (ret_val != 0) if (ret_val != 0)
return ret_val; return ret_val;
...@@ -1396,12 +1405,13 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, ...@@ -1396,12 +1405,13 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
if (ret_val != 0) if (ret_val != 0)
return ret_val; return ret_val;
secattr->mls_lvl = level; secattr->attr.mls.lvl = level;
secattr->flags |= NETLBL_SECATTR_MLS_LVL; secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) { if (tag_len > 4) {
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); secattr->attr.mls.cat =
if (secattr->mls_cat == NULL) netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->attr.mls.cat == NULL)
return -ENOMEM; return -ENOMEM;
ret_val = cipso_v4_map_cat_enum_ntoh(doi_def, ret_val = cipso_v4_map_cat_enum_ntoh(doi_def,
...@@ -1409,7 +1419,7 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def, ...@@ -1409,7 +1419,7 @@ static int cipso_v4_parsetag_enum(const struct cipso_v4_doi *doi_def,
tag_len - 4, tag_len - 4,
secattr); secattr);
if (ret_val != 0) { if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->mls_cat); netlbl_secattr_catmap_free(secattr->attr.mls.cat);
return ret_val; return ret_val;
} }
...@@ -1443,7 +1453,9 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def, ...@@ -1443,7 +1453,9 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL)) if (!(secattr->flags & NETLBL_SECATTR_MLS_LVL))
return -EPERM; return -EPERM;
ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level); ret_val = cipso_v4_map_lvl_hton(doi_def,
secattr->attr.mls.lvl,
&level);
if (ret_val != 0) if (ret_val != 0)
return ret_val; return ret_val;
...@@ -1488,12 +1500,13 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, ...@@ -1488,12 +1500,13 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level); ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
if (ret_val != 0) if (ret_val != 0)
return ret_val; return ret_val;
secattr->mls_lvl = level; secattr->attr.mls.lvl = level;
secattr->flags |= NETLBL_SECATTR_MLS_LVL; secattr->flags |= NETLBL_SECATTR_MLS_LVL;
if (tag_len > 4) { if (tag_len > 4) {
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); secattr->attr.mls.cat =
if (secattr->mls_cat == NULL) netlbl_secattr_catmap_alloc(GFP_ATOMIC);
if (secattr->attr.mls.cat == NULL)
return -ENOMEM; return -ENOMEM;
ret_val = cipso_v4_map_cat_rng_ntoh(doi_def, ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,
...@@ -1501,7 +1514,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def, ...@@ -1501,7 +1514,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
tag_len - 4, tag_len - 4,
secattr); secattr);
if (ret_val != 0) { if (ret_val != 0) {
netlbl_secattr_catmap_free(secattr->mls_cat); netlbl_secattr_catmap_free(secattr->attr.mls.cat);
return ret_val; return ret_val;
} }
...@@ -1850,6 +1863,8 @@ static int cipso_v4_getattr(const unsigned char *cipso, ...@@ -1850,6 +1863,8 @@ static int cipso_v4_getattr(const unsigned char *cipso,
ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr); ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);
break; break;
} }
if (ret_val == 0)
secattr->type = NETLBL_NLTYPE_CIPSOV4;
getattr_return: getattr_return:
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -72,12 +72,13 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info) ...@@ -72,12 +72,13 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info)
return false; return false;
} }
err = selinux_relabel_packet_permission(sel->selsid); err = selinux_secmark_relabel_packet_permission(sel->selsid);
if (err) { if (err) {
printk(KERN_INFO PFX "unable to obtain relabeling permission\n"); printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
return false; return false;
} }
selinux_secmark_refcount_inc();
return true; return true;
} }
...@@ -110,11 +111,20 @@ secmark_tg_check(const char *tablename, const void *entry, ...@@ -110,11 +111,20 @@ secmark_tg_check(const char *tablename, const void *entry,
return true; return true;
} }
void secmark_tg_destroy(const struct xt_target *target, void *targinfo)
{
switch (mode) {
case SECMARK_MODE_SEL:
selinux_secmark_refcount_dec();
}
}
static struct xt_target secmark_tg_reg[] __read_mostly = { static struct xt_target secmark_tg_reg[] __read_mostly = {
{ {
.name = "SECMARK", .name = "SECMARK",
.family = AF_INET, .family = AF_INET,
.checkentry = secmark_tg_check, .checkentry = secmark_tg_check,
.destroy = secmark_tg_destroy,
.target = secmark_tg, .target = secmark_tg,
.targetsize = sizeof(struct xt_secmark_target_info), .targetsize = sizeof(struct xt_secmark_target_info),
.table = "mangle", .table = "mangle",
...@@ -124,6 +134,7 @@ static struct xt_target secmark_tg_reg[] __read_mostly = { ...@@ -124,6 +134,7 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
.name = "SECMARK", .name = "SECMARK",
.family = AF_INET6, .family = AF_INET6,
.checkentry = secmark_tg_check, .checkentry = secmark_tg_check,
.destroy = secmark_tg_destroy,
.target = secmark_tg, .target = secmark_tg,
.targetsize = sizeof(struct xt_secmark_target_info), .targetsize = sizeof(struct xt_secmark_target_info),
.table = "mangle", .table = "mangle",
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/netlabel.h> #include <net/netlabel.h>
#include <net/cipso_ipv4.h> #include <net/cipso_ipv4.h>
#include <asm/atomic.h>
#include "netlabel_user.h" #include "netlabel_user.h"
#include "netlabel_cipso_v4.h" #include "netlabel_cipso_v4.h"
...@@ -421,7 +422,7 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info) ...@@ -421,7 +422,7 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
break; break;
} }
if (ret_val == 0) if (ret_val == 0)
netlbl_mgmt_protocount_inc(); atomic_inc(&netlabel_mgmt_protocount);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD, audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
&audit_info); &audit_info);
...@@ -698,7 +699,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) ...@@ -698,7 +699,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
&audit_info, &audit_info,
netlbl_cipsov4_doi_free); netlbl_cipsov4_doi_free);
if (ret_val == 0) if (ret_val == 0)
netlbl_mgmt_protocount_dec(); atomic_dec(&netlabel_mgmt_protocount);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL, audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
&audit_info); &audit_info);
......
...@@ -54,9 +54,6 @@ struct netlbl_domhsh_tbl { ...@@ -54,9 +54,6 @@ struct netlbl_domhsh_tbl {
* hash table should be okay */ * hash table should be okay */
static DEFINE_SPINLOCK(netlbl_domhsh_lock); static DEFINE_SPINLOCK(netlbl_domhsh_lock);
static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL; static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
/* Default domain mapping */
static DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
static struct netlbl_dom_map *netlbl_domhsh_def = NULL; static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
/* /*
...@@ -109,17 +106,14 @@ static u32 netlbl_domhsh_hash(const char *key) ...@@ -109,17 +106,14 @@ static u32 netlbl_domhsh_hash(const char *key)
/** /**
* netlbl_domhsh_search - Search for a domain entry * netlbl_domhsh_search - Search for a domain entry
* @domain: the domain * @domain: the domain
* @def: return default if no match is found
* *
* Description: * Description:
* Searches the domain hash table and returns a pointer to the hash table * Searches the domain hash table and returns a pointer to the hash table
* entry if found, otherwise NULL is returned. If @def is non-zero and a * entry if found, otherwise NULL is returned. The caller is responsibile for
* match is not found in the domain hash table the default mapping is returned * the rcu hash table locks (i.e. the caller much call rcu_read_[un]lock()).
* if it exists. The caller is responsibile for the rcu hash table locks
* (i.e. the caller much call rcu_read_[un]lock()).
* *
*/ */
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def) static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
{ {
u32 bkt; u32 bkt;
struct netlbl_dom_map *iter; struct netlbl_dom_map *iter;
...@@ -133,10 +127,31 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def) ...@@ -133,10 +127,31 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def)
return iter; return iter;
} }
if (def != 0) { return NULL;
iter = rcu_dereference(netlbl_domhsh_def); }
if (iter != NULL && iter->valid)
return iter; /**
* netlbl_domhsh_search_def - Search for a domain entry
* @domain: the domain
* @def: return default if no match is found
*
* Description:
* Searches the domain hash table and returns a pointer to the hash table
* entry if an exact match is found, if an exact match is not present in the
* hash table then the default entry is returned if valid otherwise NULL is
* returned. The caller is responsibile for the rcu hash table locks
* (i.e. the caller much call rcu_read_[un]lock()).
*
*/
static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
{
struct netlbl_dom_map *entry;
entry = netlbl_domhsh_search(domain);
if (entry == NULL) {
entry = rcu_dereference(netlbl_domhsh_def);
if (entry != NULL && entry->valid)
return entry;
} }
return NULL; return NULL;
...@@ -221,24 +236,22 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry, ...@@ -221,24 +236,22 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
INIT_RCU_HEAD(&entry->rcu); INIT_RCU_HEAD(&entry->rcu);
rcu_read_lock(); rcu_read_lock();
spin_lock(&netlbl_domhsh_lock);
if (entry->domain != NULL) { if (entry->domain != NULL) {
bkt = netlbl_domhsh_hash(entry->domain); bkt = netlbl_domhsh_hash(entry->domain);
spin_lock(&netlbl_domhsh_lock); if (netlbl_domhsh_search(entry->domain) == NULL)
if (netlbl_domhsh_search(entry->domain, 0) == NULL)
list_add_tail_rcu(&entry->list, list_add_tail_rcu(&entry->list,
&rcu_dereference(netlbl_domhsh)->tbl[bkt]); &rcu_dereference(netlbl_domhsh)->tbl[bkt]);
else else
ret_val = -EEXIST; ret_val = -EEXIST;
spin_unlock(&netlbl_domhsh_lock);
} else { } else {
INIT_LIST_HEAD(&entry->list); INIT_LIST_HEAD(&entry->list);
spin_lock(&netlbl_domhsh_def_lock);
if (rcu_dereference(netlbl_domhsh_def) == NULL) if (rcu_dereference(netlbl_domhsh_def) == NULL)
rcu_assign_pointer(netlbl_domhsh_def, entry); rcu_assign_pointer(netlbl_domhsh_def, entry);
else else
ret_val = -EEXIST; ret_val = -EEXIST;
spin_unlock(&netlbl_domhsh_def_lock);
} }
spin_unlock(&netlbl_domhsh_lock);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info); audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
if (audit_buf != NULL) { if (audit_buf != NULL) {
audit_log_format(audit_buf, audit_log_format(audit_buf,
...@@ -307,7 +320,10 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) ...@@ -307,7 +320,10 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
struct audit_buffer *audit_buf; struct audit_buffer *audit_buf;
rcu_read_lock(); rcu_read_lock();
entry = netlbl_domhsh_search(domain, (domain != NULL ? 0 : 1)); if (domain)
entry = netlbl_domhsh_search(domain);
else
entry = netlbl_domhsh_search_def(domain);
if (entry == NULL) if (entry == NULL)
goto remove_return; goto remove_return;
switch (entry->type) { switch (entry->type) {
...@@ -316,23 +332,16 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info) ...@@ -316,23 +332,16 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
entry->domain); entry->domain);
break; break;
} }
if (entry != rcu_dereference(netlbl_domhsh_def)) { spin_lock(&netlbl_domhsh_lock);
spin_lock(&netlbl_domhsh_lock); if (entry->valid) {
if (entry->valid) { entry->valid = 0;
entry->valid = 0; if (entry != rcu_dereference(netlbl_domhsh_def))
list_del_rcu(&entry->list); list_del_rcu(&entry->list);
ret_val = 0; else
}
spin_unlock(&netlbl_domhsh_lock);
} else {
spin_lock(&netlbl_domhsh_def_lock);
if (entry->valid) {
entry->valid = 0;
rcu_assign_pointer(netlbl_domhsh_def, NULL); rcu_assign_pointer(netlbl_domhsh_def, NULL);
ret_val = 0; ret_val = 0;
}
spin_unlock(&netlbl_domhsh_def_lock);
} }
spin_unlock(&netlbl_domhsh_lock);
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info); audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
if (audit_buf != NULL) { if (audit_buf != NULL) {
...@@ -377,7 +386,7 @@ int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info) ...@@ -377,7 +386,7 @@ int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
*/ */
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain) struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
{ {
return netlbl_domhsh_search(domain, 1); return netlbl_domhsh_search_def(domain);
} }
/** /**
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <net/netlabel.h> #include <net/netlabel.h>
#include <net/cipso_ipv4.h> #include <net/cipso_ipv4.h>
#include <asm/bug.h> #include <asm/bug.h>
#include <asm/atomic.h>
#include "netlabel_domainhash.h" #include "netlabel_domainhash.h"
#include "netlabel_unlabeled.h" #include "netlabel_unlabeled.h"
...@@ -262,7 +263,7 @@ int netlbl_enabled(void) ...@@ -262,7 +263,7 @@ int netlbl_enabled(void)
/* At some point we probably want to expose this mechanism to the user /* At some point we probably want to expose this mechanism to the user
* as well so that admins can toggle NetLabel regardless of the * as well so that admins can toggle NetLabel regardless of the
* configuration */ * configuration */
return (netlbl_mgmt_protocount_value() > 0 ? 1 : 0); return (atomic_read(&netlabel_mgmt_protocount) > 0);
} }
/** /**
...@@ -311,7 +312,7 @@ int netlbl_sock_setattr(struct sock *sk, ...@@ -311,7 +312,7 @@ int netlbl_sock_setattr(struct sock *sk,
* @secattr: the security attributes * @secattr: the security attributes
* *
* Description: * Description:
* Examines the given sock to see any NetLabel style labeling has been * Examines the given sock to see if any NetLabel style labeling has been
* applied to the sock, if so it parses the socket label and returns the * applied to the sock, if so it parses the socket label and returns the
* security attributes in @secattr. Returns zero on success, negative values * security attributes in @secattr. Returns zero on success, negative values
* on failure. * on failure.
...@@ -319,18 +320,13 @@ int netlbl_sock_setattr(struct sock *sk, ...@@ -319,18 +320,13 @@ int netlbl_sock_setattr(struct sock *sk,
*/ */
int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
{ {
int ret_val; return cipso_v4_sock_getattr(sk, secattr);
ret_val = cipso_v4_sock_getattr(sk, secattr);
if (ret_val == 0)
return 0;
return netlbl_unlabel_getattr(secattr);
} }
/** /**
* netlbl_skbuff_getattr - Determine the security attributes of a packet * netlbl_skbuff_getattr - Determine the security attributes of a packet
* @skb: the packet * @skb: the packet
* @family: protocol family
* @secattr: the security attributes * @secattr: the security attributes
* *
* Description: * Description:
...@@ -341,13 +337,14 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr) ...@@ -341,13 +337,14 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
* *
*/ */
int netlbl_skbuff_getattr(const struct sk_buff *skb, int netlbl_skbuff_getattr(const struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
if (CIPSO_V4_OPTEXIST(skb) && if (CIPSO_V4_OPTEXIST(skb) &&
cipso_v4_skbuff_getattr(skb, secattr) == 0) cipso_v4_skbuff_getattr(skb, secattr) == 0)
return 0; return 0;
return netlbl_unlabel_getattr(secattr); return netlbl_unlabel_getattr(skb, family, secattr);
} }
/** /**
...@@ -431,6 +428,10 @@ static int __init netlbl_init(void) ...@@ -431,6 +428,10 @@ static int __init netlbl_init(void)
if (ret_val != 0) if (ret_val != 0)
goto init_failure; goto init_failure;
ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
if (ret_val != 0)
goto init_failure;
ret_val = netlbl_netlink_init(); ret_val = netlbl_netlink_init();
if (ret_val != 0) if (ret_val != 0)
goto init_failure; goto init_failure;
......
...@@ -37,14 +37,14 @@ ...@@ -37,14 +37,14 @@
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/netlabel.h> #include <net/netlabel.h>
#include <net/cipso_ipv4.h> #include <net/cipso_ipv4.h>
#include <asm/atomic.h>
#include "netlabel_domainhash.h" #include "netlabel_domainhash.h"
#include "netlabel_user.h" #include "netlabel_user.h"
#include "netlabel_mgmt.h" #include "netlabel_mgmt.h"
/* NetLabel configured protocol count */ /* NetLabel configured protocol counter */
static DEFINE_SPINLOCK(netlabel_mgmt_protocount_lock); atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
static u32 netlabel_mgmt_protocount = 0;
/* Argument struct for netlbl_domhsh_walk() */ /* Argument struct for netlbl_domhsh_walk() */
struct netlbl_domhsh_walk_arg { struct netlbl_domhsh_walk_arg {
...@@ -70,63 +70,6 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = { ...@@ -70,63 +70,6 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 }, [NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
}; };
/*
* NetLabel Misc Management Functions
*/
/**
* netlbl_mgmt_protocount_inc - Increment the configured labeled protocol count
*
* Description:
* Increment the number of labeled protocol configurations in the current
* NetLabel configuration. Keep track of this for use in determining if
* NetLabel label enforcement should be active/enabled or not in the LSM.
*
*/
void netlbl_mgmt_protocount_inc(void)
{
spin_lock(&netlabel_mgmt_protocount_lock);
netlabel_mgmt_protocount++;
spin_unlock(&netlabel_mgmt_protocount_lock);
}
/**
* netlbl_mgmt_protocount_dec - Decrement the configured labeled protocol count
*
* Description:
* Decrement the number of labeled protocol configurations in the current
* NetLabel configuration. Keep track of this for use in determining if
* NetLabel label enforcement should be active/enabled or not in the LSM.
*
*/
void netlbl_mgmt_protocount_dec(void)
{
spin_lock(&netlabel_mgmt_protocount_lock);
if (netlabel_mgmt_protocount > 0)
netlabel_mgmt_protocount--;
spin_unlock(&netlabel_mgmt_protocount_lock);
}
/**
* netlbl_mgmt_protocount_value - Return the number of configured protocols
*
* Description:
* Return the number of labeled protocols in the current NetLabel
* configuration. This value is useful in determining if NetLabel label
* enforcement should be active/enabled or not in the LSM.
*
*/
u32 netlbl_mgmt_protocount_value(void)
{
u32 val;
rcu_read_lock();
val = netlabel_mgmt_protocount;
rcu_read_unlock();
return val;
}
/* /*
* NetLabel Command Handlers * NetLabel Command Handlers
*/ */
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define _NETLABEL_MGMT_H #define _NETLABEL_MGMT_H
#include <net/netlabel.h> #include <net/netlabel.h>
#include <asm/atomic.h>
/* /*
* The following NetLabel payloads are supported by the management interface. * The following NetLabel payloads are supported by the management interface.
...@@ -168,9 +169,7 @@ enum { ...@@ -168,9 +169,7 @@ enum {
/* NetLabel protocol functions */ /* NetLabel protocol functions */
int netlbl_mgmt_genl_init(void); int netlbl_mgmt_genl_init(void);
/* NetLabel misc management functions */ /* NetLabel configured protocol reference counter */
void netlbl_mgmt_protocount_inc(void); extern atomic_t netlabel_mgmt_protocount;
void netlbl_mgmt_protocount_dec(void);
u32 netlbl_mgmt_protocount_value(void);
#endif #endif
This diff is collapsed.
...@@ -36,6 +36,116 @@ ...@@ -36,6 +36,116 @@
/* /*
* The following NetLabel payloads are supported by the Unlabeled subsystem. * The following NetLabel payloads are supported by the Unlabeled subsystem.
* *
* o STATICADD
* This message is sent from an application to add a new static label for
* incoming unlabeled connections.
*
* Required attributes:
*
* NLBL_UNLABEL_A_IFACE
* NLBL_UNLABEL_A_SECCTX
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV4ADDR
* NLBL_UNLABEL_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV6ADDR
* NLBL_UNLABEL_A_IPV6MASK
*
* o STATICREMOVE
* This message is sent from an application to remove an existing static
* label for incoming unlabeled connections.
*
* Required attributes:
*
* NLBL_UNLABEL_A_IFACE
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV4ADDR
* NLBL_UNLABEL_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV6ADDR
* NLBL_UNLABEL_A_IPV6MASK
*
* o STATICLIST
* This message can be sent either from an application or by the kernel in
* response to an application generated STATICLIST message. When sent by an
* application there is no payload and the NLM_F_DUMP flag should be set.
* The kernel should response with a series of the following messages.
*
* Required attributes:
*
* NLBL_UNLABEL_A_IFACE
* NLBL_UNLABEL_A_SECCTX
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV4ADDR
* NLBL_UNLABEL_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV6ADDR
* NLBL_UNLABEL_A_IPV6MASK
*
* o STATICADDDEF
* This message is sent from an application to set the default static
* label for incoming unlabeled connections.
*
* Required attribute:
*
* NLBL_UNLABEL_A_SECCTX
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV4ADDR
* NLBL_UNLABEL_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV6ADDR
* NLBL_UNLABEL_A_IPV6MASK
*
* o STATICREMOVEDEF
* This message is sent from an application to remove the existing default
* static label for incoming unlabeled connections.
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV4ADDR
* NLBL_UNLABEL_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV6ADDR
* NLBL_UNLABEL_A_IPV6MASK
*
* o STATICLISTDEF
* This message can be sent either from an application or by the kernel in
* response to an application generated STATICLISTDEF message. When sent by
* an application there is no payload and the NLM_F_DUMP flag should be set.
* The kernel should response with the following message.
*
* Required attribute:
*
* NLBL_UNLABEL_A_SECCTX
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV4ADDR
* NLBL_UNLABEL_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_UNLABEL_A_IPV6ADDR
* NLBL_UNLABEL_A_IPV6MASK
*
* o ACCEPT * o ACCEPT
* This message is sent from an application to specify if the kernel should * This message is sent from an application to specify if the kernel should
* allow unlabled packets to pass if they do not match any of the static * allow unlabled packets to pass if they do not match any of the static
...@@ -62,6 +172,12 @@ enum { ...@@ -62,6 +172,12 @@ enum {
NLBL_UNLABEL_C_UNSPEC, NLBL_UNLABEL_C_UNSPEC,
NLBL_UNLABEL_C_ACCEPT, NLBL_UNLABEL_C_ACCEPT,
NLBL_UNLABEL_C_LIST, NLBL_UNLABEL_C_LIST,
NLBL_UNLABEL_C_STATICADD,
NLBL_UNLABEL_C_STATICREMOVE,
NLBL_UNLABEL_C_STATICLIST,
NLBL_UNLABEL_C_STATICADDDEF,
NLBL_UNLABEL_C_STATICREMOVEDEF,
NLBL_UNLABEL_C_STATICLISTDEF,
__NLBL_UNLABEL_C_MAX, __NLBL_UNLABEL_C_MAX,
}; };
#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1) #define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
...@@ -73,6 +189,24 @@ enum { ...@@ -73,6 +189,24 @@ enum {
/* (NLA_U8) /* (NLA_U8)
* if true then unlabeled packets are allowed to pass, else unlabeled * if true then unlabeled packets are allowed to pass, else unlabeled
* packets are rejected */ * packets are rejected */
NLBL_UNLABEL_A_IPV6ADDR,
/* (NLA_BINARY, struct in6_addr)
* an IPv6 address */
NLBL_UNLABEL_A_IPV6MASK,
/* (NLA_BINARY, struct in6_addr)
* an IPv6 address mask */
NLBL_UNLABEL_A_IPV4ADDR,
/* (NLA_BINARY, struct in_addr)
* an IPv4 address */
NLBL_UNLABEL_A_IPV4MASK,
/* (NLA_BINARY, struct in_addr)
* and IPv4 address mask */
NLBL_UNLABEL_A_IFACE,
/* (NLA_NULL_STRING)
* network interface */
NLBL_UNLABEL_A_SECCTX,
/* (NLA_BINARY)
* a LSM specific security context */
__NLBL_UNLABEL_A_MAX, __NLBL_UNLABEL_A_MAX,
}; };
#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1) #define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
...@@ -80,8 +214,17 @@ enum { ...@@ -80,8 +214,17 @@ enum {
/* NetLabel protocol functions */ /* NetLabel protocol functions */
int netlbl_unlabel_genl_init(void); int netlbl_unlabel_genl_init(void);
/* Unlabeled connection hash table size */
/* XXX - currently this number is an uneducated guess */
#define NETLBL_UNLHSH_BITSIZE 7
/* General Unlabeled init function */
int netlbl_unlabel_init(u32 size);
/* Process Unlabeled incoming network packets */ /* Process Unlabeled incoming network packets */
int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr); int netlbl_unlabel_getattr(const struct sk_buff *skb,
u16 family,
struct netlbl_lsm_secattr *secattr);
/* Set the default configuration to allow Unlabeled packets */ /* Set the default configuration to allow Unlabeled packets */
int netlbl_unlabel_defconf(void); int netlbl_unlabel_defconf(void);
......
...@@ -76,6 +76,7 @@ config SECURITY_NETWORK_XFRM ...@@ -76,6 +76,7 @@ config SECURITY_NETWORK_XFRM
config SECURITY_CAPABILITIES config SECURITY_CAPABILITIES
bool "Default Linux Capabilities" bool "Default Linux Capabilities"
depends on SECURITY depends on SECURITY
default y
help help
This enables the "default" Linux capabilities functionality. This enables the "default" Linux capabilities functionality.
If you are unsure how to answer this question, answer Y. If you are unsure how to answer this question, answer Y.
......
...@@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX ...@@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
int "NSA SELinux maximum supported policy format version value" int "NSA SELinux maximum supported policy format version value"
depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
range 15 21 range 15 22
default 19 default 19
help help
This option sets the value for the maximum policy format version This option sets the value for the maximum policy format version
......
...@@ -4,7 +4,14 @@ ...@@ -4,7 +4,14 @@
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/ obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o exports.o selinux-y := avc.o \
hooks.o \
selinuxfs.o \
netlink.o \
nlmsgtab.o \
netif.o \
netnode.o \
exports.o
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
......
...@@ -661,9 +661,18 @@ void avc_audit(u32 ssid, u32 tsid, ...@@ -661,9 +661,18 @@ void avc_audit(u32 ssid, u32 tsid,
"daddr", "dest"); "daddr", "dest");
break; break;
} }
if (a->u.net.netif) if (a->u.net.netif > 0) {
audit_log_format(ab, " netif=%s", struct net_device *dev;
a->u.net.netif);
/* NOTE: we always use init's namespace */
dev = dev_get_by_index(&init_net,
a->u.net.netif);
if (dev) {
audit_log_format(ab, " netif=%s",
dev->name);
dev_put(dev);
}
}
break; break;
} }
} }
......
...@@ -17,10 +17,14 @@ ...@@ -17,10 +17,14 @@
#include <linux/selinux.h> #include <linux/selinux.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ipc.h> #include <linux/ipc.h>
#include <asm/atomic.h>
#include "security.h" #include "security.h"
#include "objsec.h" #include "objsec.h"
/* SECMARK reference count */
extern atomic_t selinux_secmark_refcount;
int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen) int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
{ {
if (selinux_enabled) if (selinux_enabled)
...@@ -74,7 +78,7 @@ int selinux_string_to_sid(char *str, u32 *sid) ...@@ -74,7 +78,7 @@ int selinux_string_to_sid(char *str, u32 *sid)
} }
EXPORT_SYMBOL_GPL(selinux_string_to_sid); EXPORT_SYMBOL_GPL(selinux_string_to_sid);
int selinux_relabel_packet_permission(u32 sid) int selinux_secmark_relabel_packet_permission(u32 sid)
{ {
if (selinux_enabled) { if (selinux_enabled) {
struct task_security_struct *tsec = current->security; struct task_security_struct *tsec = current->security;
...@@ -84,4 +88,16 @@ int selinux_relabel_packet_permission(u32 sid) ...@@ -84,4 +88,16 @@ int selinux_relabel_packet_permission(u32 sid)
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(selinux_relabel_packet_permission); EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission);
void selinux_secmark_refcount_inc(void)
{
atomic_inc(&selinux_secmark_refcount);
}
EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc);
void selinux_secmark_refcount_dec(void)
{
atomic_dec(&selinux_secmark_refcount);
}
EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec);
This diff is collapsed.
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest") S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest")
S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv") S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv")
S_(SECCLASS_NODE, NODE__DCCP_SEND, "dccp_send") S_(SECCLASS_NODE, NODE__DCCP_SEND, "dccp_send")
S_(SECCLASS_NODE, NODE__RECVFROM, "recvfrom")
S_(SECCLASS_NODE, NODE__SENDTO, "sendto")
S_(SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv") S_(SECCLASS_NETIF, NETIF__TCP_RECV, "tcp_recv")
S_(SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send") S_(SECCLASS_NETIF, NETIF__TCP_SEND, "tcp_send")
S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv") S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv")
...@@ -45,6 +47,8 @@ ...@@ -45,6 +47,8 @@
S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send") S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send")
S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv") S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv")
S_(SECCLASS_NETIF, NETIF__DCCP_SEND, "dccp_send") S_(SECCLASS_NETIF, NETIF__DCCP_SEND, "dccp_send")
S_(SECCLASS_NETIF, NETIF__INGRESS, "ingress")
S_(SECCLASS_NETIF, NETIF__EGRESS, "egress")
S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto") S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__CONNECTTO, "connectto")
S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn") S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__NEWCONN, "newconn")
S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom") S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom")
...@@ -149,6 +153,10 @@ ...@@ -149,6 +153,10 @@
S_(SECCLASS_PACKET, PACKET__SEND, "send") S_(SECCLASS_PACKET, PACKET__SEND, "send")
S_(SECCLASS_PACKET, PACKET__RECV, "recv") S_(SECCLASS_PACKET, PACKET__RECV, "recv")
S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto") S_(SECCLASS_PACKET, PACKET__RELABELTO, "relabelto")
S_(SECCLASS_PACKET, PACKET__FLOW_IN, "flow_in")
S_(SECCLASS_PACKET, PACKET__FLOW_OUT, "flow_out")
S_(SECCLASS_PACKET, PACKET__FORWARD_IN, "forward_in")
S_(SECCLASS_PACKET, PACKET__FORWARD_OUT, "forward_out")
S_(SECCLASS_KEY, KEY__VIEW, "view") S_(SECCLASS_KEY, KEY__VIEW, "view")
S_(SECCLASS_KEY, KEY__READ, "read") S_(SECCLASS_KEY, KEY__READ, "read")
S_(SECCLASS_KEY, KEY__WRITE, "write") S_(SECCLASS_KEY, KEY__WRITE, "write")
...@@ -159,3 +167,4 @@ ...@@ -159,3 +167,4 @@
S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind") S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind")
S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect") S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero") S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
S_(SECCLASS_PEER, PEER__RECV, "recv")
...@@ -292,6 +292,8 @@ ...@@ -292,6 +292,8 @@
#define NODE__ENFORCE_DEST 0x00000040UL #define NODE__ENFORCE_DEST 0x00000040UL
#define NODE__DCCP_RECV 0x00000080UL #define NODE__DCCP_RECV 0x00000080UL
#define NODE__DCCP_SEND 0x00000100UL #define NODE__DCCP_SEND 0x00000100UL
#define NODE__RECVFROM 0x00000200UL
#define NODE__SENDTO 0x00000400UL
#define NETIF__TCP_RECV 0x00000001UL #define NETIF__TCP_RECV 0x00000001UL
#define NETIF__TCP_SEND 0x00000002UL #define NETIF__TCP_SEND 0x00000002UL
#define NETIF__UDP_RECV 0x00000004UL #define NETIF__UDP_RECV 0x00000004UL
...@@ -300,6 +302,8 @@ ...@@ -300,6 +302,8 @@
#define NETIF__RAWIP_SEND 0x00000020UL #define NETIF__RAWIP_SEND 0x00000020UL
#define NETIF__DCCP_RECV 0x00000040UL #define NETIF__DCCP_RECV 0x00000040UL
#define NETIF__DCCP_SEND 0x00000080UL #define NETIF__DCCP_SEND 0x00000080UL
#define NETIF__INGRESS 0x00000100UL
#define NETIF__EGRESS 0x00000200UL
#define NETLINK_SOCKET__IOCTL 0x00000001UL #define NETLINK_SOCKET__IOCTL 0x00000001UL
#define NETLINK_SOCKET__READ 0x00000002UL #define NETLINK_SOCKET__READ 0x00000002UL
#define NETLINK_SOCKET__WRITE 0x00000004UL #define NETLINK_SOCKET__WRITE 0x00000004UL
...@@ -792,6 +796,10 @@ ...@@ -792,6 +796,10 @@
#define PACKET__SEND 0x00000001UL #define PACKET__SEND 0x00000001UL
#define PACKET__RECV 0x00000002UL #define PACKET__RECV 0x00000002UL
#define PACKET__RELABELTO 0x00000004UL #define PACKET__RELABELTO 0x00000004UL
#define PACKET__FLOW_IN 0x00000008UL
#define PACKET__FLOW_OUT 0x00000010UL
#define PACKET__FORWARD_IN 0x00000020UL
#define PACKET__FORWARD_OUT 0x00000040UL
#define KEY__VIEW 0x00000001UL #define KEY__VIEW 0x00000001UL
#define KEY__READ 0x00000002UL #define KEY__READ 0x00000002UL
#define KEY__WRITE 0x00000004UL #define KEY__WRITE 0x00000004UL
...@@ -824,3 +832,4 @@ ...@@ -824,3 +832,4 @@
#define DCCP_SOCKET__NODE_BIND 0x00400000UL #define DCCP_SOCKET__NODE_BIND 0x00400000UL
#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL #define DCCP_SOCKET__NAME_CONNECT 0x00800000UL
#define MEMPROTECT__MMAP_ZERO 0x00000001UL #define MEMPROTECT__MMAP_ZERO 0x00000001UL
#define PEER__RECV 0x00000001UL
...@@ -51,7 +51,7 @@ struct avc_audit_data { ...@@ -51,7 +51,7 @@ struct avc_audit_data {
struct inode *inode; struct inode *inode;
} fs; } fs;
struct { struct {
char *netif; int netif;
struct sock *sk; struct sock *sk;
u16 family; u16 family;
__be16 dport; __be16 dport;
......
...@@ -64,3 +64,10 @@ ...@@ -64,3 +64,10 @@
S_(NULL) S_(NULL)
S_("dccp_socket") S_("dccp_socket")
S_("memprotect") S_("memprotect")
S_(NULL)
S_(NULL)
S_(NULL)
S_(NULL)
S_(NULL)
S_(NULL)
S_("peer")
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#define SECCLASS_KEY 58 #define SECCLASS_KEY 58
#define SECCLASS_DCCP_SOCKET 60 #define SECCLASS_DCCP_SOCKET 60
#define SECCLASS_MEMPROTECT 61 #define SECCLASS_MEMPROTECT 61
#define SECCLASS_PEER 68
/* /*
* Security identifier indices for initial entities * Security identifier indices for initial entities
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* Author: James Morris <jmorris@redhat.com> * Author: James Morris <jmorris@redhat.com>
* *
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
* Paul Moore, <paul.moore@hp.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, * it under the terms of the GNU General Public License version 2,
...@@ -15,7 +17,7 @@ ...@@ -15,7 +17,7 @@
#ifndef _SELINUX_NETIF_H_ #ifndef _SELINUX_NETIF_H_
#define _SELINUX_NETIF_H_ #define _SELINUX_NETIF_H_
int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid); int sel_netif_sid(int ifindex, u32 *sid);
#endif /* _SELINUX_NETIF_H_ */ #endif /* _SELINUX_NETIF_H_ */
...@@ -46,13 +46,17 @@ void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec, ...@@ -46,13 +46,17 @@ void selinux_netlbl_sk_security_init(struct sk_security_struct *ssec,
void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
struct sk_security_struct *newssec); struct sk_security_struct *newssec);
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid); int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
u32 *type,
u32 *sid);
void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock); void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock);
int selinux_netlbl_socket_post_create(struct socket *sock); int selinux_netlbl_socket_post_create(struct socket *sock);
int selinux_netlbl_inode_permission(struct inode *inode, int mask); int selinux_netlbl_inode_permission(struct inode *inode, int mask);
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct sk_buff *skb, struct sk_buff *skb,
u16 family,
struct avc_audit_data *ad); struct avc_audit_data *ad);
int selinux_netlbl_socket_setsockopt(struct socket *sock, int selinux_netlbl_socket_setsockopt(struct socket *sock,
int level, int level,
...@@ -83,9 +87,11 @@ static inline void selinux_netlbl_sk_security_clone( ...@@ -83,9 +87,11 @@ static inline void selinux_netlbl_sk_security_clone(
} }
static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u32 base_sid, u16 family,
u32 *type,
u32 *sid) u32 *sid)
{ {
*type = NETLBL_NLTYPE_NONE;
*sid = SECSID_NULL; *sid = SECSID_NULL;
return 0; return 0;
} }
...@@ -106,6 +112,7 @@ static inline int selinux_netlbl_inode_permission(struct inode *inode, ...@@ -106,6 +112,7 @@ static inline int selinux_netlbl_inode_permission(struct inode *inode,
} }
static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, static inline int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct sk_buff *skb, struct sk_buff *skb,
u16 family,
struct avc_audit_data *ad) struct avc_audit_data *ad)
{ {
return 0; return 0;
......
/*
* Network node table
*
* SELinux must keep a mapping of network nodes to labels/SIDs. This
* mapping is maintained as part of the normal policy but a fast cache is
* needed to reduce the lookup overhead since most of these queries happen on
* a per-packet basis.
*
* Author: Paul Moore <paul.moore@hp.com>
*
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _SELINUX_NETNODE_H
#define _SELINUX_NETNODE_H
int sel_netnode_sid(void *addr, u16 family, u32 *sid);
#endif
...@@ -96,17 +96,25 @@ struct bprm_security_struct { ...@@ -96,17 +96,25 @@ struct bprm_security_struct {
}; };
struct netif_security_struct { struct netif_security_struct {
struct net_device *dev; /* back pointer */ int ifindex; /* device index */
u32 if_sid; /* SID for this interface */ u32 sid; /* SID for this interface */
u32 msg_sid; /* default SID for messages received on this interface */ };
struct netnode_security_struct {
union {
__be32 ipv4; /* IPv4 node address */
struct in6_addr ipv6; /* IPv6 node address */
} addr;
u32 sid; /* SID for this node */
u16 family; /* address family */
}; };
struct sk_security_struct { struct sk_security_struct {
struct sock *sk; /* back pointer to sk object */ struct sock *sk; /* back pointer to sk object */
u32 sid; /* SID of this object */ u32 sid; /* SID of this object */
u32 peer_sid; /* SID of peer */ u32 peer_sid; /* SID of peer */
#ifdef CONFIG_NETLABEL
u16 sclass; /* sock security class */ u16 sclass; /* sock security class */
#ifdef CONFIG_NETLABEL
enum { /* NetLabel state */ enum { /* NetLabel state */
NLBL_UNSET = 0, NLBL_UNSET = 0,
NLBL_REQUIRE, NLBL_REQUIRE,
......
...@@ -25,13 +25,14 @@ ...@@ -25,13 +25,14 @@
#define POLICYDB_VERSION_MLS 19 #define POLICYDB_VERSION_MLS 19
#define POLICYDB_VERSION_AVTAB 20 #define POLICYDB_VERSION_AVTAB 20
#define POLICYDB_VERSION_RANGETRANS 21 #define POLICYDB_VERSION_RANGETRANS 21
#define POLICYDB_VERSION_POLCAP 22
/* Range of policy versions we understand*/ /* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
#else #else
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_RANGETRANS #define POLICYDB_VERSION_MAX POLICYDB_VERSION_POLCAP
#endif #endif
struct netlbl_lsm_secattr; struct netlbl_lsm_secattr;
...@@ -39,8 +40,19 @@ struct netlbl_lsm_secattr; ...@@ -39,8 +40,19 @@ struct netlbl_lsm_secattr;
extern int selinux_enabled; extern int selinux_enabled;
extern int selinux_mls_enabled; extern int selinux_mls_enabled;
/* Policy capabilities */
enum {
POLICYDB_CAPABILITY_NETPEER,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
extern int selinux_policycap_netpeer;
int security_load_policy(void * data, size_t len); int security_load_policy(void * data, size_t len);
int security_policycap_supported(unsigned int req_cap);
#define SEL_VEC_MAX 32 #define SEL_VEC_MAX 32
struct av_decision { struct av_decision {
u32 allowed; u32 allowed;
...@@ -77,8 +89,7 @@ int security_get_user_sids(u32 callsid, char *username, ...@@ -77,8 +89,7 @@ int security_get_user_sids(u32 callsid, char *username,
int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port, int security_port_sid(u16 domain, u16 type, u8 protocol, u16 port,
u32 *out_sid); u32 *out_sid);
int security_netif_sid(char *name, u32 *if_sid, int security_netif_sid(char *name, u32 *if_sid);
u32 *msg_sid);
int security_node_sid(u16 domain, void *addr, u32 addrlen, int security_node_sid(u16 domain, void *addr, u32 addrlen,
u32 *out_sid); u32 *out_sid);
...@@ -88,10 +99,15 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -88,10 +99,15 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
u32 xfrm_sid,
u32 *peer_sid);
int security_get_classes(char ***classes, int *nclasses); int security_get_classes(char ***classes, int *nclasses);
int security_get_permissions(char *class, char ***perms, int *nperms); int security_get_permissions(char *class, char ***perms, int *nperms);
int security_get_reject_unknown(void); int security_get_reject_unknown(void);
int security_get_allow_unknown(void); int security_get_allow_unknown(void);
int security_get_policycaps(int *len, int **values);
#define SECURITY_FS_USE_XATTR 1 /* use xattr */ #define SECURITY_FS_USE_XATTR 1 /* use xattr */
#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
...@@ -108,7 +124,6 @@ int security_genfs_sid(const char *fstype, char *name, u16 sclass, ...@@ -108,7 +124,6 @@ int security_genfs_sid(const char *fstype, char *name, u16 sclass,
#ifdef CONFIG_NETLABEL #ifdef CONFIG_NETLABEL
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
u32 base_sid,
u32 *sid); u32 *sid);
int security_netlbl_sid_to_secattr(u32 sid, int security_netlbl_sid_to_secattr(u32 sid,
...@@ -116,7 +131,6 @@ int security_netlbl_sid_to_secattr(u32 sid, ...@@ -116,7 +131,6 @@ int security_netlbl_sid_to_secattr(u32 sid,
#else #else
static inline int security_netlbl_secattr_to_sid( static inline int security_netlbl_secattr_to_sid(
struct netlbl_lsm_secattr *secattr, struct netlbl_lsm_secattr *secattr,
u32 base_sid,
u32 *sid) u32 *sid)
{ {
return -EIDRM; return -EIDRM;
......
...@@ -32,6 +32,13 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk) ...@@ -32,6 +32,13 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk)
} }
#ifdef CONFIG_SECURITY_NETWORK_XFRM #ifdef CONFIG_SECURITY_NETWORK_XFRM
extern atomic_t selinux_xfrm_refcount;
static inline int selinux_xfrm_enabled(void)
{
return (atomic_read(&selinux_xfrm_refcount) > 0);
}
int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
struct avc_audit_data *ad); struct avc_audit_data *ad);
int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
...@@ -43,6 +50,11 @@ static inline void selinux_xfrm_notify_policyload(void) ...@@ -43,6 +50,11 @@ static inline void selinux_xfrm_notify_policyload(void)
atomic_inc(&flow_cache_genid); atomic_inc(&flow_cache_genid);
} }
#else #else
static inline int selinux_xfrm_enabled(void)
{
return 0;
}
static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
struct avc_audit_data *ad) struct avc_audit_data *ad)
{ {
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
* Author: James Morris <jmorris@redhat.com> * Author: James Morris <jmorris@redhat.com>
* *
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
* Paul Moore <paul.moore@hp.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, * it under the terms of the GNU General Public License version 2,
...@@ -29,14 +31,6 @@ ...@@ -29,14 +31,6 @@
#define SEL_NETIF_HASH_SIZE 64 #define SEL_NETIF_HASH_SIZE 64
#define SEL_NETIF_HASH_MAX 1024 #define SEL_NETIF_HASH_MAX 1024
#undef DEBUG
#ifdef DEBUG
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
struct sel_netif struct sel_netif
{ {
struct list_head list; struct list_head list;
...@@ -49,174 +43,226 @@ static LIST_HEAD(sel_netif_list); ...@@ -49,174 +43,226 @@ static LIST_HEAD(sel_netif_list);
static DEFINE_SPINLOCK(sel_netif_lock); static DEFINE_SPINLOCK(sel_netif_lock);
static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE]; static struct list_head sel_netif_hash[SEL_NETIF_HASH_SIZE];
static inline u32 sel_netif_hasfn(struct net_device *dev) /**
* sel_netif_hashfn - Hashing function for the interface table
* @ifindex: the network interface
*
* Description:
* This is the hashing function for the network interface table, it returns the
* bucket number for the given interface.
*
*/
static inline u32 sel_netif_hashfn(int ifindex)
{ {
return (dev->ifindex & (SEL_NETIF_HASH_SIZE - 1)); return (ifindex & (SEL_NETIF_HASH_SIZE - 1));
} }
/* /**
* All of the devices should normally fit in the hash, so we optimize * sel_netif_find - Search for an interface record
* for that case. * @ifindex: the network interface
*
* Description:
* Search the network interface table and return the record matching @ifindex.
* If an entry can not be found in the table return NULL.
*
*/ */
static inline struct sel_netif *sel_netif_find(struct net_device *dev) static inline struct sel_netif *sel_netif_find(int ifindex)
{ {
struct list_head *pos; int idx = sel_netif_hashfn(ifindex);
int idx = sel_netif_hasfn(dev); struct sel_netif *netif;
__list_for_each_rcu(pos, &sel_netif_hash[idx]) { list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
struct sel_netif *netif = list_entry(pos, /* all of the devices should normally fit in the hash, so we
struct sel_netif, list); * optimize for that case */
if (likely(netif->nsec.dev == dev)) if (likely(netif->nsec.ifindex == ifindex))
return netif; return netif;
}
return NULL; return NULL;
} }
/**
* sel_netif_insert - Insert a new interface into the table
* @netif: the new interface record
*
* Description:
* Add a new interface record to the network interface hash table. Returns
* zero on success, negative values on failure.
*
*/
static int sel_netif_insert(struct sel_netif *netif) static int sel_netif_insert(struct sel_netif *netif)
{ {
int idx, ret = 0; int idx;
if (sel_netif_total >= SEL_NETIF_HASH_MAX) { if (sel_netif_total >= SEL_NETIF_HASH_MAX)
ret = -ENOSPC; return -ENOSPC;
goto out;
}
idx = sel_netif_hasfn(netif->nsec.dev); idx = sel_netif_hashfn(netif->nsec.ifindex);
list_add_rcu(&netif->list, &sel_netif_hash[idx]); list_add_rcu(&netif->list, &sel_netif_hash[idx]);
sel_netif_total++; sel_netif_total++;
out:
return ret; return 0;
} }
/**
* sel_netif_free - Frees an interface entry
* @p: the entry's RCU field
*
* Description:
* This function is designed to be used as a callback to the call_rcu()
* function so that memory allocated to a hash table interface entry can be
* released safely.
*
*/
static void sel_netif_free(struct rcu_head *p) static void sel_netif_free(struct rcu_head *p)
{ {
struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head); struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head);
DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
kfree(netif); kfree(netif);
} }
/**
* sel_netif_destroy - Remove an interface record from the table
* @netif: the existing interface record
*
* Description:
* Remove an existing interface record from the network interface table.
*
*/
static void sel_netif_destroy(struct sel_netif *netif) static void sel_netif_destroy(struct sel_netif *netif)
{ {
DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
list_del_rcu(&netif->list); list_del_rcu(&netif->list);
sel_netif_total--; sel_netif_total--;
call_rcu(&netif->rcu_head, sel_netif_free); call_rcu(&netif->rcu_head, sel_netif_free);
} }
static struct sel_netif *sel_netif_lookup(struct net_device *dev) /**
* sel_netif_sid_slow - Lookup the SID of a network interface using the policy
* @ifindex: the network interface
* @sid: interface SID
*
* Description:
* This function determines the SID of a network interface by quering the
* security policy. The result is added to the network interface table to
* speedup future queries. Returns zero on success, negative values on
* failure.
*
*/
static int sel_netif_sid_slow(int ifindex, u32 *sid)
{ {
int ret; int ret;
struct sel_netif *netif, *new; struct sel_netif *netif;
struct netif_security_struct *nsec; struct sel_netif *new = NULL;
struct net_device *dev;
netif = sel_netif_find(dev);
if (likely(netif != NULL)) /* NOTE: we always use init's network namespace since we don't
goto out; * currently support containers */
new = kzalloc(sizeof(*new), GFP_ATOMIC); dev = dev_get_by_index(&init_net, ifindex);
if (!new) { if (unlikely(dev == NULL)) {
netif = ERR_PTR(-ENOMEM); printk(KERN_WARNING
goto out; "SELinux: failure in sel_netif_sid_slow(),"
" invalid network interface (%d)\n", ifindex);
return -ENOENT;
} }
nsec = &new->nsec;
ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid); spin_lock_bh(&sel_netif_lock);
if (ret < 0) { netif = sel_netif_find(ifindex);
kfree(new); if (netif != NULL) {
netif = ERR_PTR(ret); *sid = netif->nsec.sid;
ret = 0;
goto out; goto out;
} }
new = kzalloc(sizeof(*new), GFP_ATOMIC);
nsec->dev = dev; if (new == NULL) {
ret = -ENOMEM;
spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(dev);
if (netif) {
spin_unlock_bh(&sel_netif_lock);
kfree(new);
goto out; goto out;
} }
ret = security_netif_sid(dev->name, &new->nsec.sid);
if (ret != 0)
goto out;
new->nsec.ifindex = ifindex;
ret = sel_netif_insert(new); ret = sel_netif_insert(new);
spin_unlock_bh(&sel_netif_lock); if (ret != 0)
if (ret) {
kfree(new);
netif = ERR_PTR(ret);
goto out; goto out;
} *sid = new->nsec.sid;
netif = new;
DEBUGP("new: ifindex=%u name=%s if_sid=%u msg_sid=%u\n", dev->ifindex, dev->name,
nsec->if_sid, nsec->msg_sid);
out: out:
return netif; spin_unlock_bh(&sel_netif_lock);
} dev_put(dev);
if (unlikely(ret)) {
static void sel_netif_assign_sids(u32 if_sid_in, u32 msg_sid_in, u32 *if_sid_out, u32 *msg_sid_out) printk(KERN_WARNING
{ "SELinux: failure in sel_netif_sid_slow(),"
if (if_sid_out) " unable to determine network interface label (%d)\n",
*if_sid_out = if_sid_in; ifindex);
if (msg_sid_out) kfree(new);
*msg_sid_out = msg_sid_in; }
}
static int sel_netif_sids_slow(struct net_device *dev, u32 *if_sid, u32 *msg_sid)
{
int ret = 0;
u32 tmp_if_sid, tmp_msg_sid;
ret = security_netif_sid(dev->name, &tmp_if_sid, &tmp_msg_sid);
if (!ret)
sel_netif_assign_sids(tmp_if_sid, tmp_msg_sid, if_sid, msg_sid);
return ret; return ret;
} }
int sel_netif_sids(struct net_device *dev, u32 *if_sid, u32 *msg_sid) /**
* sel_netif_sid - Lookup the SID of a network interface
* @ifindex: the network interface
* @sid: interface SID
*
* Description:
* This function determines the SID of a network interface using the fastest
* method possible. First the interface table is queried, but if an entry
* can't be found then the policy is queried and the result is added to the
* table to speedup future queries. Returns zero on success, negative values
* on failure.
*
*/
int sel_netif_sid(int ifindex, u32 *sid)
{ {
int ret = 0;
struct sel_netif *netif; struct sel_netif *netif;
rcu_read_lock(); rcu_read_lock();
netif = sel_netif_lookup(dev); netif = sel_netif_find(ifindex);
if (IS_ERR(netif)) { if (likely(netif != NULL)) {
*sid = netif->nsec.sid;
rcu_read_unlock(); rcu_read_unlock();
ret = sel_netif_sids_slow(dev, if_sid, msg_sid); return 0;
goto out;
} }
sel_netif_assign_sids(netif->nsec.if_sid, netif->nsec.msg_sid, if_sid, msg_sid);
rcu_read_unlock(); rcu_read_unlock();
out:
return ret; return sel_netif_sid_slow(ifindex, sid);
} }
static void sel_netif_kill(struct net_device *dev) /**
* sel_netif_kill - Remove an entry from the network interface table
* @ifindex: the network interface
*
* Description:
* This function removes the entry matching @ifindex from the network interface
* table if it exists.
*
*/
static void sel_netif_kill(int ifindex)
{ {
struct sel_netif *netif; struct sel_netif *netif;
spin_lock_bh(&sel_netif_lock); spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(dev); netif = sel_netif_find(ifindex);
if (netif) if (netif)
sel_netif_destroy(netif); sel_netif_destroy(netif);
spin_unlock_bh(&sel_netif_lock); spin_unlock_bh(&sel_netif_lock);
} }
/**
* sel_netif_flush - Flush the entire network interface table
*
* Description:
* Remove all entries from the network interface table.
*
*/
static void sel_netif_flush(void) static void sel_netif_flush(void)
{ {
int idx; int idx;
struct sel_netif *netif;
spin_lock_bh(&sel_netif_lock); spin_lock_bh(&sel_netif_lock);
for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) { for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++)
struct sel_netif *netif;
list_for_each_entry(netif, &sel_netif_hash[idx], list) list_for_each_entry(netif, &sel_netif_hash[idx], list)
sel_netif_destroy(netif); sel_netif_destroy(netif);
}
spin_unlock_bh(&sel_netif_lock); spin_unlock_bh(&sel_netif_lock);
} }
...@@ -239,7 +285,7 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, ...@@ -239,7 +285,7 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
return NOTIFY_DONE; return NOTIFY_DONE;
if (event == NETDEV_DOWN) if (event == NETDEV_DOWN)
sel_netif_kill(dev); sel_netif_kill(dev->ifindex);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -250,10 +296,10 @@ static struct notifier_block sel_netif_netdev_notifier = { ...@@ -250,10 +296,10 @@ static struct notifier_block sel_netif_netdev_notifier = {
static __init int sel_netif_init(void) static __init int sel_netif_init(void)
{ {
int i, err = 0; int i, err;
if (!selinux_enabled) if (!selinux_enabled)
goto out; return 0;
for (i = 0; i < SEL_NETIF_HASH_SIZE; i++) for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
INIT_LIST_HEAD(&sel_netif_hash[i]); INIT_LIST_HEAD(&sel_netif_hash[i]);
...@@ -265,7 +311,6 @@ static __init int sel_netif_init(void) ...@@ -265,7 +311,6 @@ static __init int sel_netif_init(void)
if (err) if (err)
panic("avc_add_callback() failed, error %d\n", err); panic("avc_add_callback() failed, error %d\n", err);
out:
return err; return err;
} }
......
...@@ -35,6 +35,33 @@ ...@@ -35,6 +35,33 @@
#include "objsec.h" #include "objsec.h"
#include "security.h" #include "security.h"
/**
* selinux_netlbl_sidlookup_cached - Cache a SID lookup
* @skb: the packet
* @secattr: the NetLabel security attributes
* @sid: the SID
*
* Description:
* Query the SELinux security server to lookup the correct SID for the given
* security attributes. If the query is successful, cache the result to speed
* up future lookups. Returns zero on success, negative values on failure.
*
*/
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr,
u32 *sid)
{
int rc;
rc = security_netlbl_secattr_to_sid(secattr, sid);
if (rc == 0 &&
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr->flags & NETLBL_SECATTR_CACHE))
netlbl_cache_add(skb, secattr);
return rc;
}
/** /**
* selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
* @sk: the socket to label * @sk: the socket to label
...@@ -137,14 +164,14 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, ...@@ -137,14 +164,14 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
* lock as other threads could have access to ssec */ * lock as other threads could have access to ssec */
rcu_read_lock(); rcu_read_lock();
selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family); selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
newssec->sclass = ssec->sclass;
rcu_read_unlock(); rcu_read_unlock();
} }
/** /**
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
* @skb: the packet * @skb: the packet
* @base_sid: the SELinux SID to use as a context for MLS only attributes * @family: protocol family
* @type: NetLabel labeling protocol type
* @sid: the SID * @sid: the SID
* *
* Description: * Description:
...@@ -153,7 +180,10 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec, ...@@ -153,7 +180,10 @@ void selinux_netlbl_sk_security_clone(struct sk_security_struct *ssec,
* assign to the packet. Returns zero on success, negative values on failure. * assign to the packet. Returns zero on success, negative values on failure.
* *
*/ */
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid) int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16 family,
u32 *type,
u32 *sid)
{ {
int rc; int rc;
struct netlbl_lsm_secattr secattr; struct netlbl_lsm_secattr secattr;
...@@ -164,15 +194,12 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid) ...@@ -164,15 +194,12 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
} }
netlbl_secattr_init(&secattr); netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, &secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) { if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid); rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
if (rc == 0 && else
(secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr.flags & NETLBL_SECATTR_CACHE))
netlbl_cache_add(skb, &secattr);
} else
*sid = SECSID_NULL; *sid = SECSID_NULL;
*type = secattr.type;
netlbl_secattr_destroy(&secattr); netlbl_secattr_destroy(&secattr);
return rc; return rc;
...@@ -190,13 +217,10 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid) ...@@ -190,13 +217,10 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
*/ */
void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
{ {
struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
struct netlbl_lsm_secattr secattr; struct netlbl_lsm_secattr secattr;
u32 nlbl_peer_sid; u32 nlbl_peer_sid;
sksec->sclass = isec->sclass;
rcu_read_lock(); rcu_read_lock();
if (sksec->nlbl_state != NLBL_REQUIRE) { if (sksec->nlbl_state != NLBL_REQUIRE) {
...@@ -207,9 +231,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock) ...@@ -207,9 +231,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
netlbl_secattr_init(&secattr); netlbl_secattr_init(&secattr);
if (netlbl_sock_getattr(sk, &secattr) == 0 && if (netlbl_sock_getattr(sk, &secattr) == 0 &&
secattr.flags != NETLBL_SECATTR_NONE && secattr.flags != NETLBL_SECATTR_NONE &&
security_netlbl_secattr_to_sid(&secattr, security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
SECINITSID_NETMSG,
&nlbl_peer_sid) == 0)
sksec->peer_sid = nlbl_peer_sid; sksec->peer_sid = nlbl_peer_sid;
netlbl_secattr_destroy(&secattr); netlbl_secattr_destroy(&secattr);
...@@ -234,11 +256,8 @@ int selinux_netlbl_socket_post_create(struct socket *sock) ...@@ -234,11 +256,8 @@ int selinux_netlbl_socket_post_create(struct socket *sock)
{ {
int rc = 0; int rc = 0;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
sksec->sclass = isec->sclass;
rcu_read_lock(); rcu_read_lock();
if (sksec->nlbl_state == NLBL_REQUIRE) if (sksec->nlbl_state == NLBL_REQUIRE)
rc = selinux_netlbl_sock_setsid(sk, sksec->sid); rc = selinux_netlbl_sock_setsid(sk, sksec->sid);
...@@ -292,6 +311,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) ...@@ -292,6 +311,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
* selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
* @sksec: the sock's sk_security_struct * @sksec: the sock's sk_security_struct
* @skb: the packet * @skb: the packet
* @family: protocol family
* @ad: the audit data * @ad: the audit data
* *
* Description: * Description:
...@@ -302,6 +322,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask) ...@@ -302,6 +322,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
*/ */
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct sk_buff *skb, struct sk_buff *skb,
u16 family,
struct avc_audit_data *ad) struct avc_audit_data *ad)
{ {
int rc; int rc;
...@@ -313,16 +334,10 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, ...@@ -313,16 +334,10 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
return 0; return 0;
netlbl_secattr_init(&secattr); netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, &secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr);
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) { if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
rc = security_netlbl_secattr_to_sid(&secattr, rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
SECINITSID_NETMSG, else
&nlbl_sid);
if (rc == 0 &&
(secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr.flags & NETLBL_SECATTR_CACHE))
netlbl_cache_add(skb, &secattr);
} else
nlbl_sid = SECINITSID_UNLABELED; nlbl_sid = SECINITSID_UNLABELED;
netlbl_secattr_destroy(&secattr); netlbl_secattr_destroy(&secattr);
if (rc != 0) if (rc != 0)
......
/*
* Network node table
*
* SELinux must keep a mapping of network nodes to labels/SIDs. This
* mapping is maintained as part of the normal policy but a fast cache is
* needed to reduce the lookup overhead since most of these queries happen on
* a per-packet basis.
*
* Author: Paul Moore <paul.moore@hp.com>
*
* This code is heavily based on the "netif" concept originally developed by
* James Morris <jmorris@redhat.com>
* (see security/selinux/netif.c for more information)
*
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/types.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <asm/bug.h>
#include "objsec.h"
#define SEL_NETNODE_HASH_SIZE 256
#define SEL_NETNODE_HASH_BKT_LIMIT 16
struct sel_netnode {
struct netnode_security_struct nsec;
struct list_head list;
struct rcu_head rcu;
};
/* NOTE: we are using a combined hash table for both IPv4 and IPv6, the reason
* for this is that I suspect most users will not make heavy use of both
* address families at the same time so one table will usually end up wasted,
* if this becomes a problem we can always add a hash table for each address
* family later */
static LIST_HEAD(sel_netnode_list);
static DEFINE_SPINLOCK(sel_netnode_lock);
static struct list_head sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
/**
* sel_netnode_free - Frees a node entry
* @p: the entry's RCU field
*
* Description:
* This function is designed to be used as a callback to the call_rcu()
* function so that memory allocated to a hash table node entry can be
* released safely.
*
*/
static void sel_netnode_free(struct rcu_head *p)
{
struct sel_netnode *node = container_of(p, struct sel_netnode, rcu);
kfree(node);
}
/**
* sel_netnode_hashfn_ipv4 - IPv4 hashing function for the node table
* @addr: IPv4 address
*
* Description:
* This is the IPv4 hashing function for the node interface table, it returns
* the bucket number for the given IP address.
*
*/
static u32 sel_netnode_hashfn_ipv4(__be32 addr)
{
/* at some point we should determine if the mismatch in byte order
* affects the hash function dramatically */
return (addr & (SEL_NETNODE_HASH_SIZE - 1));
}
/**
* sel_netnode_hashfn_ipv6 - IPv6 hashing function for the node table
* @addr: IPv6 address
*
* Description:
* This is the IPv6 hashing function for the node interface table, it returns
* the bucket number for the given IP address.
*
*/
static u32 sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
{
/* just hash the least significant 32 bits to keep things fast (they
* are the most likely to be different anyway), we can revisit this
* later if needed */
return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
}
/**
* sel_netnode_find - Search for a node record
* @addr: IP address
* @family: address family
*
* Description:
* Search the network node table and return the record matching @addr. If an
* entry can not be found in the table return NULL.
*
*/
static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
{
u32 idx;
struct sel_netnode *node;
switch (family) {
case PF_INET:
idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
break;
case PF_INET6:
idx = sel_netnode_hashfn_ipv6(addr);
break;
default:
BUG();
}
list_for_each_entry_rcu(node, &sel_netnode_hash[idx], list)
if (node->nsec.family == family)
switch (family) {
case PF_INET:
if (node->nsec.addr.ipv4 == *(__be32 *)addr)
return node;
break;
case PF_INET6:
if (ipv6_addr_equal(&node->nsec.addr.ipv6,
addr))
return node;
break;
}
return NULL;
}
/**
* sel_netnode_insert - Insert a new node into the table
* @node: the new node record
*
* Description:
* Add a new node record to the network address hash table. Returns zero on
* success, negative values on failure.
*
*/
static int sel_netnode_insert(struct sel_netnode *node)
{
u32 idx;
u32 count = 0;
struct sel_netnode *iter;
switch (node->nsec.family) {
case PF_INET:
idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
break;
case PF_INET6:
idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
break;
default:
BUG();
}
list_add_rcu(&node->list, &sel_netnode_hash[idx]);
/* we need to impose a limit on the growth of the hash table so check
* this bucket to make sure it is within the specified bounds */
list_for_each_entry(iter, &sel_netnode_hash[idx], list)
if (++count > SEL_NETNODE_HASH_BKT_LIMIT) {
list_del_rcu(&iter->list);
call_rcu(&iter->rcu, sel_netnode_free);
break;
}
return 0;
}
/**
* sel_netnode_destroy - Remove a node record from the table
* @node: the existing node record
*
* Description:
* Remove an existing node record from the network address table.
*
*/
static void sel_netnode_destroy(struct sel_netnode *node)
{
list_del_rcu(&node->list);
call_rcu(&node->rcu, sel_netnode_free);
}
/**
* sel_netnode_sid_slow - Lookup the SID of a network address using the policy
* @addr: the IP address
* @family: the address family
* @sid: node SID
*
* Description:
* This function determines the SID of a network address by quering the
* security policy. The result is added to the network address table to
* speedup future queries. Returns zero on success, negative values on
* failure.
*
*/
static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
{
int ret;
struct sel_netnode *node;
struct sel_netnode *new = NULL;
spin_lock_bh(&sel_netnode_lock);
node = sel_netnode_find(addr, family);
if (node != NULL) {
*sid = node->nsec.sid;
ret = 0;
goto out;
}
new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL) {
ret = -ENOMEM;
goto out;
}
switch (family) {
case PF_INET:
ret = security_node_sid(PF_INET,
addr, sizeof(struct in_addr),
&new->nsec.sid);
new->nsec.addr.ipv4 = *(__be32 *)addr;
break;
case PF_INET6:
ret = security_node_sid(PF_INET6,
addr, sizeof(struct in6_addr),
&new->nsec.sid);
ipv6_addr_copy(&new->nsec.addr.ipv6, addr);
break;
default:
BUG();
}
if (ret != 0)
goto out;
new->nsec.family = family;
ret = sel_netnode_insert(new);
if (ret != 0)
goto out;
*sid = new->nsec.sid;
out:
spin_unlock_bh(&sel_netnode_lock);
if (unlikely(ret)) {
printk(KERN_WARNING
"SELinux: failure in sel_netnode_sid_slow(),"
" unable to determine network node label\n");
kfree(new);
}
return ret;
}
/**
* sel_netnode_sid - Lookup the SID of a network address
* @addr: the IP address
* @family: the address family
* @sid: node SID
*
* Description:
* This function determines the SID of a network address using the fastest
* method possible. First the address table is queried, but if an entry
* can't be found then the policy is queried and the result is added to the
* table to speedup future queries. Returns zero on success, negative values
* on failure.
*
*/
int sel_netnode_sid(void *addr, u16 family, u32 *sid)
{
struct sel_netnode *node;
rcu_read_lock();
node = sel_netnode_find(addr, family);
if (node != NULL) {
*sid = node->nsec.sid;
rcu_read_unlock();
return 0;
}
rcu_read_unlock();
return sel_netnode_sid_slow(addr, family, sid);
}
/**
* sel_netnode_flush - Flush the entire network address table
*
* Description:
* Remove all entries from the network address table.
*
*/
static void sel_netnode_flush(void)
{
u32 idx;
struct sel_netnode *node;
spin_lock_bh(&sel_netnode_lock);
for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++)
list_for_each_entry(node, &sel_netnode_hash[idx], list)
sel_netnode_destroy(node);
spin_unlock_bh(&sel_netnode_lock);
}
static int sel_netnode_avc_callback(u32 event, u32 ssid, u32 tsid,
u16 class, u32 perms, u32 *retained)
{
if (event == AVC_CALLBACK_RESET) {
sel_netnode_flush();
synchronize_net();
}
return 0;
}
static __init int sel_netnode_init(void)
{
int iter;
int ret;
if (!selinux_enabled)
return 0;
for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++)
INIT_LIST_HEAD(&sel_netnode_hash[iter]);
ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET,
SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
if (ret != 0)
panic("avc_add_callback() failed, error %d\n", ret);
return ret;
}
__initcall(sel_netnode_init);
...@@ -2,6 +2,11 @@ ...@@ -2,6 +2,11 @@
* *
* Added conditional policy language extensions * Added conditional policy language extensions
* *
* Updated: Hewlett-Packard <paul.moore@hp.com>
*
* Added support for the policy capability bitmap
*
* Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2003 - 2004 Tresys Technology, LLC
* Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -35,6 +40,11 @@ ...@@ -35,6 +40,11 @@
#include "objsec.h" #include "objsec.h"
#include "conditional.h" #include "conditional.h"
/* Policy capability filenames */
static char *policycap_names[] = {
"network_peer_controls"
};
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT #ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
...@@ -72,6 +82,9 @@ static int *bool_pending_values = NULL; ...@@ -72,6 +82,9 @@ static int *bool_pending_values = NULL;
static struct dentry *class_dir = NULL; static struct dentry *class_dir = NULL;
static unsigned long last_class_ino; static unsigned long last_class_ino;
/* global data for policy capabilities */
static struct dentry *policycap_dir = NULL;
extern void selnl_notify_setenforce(int val); extern void selnl_notify_setenforce(int val);
/* Check whether a task is allowed to use a security operation. */ /* Check whether a task is allowed to use a security operation. */
...@@ -111,10 +124,11 @@ enum sel_inos { ...@@ -111,10 +124,11 @@ enum sel_inos {
static unsigned long sel_last_ino = SEL_INO_NEXT - 1; static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
#define SEL_INITCON_INO_OFFSET 0x01000000 #define SEL_INITCON_INO_OFFSET 0x01000000
#define SEL_BOOL_INO_OFFSET 0x02000000 #define SEL_BOOL_INO_OFFSET 0x02000000
#define SEL_CLASS_INO_OFFSET 0x04000000 #define SEL_CLASS_INO_OFFSET 0x04000000
#define SEL_INO_MASK 0x00ffffff #define SEL_POLICYCAP_INO_OFFSET 0x08000000
#define SEL_INO_MASK 0x00ffffff
#define TMPBUFLEN 12 #define TMPBUFLEN 12
static ssize_t sel_read_enforce(struct file *filp, char __user *buf, static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
...@@ -263,6 +277,7 @@ static const struct file_operations sel_policyvers_ops = { ...@@ -263,6 +277,7 @@ static const struct file_operations sel_policyvers_ops = {
/* declaration for sel_write_load */ /* declaration for sel_write_load */
static int sel_make_bools(void); static int sel_make_bools(void);
static int sel_make_classes(void); static int sel_make_classes(void);
static int sel_make_policycap(void);
/* declaration for sel_make_class_dirs */ /* declaration for sel_make_class_dirs */
static int sel_make_dir(struct inode *dir, struct dentry *dentry, static int sel_make_dir(struct inode *dir, struct dentry *dentry,
...@@ -323,6 +338,12 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf, ...@@ -323,6 +338,12 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
} }
ret = sel_make_classes(); ret = sel_make_classes();
if (ret) {
length = ret;
goto out1;
}
ret = sel_make_policycap();
if (ret) if (ret)
length = ret; length = ret;
else else
...@@ -1399,6 +1420,24 @@ static const struct file_operations sel_perm_ops = { ...@@ -1399,6 +1420,24 @@ static const struct file_operations sel_perm_ops = {
.read = sel_read_perm, .read = sel_read_perm,
}; };
static ssize_t sel_read_policycap(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int value;
char tmpbuf[TMPBUFLEN];
ssize_t length;
unsigned long i_ino = file->f_path.dentry->d_inode->i_ino;
value = security_policycap_supported(i_ino & SEL_INO_MASK);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
static const struct file_operations sel_policycap_ops = {
.read = sel_read_policycap,
};
static int sel_make_perm_files(char *objclass, int classvalue, static int sel_make_perm_files(char *objclass, int classvalue,
struct dentry *dir) struct dentry *dir)
{ {
...@@ -1545,6 +1584,36 @@ static int sel_make_classes(void) ...@@ -1545,6 +1584,36 @@ static int sel_make_classes(void)
return rc; return rc;
} }
static int sel_make_policycap(void)
{
unsigned int iter;
struct dentry *dentry = NULL;
struct inode *inode = NULL;
sel_remove_entries(policycap_dir);
for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
if (iter < ARRAY_SIZE(policycap_names))
dentry = d_alloc_name(policycap_dir,
policycap_names[iter]);
else
dentry = d_alloc_name(policycap_dir, "unknown");
if (dentry == NULL)
return -ENOMEM;
inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO);
if (inode == NULL)
return -ENOMEM;
inode->i_fop = &sel_policycap_ops;
inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
d_add(dentry, inode);
}
return 0;
}
static int sel_make_dir(struct inode *dir, struct dentry *dentry, static int sel_make_dir(struct inode *dir, struct dentry *dentry,
unsigned long *ino) unsigned long *ino)
{ {
...@@ -1673,6 +1742,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent) ...@@ -1673,6 +1742,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
class_dir = dentry; class_dir = dentry;
dentry = d_alloc_name(sb->s_root, "policy_capabilities");
if (!dentry) {
ret = -ENOMEM;
goto err;
}
ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
if (ret)
goto err;
policycap_dir = dentry;
out: out:
return ret; return ret;
err: err:
......
This diff is collapsed.
This diff is collapsed.
...@@ -241,6 +241,8 @@ struct policydb { ...@@ -241,6 +241,8 @@ struct policydb {
/* type -> attribute reverse mapping */ /* type -> attribute reverse mapping */
struct ebitmap *type_attr_map; struct ebitmap *type_attr_map;
struct ebitmap policycaps;
unsigned int policyvers; unsigned int policyvers;
unsigned int reject_unknown : 1; unsigned int reject_unknown : 1;
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment