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
This commit is contained in:
Linus Torvalds 2008-01-31 09:32:24 +11:00
commit 44c3b59102
38 changed files with 3382 additions and 684 deletions

View file

@ -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

View file

@ -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)
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 */

View file

@ -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;
/* 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 {
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(
*/ */
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)
*/ */
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,
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,
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,
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;

View file

@ -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,
} }
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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,
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();

View file

@ -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,
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 = {
.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",

View file

@ -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)
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)
&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);

View file

@ -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)
/** /**
* 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)
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,
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)
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)
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)
*/ */
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);
} }
/** /**

View file

@ -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)
/* 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,
* @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,
*/ */
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)
* *
*/ */
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)
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;

View file

@ -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] = {
[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
*/ */

View file

@ -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 {
/* 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

File diff suppressed because it is too large Load diff

View file

@ -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 {
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 {
/* (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 {
/* 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);

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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;
} }
} }

View file

@ -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)
} }
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)
} }
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);

View file

@ -12,8 +12,8 @@
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* <dgoeddel@trustedcs.com> * <dgoeddel@trustedcs.com>
* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
* Paul Moore, <paul.moore@hp.com> * Paul Moore <paul.moore@hp.com>
* Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
* Yuichi Nakamura <ynakam@hitachisoft.jp> * Yuichi Nakamura <ynakam@hitachisoft.jp>
* *
@ -50,8 +50,11 @@
#include <net/icmp.h> #include <net/icmp.h>
#include <net/ip.h> /* for local_port_range[] */ #include <net/ip.h> /* for local_port_range[] */
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
#include <net/net_namespace.h>
#include <net/netlabel.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <asm/atomic.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/netdevice.h> /* for network interface checks */ #include <linux/netdevice.h> /* for network interface checks */
@ -76,6 +79,7 @@
#include "avc.h" #include "avc.h"
#include "objsec.h" #include "objsec.h"
#include "netif.h" #include "netif.h"
#include "netnode.h"
#include "xfrm.h" #include "xfrm.h"
#include "netlabel.h" #include "netlabel.h"
@ -89,6 +93,9 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
extern int selinux_compat_net; extern int selinux_compat_net;
extern struct security_operations *security_ops; extern struct security_operations *security_ops;
/* SECMARK reference count */
atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
int selinux_enforcing = 0; int selinux_enforcing = 0;
@ -155,6 +162,21 @@ static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
return len; return len;
} }
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
*
* Description:
* This function checks the SECMARK reference counter to see if any SECMARK
* targets are currently configured, if the reference counter is greater than
* zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
* enabled, false (0) if SECMARK is disabled.
*
*/
static int selinux_secmark_enabled(void)
{
return (atomic_read(&selinux_secmark_refcount) > 0);
}
/* Allocate and free functions for each kind of security blob. */ /* Allocate and free functions for each kind of security blob. */
static int task_alloc_security(struct task_struct *task) static int task_alloc_security(struct task_struct *task)
@ -561,8 +583,8 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
* Allow filesystems with binary mount data to explicitly set mount point * Allow filesystems with binary mount data to explicitly set mount point
* labeling information. * labeling information.
*/ */
int selinux_set_mnt_opts(struct super_block *sb, char **mount_options, static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
int *flags, int num_opts) int *flags, int num_opts)
{ {
int rc = 0, i; int rc = 0, i;
struct task_security_struct *tsec = current->security; struct task_security_struct *tsec = current->security;
@ -3395,7 +3417,7 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
#endif /* IPV6 */ #endif /* IPV6 */
static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
char **addrp, int *len, int src, u8 *proto) char **addrp, int src, u8 *proto)
{ {
int ret = 0; int ret = 0;
@ -3404,7 +3426,6 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
ret = selinux_parse_skb_ipv4(skb, ad, proto); ret = selinux_parse_skb_ipv4(skb, ad, proto);
if (ret || !addrp) if (ret || !addrp)
break; break;
*len = 4;
*addrp = (char *)(src ? &ad->u.net.v4info.saddr : *addrp = (char *)(src ? &ad->u.net.v4info.saddr :
&ad->u.net.v4info.daddr); &ad->u.net.v4info.daddr);
break; break;
@ -3414,7 +3435,6 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
ret = selinux_parse_skb_ipv6(skb, ad, proto); ret = selinux_parse_skb_ipv6(skb, ad, proto);
if (ret || !addrp) if (ret || !addrp)
break; break;
*len = 16;
*addrp = (char *)(src ? &ad->u.net.v6info.saddr : *addrp = (char *)(src ? &ad->u.net.v6info.saddr :
&ad->u.net.v6info.daddr); &ad->u.net.v6info.daddr);
break; break;
@ -3423,36 +3443,48 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
break; break;
} }
if (unlikely(ret))
printk(KERN_WARNING
"SELinux: failure in selinux_parse_skb(),"
" unable to parse packet\n");
return ret; return ret;
} }
/** /**
* selinux_skb_extlbl_sid - Determine the external label of a packet * selinux_skb_peerlbl_sid - Determine the peer label of a packet
* @skb: the packet * @skb: the packet
* @sid: the packet's SID * @family: protocol family
* @sid: the packet's peer label SID
* *
* Description: * Description:
* Check the various different forms of external packet labeling and determine * Check the various different forms of network peer labeling and determine
* the external SID for the packet. If only one form of external labeling is * the peer label/SID for the packet; most of the magic actually occurs in
* present then it is used, if both labeled IPsec and NetLabel labels are * the security server function security_net_peersid_cmp(). The function
* present then the SELinux type information is taken from the labeled IPsec * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
* SA and the MLS sensitivity label information is taken from the NetLabel * or -EACCES if @sid is invalid due to inconsistencies with the different
* security attributes. This bit of "magic" is done in the call to * peer labels.
* selinux_netlbl_skbuff_getsid().
* *
*/ */
static void selinux_skb_extlbl_sid(struct sk_buff *skb, u32 *sid) static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
{ {
int err;
u32 xfrm_sid; u32 xfrm_sid;
u32 nlbl_sid; u32 nlbl_sid;
u32 nlbl_type;
selinux_skb_xfrm_sid(skb, &xfrm_sid); selinux_skb_xfrm_sid(skb, &xfrm_sid);
if (selinux_netlbl_skbuff_getsid(skb, selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
(xfrm_sid == SECSID_NULL ?
SECINITSID_NETMSG : xfrm_sid), err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
&nlbl_sid) != 0) if (unlikely(err)) {
nlbl_sid = SECSID_NULL; printk(KERN_WARNING
*sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid); "SELinux: failure in selinux_skb_peerlbl_sid(),"
" unable to determine packet's peer label\n");
return -EACCES;
}
return 0;
} }
/* socket security operations */ /* socket security operations */
@ -3518,6 +3550,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
if (sock->sk) { if (sock->sk) {
sksec = sock->sk->sk_security; sksec = sock->sk->sk_security;
sksec->sid = isec->sid; sksec->sid = isec->sid;
sksec->sclass = isec->sclass;
err = selinux_netlbl_socket_post_create(sock); err = selinux_netlbl_socket_post_create(sock);
} }
@ -3610,7 +3643,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
break; break;
} }
err = security_node_sid(family, addrp, addrlen, &sid); err = sel_netnode_sid(addrp, family, &sid);
if (err) if (err)
goto out; goto out;
@ -3821,131 +3854,182 @@ static int selinux_socket_unix_may_send(struct socket *sock,
return 0; return 0;
} }
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
struct avc_audit_data *ad, u16 family, char *addrp, int len) u32 peer_sid,
struct avc_audit_data *ad)
{ {
int err = 0; int err;
u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0; u32 if_sid;
struct socket *sock; u32 node_sid;
u16 sock_class = 0;
u32 sock_sid = 0;
read_lock_bh(&sk->sk_callback_lock); err = sel_netif_sid(ifindex, &if_sid);
sock = sk->sk_socket;
if (sock) {
struct inode *inode;
inode = SOCK_INODE(sock);
if (inode) {
struct inode_security_struct *isec;
isec = inode->i_security;
sock_sid = isec->sid;
sock_class = isec->sclass;
}
}
read_unlock_bh(&sk->sk_callback_lock);
if (!sock_sid)
goto out;
if (!skb->dev)
goto out;
err = sel_netif_sids(skb->dev, &if_sid, NULL);
if (err) if (err)
goto out; return err;
err = avc_has_perm(peer_sid, if_sid,
SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err)
return err;
switch (sock_class) { err = sel_netnode_sid(addrp, family, &node_sid);
if (err)
return err;
return avc_has_perm(peer_sid, node_sid,
SECCLASS_NODE, NODE__RECVFROM, ad);
}
static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
struct sk_buff *skb,
struct avc_audit_data *ad,
u16 family,
char *addrp)
{
int err;
struct sk_security_struct *sksec = sk->sk_security;
u16 sk_class;
u32 netif_perm, node_perm, recv_perm;
u32 port_sid, node_sid, if_sid, sk_sid;
sk_sid = sksec->sid;
sk_class = sksec->sclass;
switch (sk_class) {
case SECCLASS_UDP_SOCKET: case SECCLASS_UDP_SOCKET:
netif_perm = NETIF__UDP_RECV; netif_perm = NETIF__UDP_RECV;
node_perm = NODE__UDP_RECV; node_perm = NODE__UDP_RECV;
recv_perm = UDP_SOCKET__RECV_MSG; recv_perm = UDP_SOCKET__RECV_MSG;
break; break;
case SECCLASS_TCP_SOCKET: case SECCLASS_TCP_SOCKET:
netif_perm = NETIF__TCP_RECV; netif_perm = NETIF__TCP_RECV;
node_perm = NODE__TCP_RECV; node_perm = NODE__TCP_RECV;
recv_perm = TCP_SOCKET__RECV_MSG; recv_perm = TCP_SOCKET__RECV_MSG;
break; break;
case SECCLASS_DCCP_SOCKET: case SECCLASS_DCCP_SOCKET:
netif_perm = NETIF__DCCP_RECV; netif_perm = NETIF__DCCP_RECV;
node_perm = NODE__DCCP_RECV; node_perm = NODE__DCCP_RECV;
recv_perm = DCCP_SOCKET__RECV_MSG; recv_perm = DCCP_SOCKET__RECV_MSG;
break; break;
default: default:
netif_perm = NETIF__RAWIP_RECV; netif_perm = NETIF__RAWIP_RECV;
node_perm = NODE__RAWIP_RECV; node_perm = NODE__RAWIP_RECV;
recv_perm = 0;
break; break;
} }
err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); err = sel_netif_sid(skb->iif, &if_sid);
if (err) if (err)
goto out; return err;
err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
if (err)
return err;
err = security_node_sid(family, addrp, len, &node_sid); err = sel_netnode_sid(addrp, family, &node_sid);
if (err) if (err)
goto out; return err;
err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad);
if (err) if (err)
goto out; return err;
if (recv_perm) { if (!recv_perm)
u32 port_sid; return 0;
err = security_port_sid(sk->sk_family, sk->sk_type,
sk->sk_protocol, ntohs(ad->u.net.sport),
&port_sid);
if (unlikely(err)) {
printk(KERN_WARNING
"SELinux: failure in"
" selinux_sock_rcv_skb_iptables_compat(),"
" network port label not found\n");
return err;
}
return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad);
}
err = security_port_sid(sk->sk_family, sk->sk_type, static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
sk->sk_protocol, ntohs(ad->u.net.sport), struct avc_audit_data *ad,
&port_sid); u16 family, char *addrp)
{
int err;
struct sk_security_struct *sksec = sk->sk_security;
u32 peer_sid;
u32 sk_sid = sksec->sid;
if (selinux_compat_net)
err = selinux_sock_rcv_skb_iptables_compat(sk, skb, ad,
family, addrp);
else
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, ad);
if (err)
return err;
if (selinux_policycap_netpeer) {
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
if (err) if (err)
goto out; return err;
err = avc_has_perm(sk_sid, peer_sid,
err = avc_has_perm(sock_sid, port_sid, SECCLASS_PEER, PEER__RECV, ad);
sock_class, recv_perm, ad); } else {
err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, ad);
if (err)
return err;
err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, ad);
} }
out:
return err; return err;
} }
static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{ {
u16 family; int err;
char *addrp;
int len, err = 0;
struct avc_audit_data ad;
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
u16 family = sk->sk_family;
u32 sk_sid = sksec->sid;
struct avc_audit_data ad;
char *addrp;
family = sk->sk_family;
if (family != PF_INET && family != PF_INET6) if (family != PF_INET && family != PF_INET6)
goto out; return 0;
/* Handle mapped IPv4 packets arriving via IPv6 sockets */ /* Handle mapped IPv4 packets arriving via IPv6 sockets */
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
family = PF_INET; family = PF_INET;
AVC_AUDIT_DATA_INIT(&ad, NET); AVC_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.netif = skb->dev ? skb->dev->name : "[unknown]"; ad.u.net.netif = skb->iif;
ad.u.net.family = family; ad.u.net.family = family;
err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL);
if (err) if (err)
goto out; return err;
if (selinux_compat_net) /* If any sort of compatibility mode is enabled then handoff processing
err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family, * to the selinux_sock_rcv_skb_compat() function to deal with the
addrp, len); * special handling. We do this in an attempt to keep this function
else * as fast and as clean as possible. */
err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET, if (selinux_compat_net || !selinux_policycap_netpeer)
return selinux_sock_rcv_skb_compat(sk, skb, &ad,
family, addrp);
if (netlbl_enabled() || selinux_xfrm_enabled()) {
u32 peer_sid;
err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
if (err)
return err;
err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family,
peer_sid, &ad);
if (err)
return err;
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad);
}
if (selinux_secmark_enabled()) {
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad); PACKET__RECV, &ad);
if (err) if (err)
goto out; return err;
}
err = selinux_netlbl_sock_rcv_skb(sksec, skb, &ad);
if (err)
goto out;
err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
out:
return err; return err;
} }
@ -3996,18 +4080,25 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
{ {
u32 peer_secid = SECSID_NULL; u32 peer_secid = SECSID_NULL;
int err = 0; u16 family;
if (sock && sock->sk->sk_family == PF_UNIX) if (sock)
family = sock->sk->sk_family;
else if (skb && skb->sk)
family = skb->sk->sk_family;
else
goto out;
if (sock && family == PF_UNIX)
selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid); selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
else if (skb) else if (skb)
selinux_skb_extlbl_sid(skb, &peer_secid); selinux_skb_peerlbl_sid(skb, family, &peer_secid);
if (peer_secid == SECSID_NULL) out:
err = -EINVAL;
*secid = peer_secid; *secid = peer_secid;
if (peer_secid == SECSID_NULL)
return err; return -EINVAL;
return 0;
} }
static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
@ -4027,6 +4118,7 @@ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
newssec->sid = ssec->sid; newssec->sid = ssec->sid;
newssec->peer_sid = ssec->peer_sid; newssec->peer_sid = ssec->peer_sid;
newssec->sclass = ssec->sclass;
selinux_netlbl_sk_security_clone(ssec, newssec); selinux_netlbl_sk_security_clone(ssec, newssec);
} }
@ -4050,6 +4142,7 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent)
if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
sk->sk_family == PF_UNIX) sk->sk_family == PF_UNIX)
isec->sid = sksec->sid; isec->sid = sksec->sid;
sksec->sclass = isec->sclass;
selinux_netlbl_sock_graft(sk, parent); selinux_netlbl_sock_graft(sk, parent);
} }
@ -4062,7 +4155,9 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
u32 newsid; u32 newsid;
u32 peersid; u32 peersid;
selinux_skb_extlbl_sid(skb, &peersid); err = selinux_skb_peerlbl_sid(skb, sk->sk_family, &peersid);
if (err)
return err;
if (peersid == SECSID_NULL) { if (peersid == SECSID_NULL) {
req->secid = sksec->sid; req->secid = sksec->sid;
req->peer_secid = SECSID_NULL; req->peer_secid = SECSID_NULL;
@ -4100,7 +4195,7 @@ static void selinux_inet_conn_established(struct sock *sk,
{ {
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
selinux_skb_extlbl_sid(skb, &sksec->peer_sid); selinux_skb_peerlbl_sid(skb, sk->sk_family, &sksec->peer_sid);
} }
static void selinux_req_classify_flow(const struct request_sock *req, static void selinux_req_classify_flow(const struct request_sock *req,
@ -4147,149 +4242,260 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev, static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
struct avc_audit_data *ad, u16 family)
u16 family, char *addrp, int len)
{ {
int err = 0; char *addrp;
u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0; u32 peer_sid;
struct socket *sock; struct avc_audit_data ad;
struct inode *inode; u8 secmark_active;
struct inode_security_struct *isec; u8 peerlbl_active;
sock = sk->sk_socket; if (!selinux_policycap_netpeer)
if (!sock) return NF_ACCEPT;
goto out;
inode = SOCK_INODE(sock); secmark_active = selinux_secmark_enabled();
if (!inode) peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
goto out; if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
isec = inode->i_security; AVC_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.netif = ifindex;
err = sel_netif_sids(dev, &if_sid, NULL); ad.u.net.family = family;
if (err) if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
goto out; return NF_DROP;
switch (isec->sclass) { if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
return NF_DROP;
if (peerlbl_active)
if (selinux_inet_sys_rcv_skb(ifindex, addrp, family,
peer_sid, &ad) != 0)
return NF_DROP;
if (secmark_active)
if (avc_has_perm(peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
return NF_ACCEPT;
}
static unsigned int selinux_ipv4_forward(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return selinux_ip_forward(skb, in->ifindex, PF_INET);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static unsigned int selinux_ipv6_forward(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return selinux_ip_forward(skb, in->ifindex, PF_INET6);
}
#endif /* IPV6 */
static int selinux_ip_postroute_iptables_compat(struct sock *sk,
int ifindex,
struct avc_audit_data *ad,
u16 family, char *addrp)
{
int err;
struct sk_security_struct *sksec = sk->sk_security;
u16 sk_class;
u32 netif_perm, node_perm, send_perm;
u32 port_sid, node_sid, if_sid, sk_sid;
sk_sid = sksec->sid;
sk_class = sksec->sclass;
switch (sk_class) {
case SECCLASS_UDP_SOCKET: case SECCLASS_UDP_SOCKET:
netif_perm = NETIF__UDP_SEND; netif_perm = NETIF__UDP_SEND;
node_perm = NODE__UDP_SEND; node_perm = NODE__UDP_SEND;
send_perm = UDP_SOCKET__SEND_MSG; send_perm = UDP_SOCKET__SEND_MSG;
break; break;
case SECCLASS_TCP_SOCKET: case SECCLASS_TCP_SOCKET:
netif_perm = NETIF__TCP_SEND; netif_perm = NETIF__TCP_SEND;
node_perm = NODE__TCP_SEND; node_perm = NODE__TCP_SEND;
send_perm = TCP_SOCKET__SEND_MSG; send_perm = TCP_SOCKET__SEND_MSG;
break; break;
case SECCLASS_DCCP_SOCKET: case SECCLASS_DCCP_SOCKET:
netif_perm = NETIF__DCCP_SEND; netif_perm = NETIF__DCCP_SEND;
node_perm = NODE__DCCP_SEND; node_perm = NODE__DCCP_SEND;
send_perm = DCCP_SOCKET__SEND_MSG; send_perm = DCCP_SOCKET__SEND_MSG;
break; break;
default: default:
netif_perm = NETIF__RAWIP_SEND; netif_perm = NETIF__RAWIP_SEND;
node_perm = NODE__RAWIP_SEND; node_perm = NODE__RAWIP_SEND;
send_perm = 0;
break; break;
} }
err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad); err = sel_netif_sid(ifindex, &if_sid);
if (err) if (err)
goto out; return err;
err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
return err;
err = security_node_sid(family, addrp, len, &node_sid); err = sel_netnode_sid(addrp, family, &node_sid);
if (err) if (err)
goto out; return err;
err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
if (err) if (err)
goto out; return err;
if (send_perm) { if (send_perm != 0)
u32 port_sid; return 0;
err = security_port_sid(sk->sk_family,
sk->sk_type,
sk->sk_protocol,
ntohs(ad->u.net.dport),
&port_sid);
if (err)
goto out;
err = avc_has_perm(isec->sid, port_sid, isec->sclass, err = security_port_sid(sk->sk_family, sk->sk_type,
send_perm, ad); sk->sk_protocol, ntohs(ad->u.net.dport),
&port_sid);
if (unlikely(err)) {
printk(KERN_WARNING
"SELinux: failure in"
" selinux_ip_postroute_iptables_compat(),"
" network port label not found\n");
return err;
} }
out: return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
return err;
} }
static unsigned int selinux_ip_postroute_last(unsigned int hooknum, static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
struct sk_buff *skb, int ifindex,
const struct net_device *in, struct avc_audit_data *ad,
const struct net_device *out, u16 family,
int (*okfn)(struct sk_buff *), char *addrp,
u16 family) u8 proto)
{ {
char *addrp; struct sock *sk = skb->sk;
int len, err = 0;
struct sock *sk;
struct avc_audit_data ad;
struct net_device *dev = (struct net_device *)out;
struct sk_security_struct *sksec; struct sk_security_struct *sksec;
u8 proto;
sk = skb->sk;
if (!sk)
goto out;
if (sk == NULL)
return NF_ACCEPT;
sksec = sk->sk_security; sksec = sk->sk_security;
AVC_AUDIT_DATA_INIT(&ad, NET); if (selinux_compat_net) {
ad.u.net.netif = dev->name; if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
ad.u.net.family = family; ad, family, addrp))
return NF_DROP;
} else {
if (avc_has_perm(sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, ad))
return NF_DROP;
}
err = selinux_parse_skb(skb, &ad, &addrp, &len, 0, &proto); if (selinux_policycap_netpeer)
if (err) if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
goto out; return NF_DROP;
if (selinux_compat_net) return NF_ACCEPT;
err = selinux_ip_postroute_last_compat(sk, dev, &ad,
family, addrp, len);
else
err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
PACKET__SEND, &ad);
if (err)
goto out;
err = selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto);
out:
return err ? NF_DROP : NF_ACCEPT;
} }
static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum, static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
struct sk_buff *skb, u16 family)
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{ {
return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET); u32 secmark_perm;
u32 peer_sid;
struct sock *sk;
struct avc_audit_data ad;
char *addrp;
u8 proto;
u8 secmark_active;
u8 peerlbl_active;
AVC_AUDIT_DATA_INIT(&ad, NET);
ad.u.net.netif = ifindex;
ad.u.net.family = family;
if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
return NF_DROP;
/* If any sort of compatibility mode is enabled then handoff processing
* to the selinux_ip_postroute_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
if (selinux_compat_net || !selinux_policycap_netpeer)
return selinux_ip_postroute_compat(skb, ifindex, &ad,
family, addrp, proto);
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
* packet transformation so allow the packet to pass without any checks
* since we'll have another chance to perform access control checks
* when the packet is on it's final way out.
* NOTE: there appear to be some IPv6 multicast cases where skb->dst
* is NULL, in this case go ahead and apply access control. */
if (skb->dst != NULL && skb->dst->xfrm != NULL)
return NF_ACCEPT;
secmark_active = selinux_secmark_enabled();
peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
/* if the packet is locally generated (skb->sk != NULL) then use the
* socket's label as the peer label, otherwise the packet is being
* forwarded through this system and we need to fetch the peer label
* directly from the packet */
sk = skb->sk;
if (sk) {
struct sk_security_struct *sksec = sk->sk_security;
peer_sid = sksec->sid;
secmark_perm = PACKET__SEND;
} else {
if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
return NF_DROP;
secmark_perm = PACKET__FORWARD_OUT;
}
if (secmark_active)
if (avc_has_perm(peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP;
if (peerlbl_active) {
u32 if_sid;
u32 node_sid;
if (sel_netif_sid(ifindex, &if_sid))
return NF_DROP;
if (avc_has_perm(peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP;
if (sel_netnode_sid(addrp, family, &node_sid))
return NF_DROP;
if (avc_has_perm(peer_sid, node_sid,
SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP;
}
return NF_ACCEPT;
}
static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
return selinux_ip_postroute(skb, out->ifindex, PF_INET);
} }
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum, struct sk_buff *skb,
struct sk_buff *skb, const struct net_device *in,
const struct net_device *in, const struct net_device *out,
const struct net_device *out, int (*okfn)(struct sk_buff *))
int (*okfn)(struct sk_buff *))
{ {
return selinux_ip_postroute_last(hooknum, skb, in, out, okfn, PF_INET6); return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
} }
#endif /* IPV6 */ #endif /* IPV6 */
#endif /* CONFIG_NETFILTER */ #endif /* CONFIG_NETFILTER */
@ -5277,22 +5483,40 @@ security_initcall(selinux_init);
#if defined(CONFIG_NETFILTER) #if defined(CONFIG_NETFILTER)
static struct nf_hook_ops selinux_ipv4_op = { static struct nf_hook_ops selinux_ipv4_ops[] = {
.hook = selinux_ipv4_postroute_last, {
.owner = THIS_MODULE, .hook = selinux_ipv4_postroute,
.pf = PF_INET, .owner = THIS_MODULE,
.hooknum = NF_INET_POST_ROUTING, .pf = PF_INET,
.priority = NF_IP_PRI_SELINUX_LAST, .hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP_PRI_SELINUX_LAST,
},
{
.hook = selinux_ipv4_forward,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP_PRI_SELINUX_FIRST,
}
}; };
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static struct nf_hook_ops selinux_ipv6_op = { static struct nf_hook_ops selinux_ipv6_ops[] = {
.hook = selinux_ipv6_postroute_last, {
.owner = THIS_MODULE, .hook = selinux_ipv6_postroute,
.pf = PF_INET6, .owner = THIS_MODULE,
.hooknum = NF_INET_POST_ROUTING, .pf = PF_INET6,
.priority = NF_IP6_PRI_SELINUX_LAST, .hooknum = NF_INET_POST_ROUTING,
.priority = NF_IP6_PRI_SELINUX_LAST,
},
{
.hook = selinux_ipv6_forward,
.owner = THIS_MODULE,
.pf = PF_INET6,
.hooknum = NF_INET_FORWARD,
.priority = NF_IP6_PRI_SELINUX_FIRST,
}
}; };
#endif /* IPV6 */ #endif /* IPV6 */
@ -5300,22 +5524,27 @@ static struct nf_hook_ops selinux_ipv6_op = {
static int __init selinux_nf_ip_init(void) static int __init selinux_nf_ip_init(void)
{ {
int err = 0; int err = 0;
u32 iter;
if (!selinux_enabled) if (!selinux_enabled)
goto out; goto out;
printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
err = nf_register_hook(&selinux_ipv4_op); for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) {
if (err) err = nf_register_hook(&selinux_ipv4_ops[iter]);
panic("SELinux: nf_register_hook for IPv4: error %d\n", err); if (err)
panic("SELinux: nf_register_hook for IPv4: error %d\n",
err);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) {
err = nf_register_hook(&selinux_ipv6_op); err = nf_register_hook(&selinux_ipv6_ops[iter]);
if (err) if (err)
panic("SELinux: nf_register_hook for IPv6: error %d\n", err); panic("SELinux: nf_register_hook for IPv6: error %d\n",
err);
}
#endif /* IPV6 */ #endif /* IPV6 */
out: out:
@ -5327,11 +5556,15 @@ __initcall(selinux_nf_ip_init);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef CONFIG_SECURITY_SELINUX_DISABLE
static void selinux_nf_ip_exit(void) static void selinux_nf_ip_exit(void)
{ {
u32 iter;
printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n");
nf_unregister_hook(&selinux_ipv4_op); for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++)
nf_unregister_hook(&selinux_ipv4_ops[iter]);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
nf_unregister_hook(&selinux_ipv6_op); for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++)
nf_unregister_hook(&selinux_ipv6_ops[iter]);
#endif /* IPV6 */ #endif /* IPV6 */
} }
#endif #endif

View file

@ -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 @@
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 @@
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 @@
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")

View file

@ -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 @@
#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 @@
#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 @@
#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

View file

@ -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;

View file

@ -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")

View file

@ -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

View file

@ -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 @@
#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_ */

View file

@ -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(
} }
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,
} }
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;

View file

@ -0,0 +1,32 @@
/*
* 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

View file

@ -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,

View file

@ -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;
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,
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,
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,
#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,
#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;

View file

@ -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)
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)
{ {

View file

@ -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 @@
#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);
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); /* NOTE: we always use init's network namespace since we don't
if (likely(netif != NULL)) * currently support containers */
goto out;
new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (!new) {
netif = ERR_PTR(-ENOMEM);
goto out;
}
nsec = &new->nsec;
ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid); dev = dev_get_by_index(&init_net, ifindex);
if (ret < 0) { if (unlikely(dev == NULL)) {
kfree(new); printk(KERN_WARNING
netif = ERR_PTR(ret); "SELinux: failure in sel_netif_sid_slow(),"
goto out; " invalid network interface (%d)\n", ifindex);
return -ENOENT;
} }
nsec->dev = dev;
spin_lock_bh(&sel_netif_lock); spin_lock_bh(&sel_netif_lock);
netif = sel_netif_find(ifindex);
netif = sel_netif_find(dev); if (netif != NULL) {
if (netif) { *sid = netif->nsec.sid;
spin_unlock_bh(&sel_netif_lock); ret = 0;
kfree(new);
goto out; goto out;
} }
new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL) {
ret = -ENOMEM;
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,
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 = {
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)
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;
} }

View file

@ -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,
* 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,
* 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)
} }
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)
*/ */
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)
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)
{ {
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)
* 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)
*/ */
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,
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)

354
security/selinux/netnode.c Normal file
View file

@ -0,0 +1,354 @@
/*
* 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);

View file

@ -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 @@
#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;
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 {
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 = {
/* 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,
} }
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 = {
.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)
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)
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:

View file

@ -562,7 +562,7 @@ void mls_export_netlbl_lvl(struct context *context,
if (!selinux_mls_enabled) if (!selinux_mls_enabled)
return; return;
secattr->mls_lvl = context->range.level[0].sens - 1; secattr->attr.mls.lvl = context->range.level[0].sens - 1;
secattr->flags |= NETLBL_SECATTR_MLS_LVL; secattr->flags |= NETLBL_SECATTR_MLS_LVL;
} }
@ -582,7 +582,7 @@ void mls_import_netlbl_lvl(struct context *context,
if (!selinux_mls_enabled) if (!selinux_mls_enabled)
return; return;
context->range.level[0].sens = secattr->mls_lvl + 1; context->range.level[0].sens = secattr->attr.mls.lvl + 1;
context->range.level[1].sens = context->range.level[0].sens; context->range.level[1].sens = context->range.level[0].sens;
} }
@ -605,8 +605,8 @@ int mls_export_netlbl_cat(struct context *context,
return 0; return 0;
rc = ebitmap_netlbl_export(&context->range.level[0].cat, rc = ebitmap_netlbl_export(&context->range.level[0].cat,
&secattr->mls_cat); &secattr->attr.mls.cat);
if (rc == 0 && secattr->mls_cat != NULL) if (rc == 0 && secattr->attr.mls.cat != NULL)
secattr->flags |= NETLBL_SECATTR_MLS_CAT; secattr->flags |= NETLBL_SECATTR_MLS_CAT;
return rc; return rc;
@ -633,7 +633,7 @@ int mls_import_netlbl_cat(struct context *context,
return 0; return 0;
rc = ebitmap_netlbl_import(&context->range.level[0].cat, rc = ebitmap_netlbl_import(&context->range.level[0].cat,
secattr->mls_cat); secattr->attr.mls.cat);
if (rc != 0) if (rc != 0)
goto import_netlbl_cat_failure; goto import_netlbl_cat_failure;

View file

@ -13,6 +13,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) 2004-2005 Trusted Computer Solutions, Inc. * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004 Tresys Technology, LLC * Copyright (C) 2003 - 2004 Tresys Technology, LLC
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -102,6 +107,11 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM, .sym_num = SYM_NUM,
.ocon_num = OCON_NUM, .ocon_num = OCON_NUM,
}, },
{
.version = POLICYDB_VERSION_POLCAP,
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
}
}; };
static struct policydb_compat_info *policydb_lookup_compat(int version) static struct policydb_compat_info *policydb_lookup_compat(int version)
@ -183,6 +193,8 @@ static int policydb_init(struct policydb *p)
if (rc) if (rc)
goto out_free_symtab; goto out_free_symtab;
ebitmap_init(&p->policycaps);
out: out:
return rc; return rc;
@ -673,8 +685,8 @@ void policydb_destroy(struct policydb *p)
ebitmap_destroy(&p->type_attr_map[i]); ebitmap_destroy(&p->type_attr_map[i]);
} }
kfree(p->type_attr_map); kfree(p->type_attr_map);
kfree(p->undefined_perms); kfree(p->undefined_perms);
ebitmap_destroy(&p->policycaps);
return; return;
} }
@ -1554,6 +1566,10 @@ int policydb_read(struct policydb *p, void *fp)
p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
if (p->policyvers >= POLICYDB_VERSION_POLCAP &&
ebitmap_read(&p->policycaps, fp) != 0)
goto bad;
info = policydb_lookup_compat(p->policyvers); info = policydb_lookup_compat(p->policyvers);
if (!info) { if (!info) {
printk(KERN_ERR "security: unable to find policy compat info " printk(KERN_ERR "security: unable to find policy compat info "

View file

@ -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;

View file

@ -16,12 +16,13 @@
* Updated: Hewlett-Packard <paul.moore@hp.com> * Updated: Hewlett-Packard <paul.moore@hp.com>
* *
* Added support for NetLabel * Added support for NetLabel
* Added support for the policy capability bitmap
* *
* Updated: Chad Sellers <csellers@tresys.com> * Updated: Chad Sellers <csellers@tresys.com>
* *
* Added validation of kernel classes and permissions * Added validation of kernel classes and permissions
* *
* Copyright (C) 2006 Hewlett-Packard Development Company, L.P. * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@ -59,6 +60,8 @@
extern void selnl_notify_policyload(u32 seqno); extern void selnl_notify_policyload(u32 seqno);
unsigned int policydb_loaded_version; unsigned int policydb_loaded_version;
int selinux_policycap_netpeer;
/* /*
* This is declared in avc.c * This is declared in avc.c
*/ */
@ -1299,6 +1302,12 @@ static int convert_context(u32 key,
goto out; goto out;
} }
static void security_load_policycaps(void)
{
selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_NETPEER);
}
extern void selinux_complete_init(void); extern void selinux_complete_init(void);
static int security_preserve_bools(struct policydb *p); static int security_preserve_bools(struct policydb *p);
@ -1346,6 +1355,7 @@ int security_load_policy(void *data, size_t len)
avtab_cache_destroy(); avtab_cache_destroy();
return -EINVAL; return -EINVAL;
} }
security_load_policycaps();
policydb_loaded_version = policydb.policyvers; policydb_loaded_version = policydb.policyvers;
ss_initialized = 1; ss_initialized = 1;
seqno = ++latest_granting; seqno = ++latest_granting;
@ -1404,6 +1414,7 @@ int security_load_policy(void *data, size_t len)
POLICY_WRLOCK; POLICY_WRLOCK;
memcpy(&policydb, &newpolicydb, sizeof policydb); memcpy(&policydb, &newpolicydb, sizeof policydb);
sidtab_set(&sidtab, &newsidtab); sidtab_set(&sidtab, &newsidtab);
security_load_policycaps();
seqno = ++latest_granting; seqno = ++latest_granting;
policydb_loaded_version = policydb.policyvers; policydb_loaded_version = policydb.policyvers;
POLICY_WRUNLOCK; POLICY_WRUNLOCK;
@ -1478,11 +1489,8 @@ int security_port_sid(u16 domain,
* security_netif_sid - Obtain the SID for a network interface. * security_netif_sid - Obtain the SID for a network interface.
* @name: interface name * @name: interface name
* @if_sid: interface SID * @if_sid: interface SID
* @msg_sid: default SID for received packets
*/ */
int security_netif_sid(char *name, int security_netif_sid(char *name, u32 *if_sid)
u32 *if_sid,
u32 *msg_sid)
{ {
int rc = 0; int rc = 0;
struct ocontext *c; struct ocontext *c;
@ -1510,11 +1518,8 @@ int security_netif_sid(char *name,
goto out; goto out;
} }
*if_sid = c->sid[0]; *if_sid = c->sid[0];
*msg_sid = c->sid[1]; } else
} else {
*if_sid = SECINITSID_NETIF; *if_sid = SECINITSID_NETIF;
*msg_sid = SECINITSID_NETMSG;
}
out: out:
POLICY_RDUNLOCK; POLICY_RDUNLOCK;
@ -2049,6 +2054,91 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
return rc; return rc;
} }
/**
* security_net_peersid_resolve - Compare and resolve two network peer SIDs
* @nlbl_sid: NetLabel SID
* @nlbl_type: NetLabel labeling protocol type
* @xfrm_sid: XFRM SID
*
* Description:
* Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
* resolved into a single SID it is returned via @peer_sid and the function
* returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function
* returns a negative value. A table summarizing the behavior is below:
*
* | function return | @sid
* ------------------------------+-----------------+-----------------
* no peer labels | 0 | SECSID_NULL
* single peer label | 0 | <peer_label>
* multiple, consistent labels | 0 | <peer_label>
* multiple, inconsistent labels | -<errno> | SECSID_NULL
*
*/
int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
u32 xfrm_sid,
u32 *peer_sid)
{
int rc;
struct context *nlbl_ctx;
struct context *xfrm_ctx;
/* handle the common (which also happens to be the set of easy) cases
* right away, these two if statements catch everything involving a
* single or absent peer SID/label */
if (xfrm_sid == SECSID_NULL) {
*peer_sid = nlbl_sid;
return 0;
}
/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
* and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
* is present */
if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
*peer_sid = xfrm_sid;
return 0;
}
/* we don't need to check ss_initialized here since the only way both
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
* security server was initialized and ss_initialized was true */
if (!selinux_mls_enabled) {
*peer_sid = SECSID_NULL;
return 0;
}
POLICY_RDLOCK;
nlbl_ctx = sidtab_search(&sidtab, nlbl_sid);
if (!nlbl_ctx) {
printk(KERN_ERR
"security_sid_mls_cmp: unrecognized SID %d\n",
nlbl_sid);
rc = -EINVAL;
goto out_slowpath;
}
xfrm_ctx = sidtab_search(&sidtab, xfrm_sid);
if (!xfrm_ctx) {
printk(KERN_ERR
"security_sid_mls_cmp: unrecognized SID %d\n",
xfrm_sid);
rc = -EINVAL;
goto out_slowpath;
}
rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
out_slowpath:
POLICY_RDUNLOCK;
if (rc == 0)
/* at present NetLabel SIDs/labels really only carry MLS
* information so if the MLS portion of the NetLabel SID
* matches the MLS portion of the labeled XFRM SID/label
* then pass along the XFRM SID as it is the most
* expressive */
*peer_sid = xfrm_sid;
else
*peer_sid = SECSID_NULL;
return rc;
}
static int get_classes_callback(void *k, void *d, void *args) static int get_classes_callback(void *k, void *d, void *args)
{ {
struct class_datum *datum = d; struct class_datum *datum = d;
@ -2154,6 +2244,60 @@ int security_get_allow_unknown(void)
return policydb.allow_unknown; return policydb.allow_unknown;
} }
/**
* security_get_policycaps - Query the loaded policy for its capabilities
* @len: the number of capability bits
* @values: the capability bit array
*
* Description:
* Get an array of the policy capabilities in @values where each entry in
* @values is either true (1) or false (0) depending the policy's support of
* that feature. The policy capabilities are defined by the
* POLICYDB_CAPABILITY_* enums. The size of the array is stored in @len and it
* is up to the caller to free the array in @values. Returns zero on success,
* negative values on failure.
*
*/
int security_get_policycaps(int *len, int **values)
{
int rc = -ENOMEM;
unsigned int iter;
POLICY_RDLOCK;
*values = kcalloc(POLICYDB_CAPABILITY_MAX, sizeof(int), GFP_ATOMIC);
if (*values == NULL)
goto out;
for (iter = 0; iter < POLICYDB_CAPABILITY_MAX; iter++)
(*values)[iter] = ebitmap_get_bit(&policydb.policycaps, iter);
*len = POLICYDB_CAPABILITY_MAX;
out:
POLICY_RDUNLOCK;
return rc;
}
/**
* security_policycap_supported - Check for a specific policy capability
* @req_cap: capability
*
* Description:
* This function queries the currently loaded policy to see if it supports the
* capability specified by @req_cap. Returns true (1) if the capability is
* supported, false (0) if it isn't supported.
*
*/
int security_policycap_supported(unsigned int req_cap)
{
int rc;
POLICY_RDLOCK;
rc = ebitmap_get_bit(&policydb.policycaps, req_cap);
POLICY_RDUNLOCK;
return rc;
}
struct selinux_audit_rule { struct selinux_audit_rule {
u32 au_seqno; u32 au_seqno;
struct context au_ctxt; struct context au_ctxt;
@ -2403,50 +2547,10 @@ void selinux_audit_set_callback(int (*callback)(void))
} }
#ifdef CONFIG_NETLABEL #ifdef CONFIG_NETLABEL
/*
* NetLabel cache structure
*/
#define NETLBL_CACHE(x) ((struct selinux_netlbl_cache *)(x))
#define NETLBL_CACHE_T_NONE 0
#define NETLBL_CACHE_T_SID 1
#define NETLBL_CACHE_T_MLS 2
struct selinux_netlbl_cache {
u32 type;
union {
u32 sid;
struct mls_range mls_label;
} data;
};
/**
* security_netlbl_cache_free - Free the NetLabel cached data
* @data: the data to free
*
* Description:
* This function is intended to be used as the free() callback inside the
* netlbl_lsm_cache structure.
*
*/
static void security_netlbl_cache_free(const void *data)
{
struct selinux_netlbl_cache *cache;
if (data == NULL)
return;
cache = NETLBL_CACHE(data);
switch (cache->type) {
case NETLBL_CACHE_T_MLS:
ebitmap_destroy(&cache->data.mls_label.level[0].cat);
break;
}
kfree(data);
}
/** /**
* security_netlbl_cache_add - Add an entry to the NetLabel cache * security_netlbl_cache_add - Add an entry to the NetLabel cache
* @secattr: the NetLabel packet security attributes * @secattr: the NetLabel packet security attributes
* @ctx: the SELinux context * @sid: the SELinux SID
* *
* Description: * Description:
* Attempt to cache the context in @ctx, which was derived from the packet in * Attempt to cache the context in @ctx, which was derived from the packet in
@ -2455,60 +2559,46 @@ static void security_netlbl_cache_free(const void *data)
* *
*/ */
static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
struct context *ctx) u32 sid)
{ {
struct selinux_netlbl_cache *cache = NULL; u32 *sid_cache;
sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
if (sid_cache == NULL)
return;
secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
if (secattr->cache == NULL) if (secattr->cache == NULL) {
return; kfree(sid_cache);
cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
if (cache == NULL)
return;
cache->type = NETLBL_CACHE_T_MLS;
if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
&ctx->range.level[0].cat) != 0) {
kfree(cache);
return; return;
} }
cache->data.mls_label.level[1].cat.highbit =
cache->data.mls_label.level[0].cat.highbit;
cache->data.mls_label.level[1].cat.node =
cache->data.mls_label.level[0].cat.node;
cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
secattr->cache->free = security_netlbl_cache_free; *sid_cache = sid;
secattr->cache->data = (void *)cache; secattr->cache->free = kfree;
secattr->cache->data = sid_cache;
secattr->flags |= NETLBL_SECATTR_CACHE; secattr->flags |= NETLBL_SECATTR_CACHE;
} }
/** /**
* security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
* @secattr: the NetLabel packet security attributes * @secattr: the NetLabel packet security attributes
* @base_sid: the SELinux SID to use as a context for MLS only attributes
* @sid: the SELinux SID * @sid: the SELinux SID
* *
* Description: * Description:
* Convert the given NetLabel security attributes in @secattr into a * Convert the given NetLabel security attributes in @secattr into a
* SELinux SID. If the @secattr field does not contain a full SELinux * SELinux SID. If the @secattr field does not contain a full SELinux
* SID/context then use the context in @base_sid as the foundation. If * SID/context then use SECINITSID_NETMSG as the foundation. If possibile the
* possibile the 'cache' field of @secattr is set and the CACHE flag is set; * 'cache' field of @secattr is set and the CACHE flag is set; this is to
* this is to allow the @secattr to be used by NetLabel to cache the secattr to * allow the @secattr to be used by NetLabel to cache the secattr to SID
* SID conversion for future lookups. Returns zero on success, negative * conversion for future lookups. Returns zero on success, negative values on
* values on failure. * failure.
* *
*/ */
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 rc = -EIDRM; int rc = -EIDRM;
struct context *ctx; struct context *ctx;
struct context ctx_new; struct context ctx_new;
struct selinux_netlbl_cache *cache;
if (!ss_initialized) { if (!ss_initialized) {
*sid = SECSID_NULL; *sid = SECSID_NULL;
@ -2518,40 +2608,13 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
POLICY_RDLOCK; POLICY_RDLOCK;
if (secattr->flags & NETLBL_SECATTR_CACHE) { if (secattr->flags & NETLBL_SECATTR_CACHE) {
cache = NETLBL_CACHE(secattr->cache->data); *sid = *(u32 *)secattr->cache->data;
switch (cache->type) { rc = 0;
case NETLBL_CACHE_T_SID: } else if (secattr->flags & NETLBL_SECATTR_SECID) {
*sid = cache->data.sid; *sid = secattr->attr.secid;
rc = 0; rc = 0;
break;
case NETLBL_CACHE_T_MLS:
ctx = sidtab_search(&sidtab, base_sid);
if (ctx == NULL)
goto netlbl_secattr_to_sid_return;
ctx_new.user = ctx->user;
ctx_new.role = ctx->role;
ctx_new.type = ctx->type;
ctx_new.range.level[0].sens =
cache->data.mls_label.level[0].sens;
ctx_new.range.level[0].cat.highbit =
cache->data.mls_label.level[0].cat.highbit;
ctx_new.range.level[0].cat.node =
cache->data.mls_label.level[0].cat.node;
ctx_new.range.level[1].sens =
cache->data.mls_label.level[1].sens;
ctx_new.range.level[1].cat.highbit =
cache->data.mls_label.level[1].cat.highbit;
ctx_new.range.level[1].cat.node =
cache->data.mls_label.level[1].cat.node;
rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
break;
default:
goto netlbl_secattr_to_sid_return;
}
} else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
ctx = sidtab_search(&sidtab, base_sid); ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
if (ctx == NULL) if (ctx == NULL)
goto netlbl_secattr_to_sid_return; goto netlbl_secattr_to_sid_return;
@ -2561,7 +2624,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
mls_import_netlbl_lvl(&ctx_new, secattr); mls_import_netlbl_lvl(&ctx_new, secattr);
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
secattr->mls_cat) != 0) secattr->attr.mls.cat) != 0)
goto netlbl_secattr_to_sid_return; goto netlbl_secattr_to_sid_return;
ctx_new.range.level[1].cat.highbit = ctx_new.range.level[1].cat.highbit =
ctx_new.range.level[0].cat.highbit; ctx_new.range.level[0].cat.highbit;
@ -2578,7 +2641,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
if (rc != 0) if (rc != 0)
goto netlbl_secattr_to_sid_return_cleanup; goto netlbl_secattr_to_sid_return_cleanup;
security_netlbl_cache_add(secattr, &ctx_new); security_netlbl_cache_add(secattr, *sid);
ebitmap_destroy(&ctx_new.range.level[0].cat); ebitmap_destroy(&ctx_new.range.level[0].cat);
} else { } else {

View file

@ -46,11 +46,14 @@
#include <net/checksum.h> #include <net/checksum.h>
#include <net/udp.h> #include <net/udp.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/atomic.h>
#include "avc.h" #include "avc.h"
#include "objsec.h" #include "objsec.h"
#include "xfrm.h" #include "xfrm.h"
/* Labeled XFRM instance counter */
atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
/* /*
* Returns true if an LSM/SELinux context * Returns true if an LSM/SELinux context
@ -293,6 +296,9 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
BUG_ON(!uctx); BUG_ON(!uctx);
err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0);
if (err == 0)
atomic_inc(&selinux_xfrm_refcount);
return err; return err;
} }
@ -340,10 +346,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
struct xfrm_sec_ctx *ctx = xp->security; struct xfrm_sec_ctx *ctx = xp->security;
int rc = 0; int rc = 0;
if (ctx) if (ctx) {
rc = avc_has_perm(tsec->sid, ctx->ctx_sid, rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, SECCLASS_ASSOCIATION,
ASSOCIATION__SETCONTEXT, NULL); ASSOCIATION__SETCONTEXT, NULL);
if (rc == 0)
atomic_dec(&selinux_xfrm_refcount);
}
return rc; return rc;
} }
@ -360,6 +369,8 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
BUG_ON(!x); BUG_ON(!x);
err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
if (err == 0)
atomic_inc(&selinux_xfrm_refcount);
return err; return err;
} }
@ -382,10 +393,13 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
struct xfrm_sec_ctx *ctx = x->security; struct xfrm_sec_ctx *ctx = x->security;
int rc = 0; int rc = 0;
if (ctx) if (ctx) {
rc = avc_has_perm(tsec->sid, ctx->ctx_sid, rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, SECCLASS_ASSOCIATION,
ASSOCIATION__SETCONTEXT, NULL); ASSOCIATION__SETCONTEXT, NULL);
if (rc == 0)
atomic_dec(&selinux_xfrm_refcount);
}
return rc; return rc;
} }