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:
commit
44c3b59102
|
@ -115,6 +115,8 @@
|
|||
#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */
|
||||
#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */
|
||||
#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_LAST_KERN_ANOM_MSG 1799
|
||||
|
|
|
@ -120,16 +120,35 @@ void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
|
|||
int selinux_string_to_sid(char *str, u32 *sid);
|
||||
|
||||
/**
|
||||
* selinux_relabel_packet_permission - check permission to relabel a packet
|
||||
* @sid: ID value to be applied to network packet (via SECMARK, most likely)
|
||||
* selinux_secmark_relabel_packet_permission - secmark permission check
|
||||
* @sid: SECMARK ID value to be applied to network packet
|
||||
*
|
||||
* Returns 0 if the current task is allowed to label packets with the
|
||||
* supplied security ID. Note that it is implicit that the packet is always
|
||||
* being relabeled from the default unlabled value, and that the access
|
||||
* control decision is made in the AVC.
|
||||
* Returns 0 if the current task is allowed to set the SECMARK label of
|
||||
* packets with the supplied security ID. Note that it is implicit that
|
||||
* the packet is always being relabeled from the default unlabeled value,
|
||||
* 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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline int selinux_relabel_packet_permission(u32 sid)
|
||||
static inline int selinux_secmark_relabel_packet_permission(u32 sid)
|
||||
{
|
||||
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 /* _LINUX_SELINUX_H */
|
||||
|
|
|
@ -67,7 +67,11 @@
|
|||
* 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 */
|
||||
#define NETLBL_NLTYPE_NONE 0
|
||||
|
@ -105,17 +109,49 @@ struct netlbl_dom_map;
|
|||
/* Domain mapping operations */
|
||||
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 {
|
||||
atomic_t refcount;
|
||||
void (*free) (const 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!)
|
||||
* should be used when changing these values as the LSM implementation
|
||||
* probably has functions which rely on the sizes of these types to speed
|
||||
* processing. */
|
||||
* processing.
|
||||
*
|
||||
*/
|
||||
#define NETLBL_CATMAP_MAPTYPE u64
|
||||
#define NETLBL_CATMAP_MAPCNT 4
|
||||
#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];
|
||||
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_DOMAIN 0x00000001
|
||||
#define NETLBL_SECATTR_CACHE 0x00000002
|
||||
#define NETLBL_SECATTR_MLS_LVL 0x00000004
|
||||
#define NETLBL_SECATTR_MLS_CAT 0x00000008
|
||||
#define NETLBL_SECATTR_SECID 0x00000010
|
||||
#define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \
|
||||
NETLBL_SECATTR_MLS_CAT)
|
||||
NETLBL_SECATTR_MLS_CAT | \
|
||||
NETLBL_SECATTR_SECID)
|
||||
struct netlbl_lsm_secattr {
|
||||
u32 flags;
|
||||
|
||||
u32 type;
|
||||
char *domain;
|
||||
|
||||
u32 mls_lvl;
|
||||
struct netlbl_lsm_secattr_catmap *mls_cat;
|
||||
|
||||
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)
|
||||
{
|
||||
secattr->flags = 0;
|
||||
secattr->domain = NULL;
|
||||
secattr->mls_cat = NULL;
|
||||
secattr->cache = NULL;
|
||||
memset(secattr, 0, sizeof(*secattr));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -248,11 +307,11 @@ static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
|
|||
*/
|
||||
static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if (secattr->cache)
|
||||
netlbl_secattr_cache_free(secattr->cache);
|
||||
kfree(secattr->domain);
|
||||
if (secattr->mls_cat)
|
||||
netlbl_secattr_catmap_free(secattr->mls_cat);
|
||||
if (secattr->flags & NETLBL_SECATTR_CACHE)
|
||||
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);
|
||||
|
||||
/*
|
||||
* LSM protocol operations
|
||||
* LSM protocol operations (NetLabel LSM/kernel API)
|
||||
*/
|
||||
int netlbl_enabled(void);
|
||||
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,
|
||||
struct netlbl_lsm_secattr *secattr);
|
||||
int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct netlbl_lsm_secattr *secattr);
|
||||
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;
|
||||
}
|
||||
static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
return -ENOSYS;
|
||||
|
|
|
@ -348,6 +348,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
|
|||
atomic_inc(&entry->lsm_data->refcount);
|
||||
secattr->cache = entry->lsm_data;
|
||||
secattr->flags |= NETLBL_SECATTR_CACHE;
|
||||
secattr->type = NETLBL_NLTYPE_CIPSOV4;
|
||||
if (prev_entry == NULL) {
|
||||
spin_unlock_bh(&cipso_v4_cache[bkt].lock);
|
||||
return 0;
|
||||
|
@ -865,7 +866,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
|
|||
}
|
||||
|
||||
for (;;) {
|
||||
host_spot = netlbl_secattr_catmap_walk(secattr->mls_cat,
|
||||
host_spot = netlbl_secattr_catmap_walk(secattr->attr.mls.cat,
|
||||
host_spot + 1);
|
||||
if (host_spot < 0)
|
||||
break;
|
||||
|
@ -948,7 +949,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
|
|||
return -EPERM;
|
||||
break;
|
||||
}
|
||||
ret_val = netlbl_secattr_catmap_setbit(secattr->mls_cat,
|
||||
ret_val = netlbl_secattr_catmap_setbit(secattr->attr.mls.cat,
|
||||
host_spot,
|
||||
GFP_ATOMIC);
|
||||
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;
|
||||
|
||||
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)
|
||||
break;
|
||||
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;
|
||||
|
||||
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])),
|
||||
GFP_ATOMIC);
|
||||
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;
|
||||
|
||||
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)
|
||||
break;
|
||||
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;
|
||||
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)
|
||||
return -EFAULT;
|
||||
cat_size += sizeof(u16);
|
||||
|
@ -1191,7 +1195,7 @@ static int cipso_v4_map_cat_rng_ntoh(const struct cipso_v4_doi *doi_def,
|
|||
else
|
||||
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_high,
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
secattr->mls_lvl = level;
|
||||
secattr->attr.mls.lvl = level;
|
||||
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
|
||||
|
||||
if (tag_len > 4) {
|
||||
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
|
||||
if (secattr->mls_cat == NULL)
|
||||
secattr->attr.mls.cat =
|
||||
netlbl_secattr_catmap_alloc(GFP_ATOMIC);
|
||||
if (secattr->attr.mls.cat == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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,
|
||||
secattr);
|
||||
if (ret_val != 0) {
|
||||
netlbl_secattr_catmap_free(secattr->mls_cat);
|
||||
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
|
||||
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))
|
||||
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)
|
||||
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);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
secattr->mls_lvl = level;
|
||||
secattr->attr.mls.lvl = level;
|
||||
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
|
||||
|
||||
if (tag_len > 4) {
|
||||
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
|
||||
if (secattr->mls_cat == NULL)
|
||||
secattr->attr.mls.cat =
|
||||
netlbl_secattr_catmap_alloc(GFP_ATOMIC);
|
||||
if (secattr->attr.mls.cat == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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,
|
||||
secattr);
|
||||
if (ret_val != 0) {
|
||||
netlbl_secattr_catmap_free(secattr->mls_cat);
|
||||
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
|
||||
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))
|
||||
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)
|
||||
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);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
secattr->mls_lvl = level;
|
||||
secattr->attr.mls.lvl = level;
|
||||
secattr->flags |= NETLBL_SECATTR_MLS_LVL;
|
||||
|
||||
if (tag_len > 4) {
|
||||
secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);
|
||||
if (secattr->mls_cat == NULL)
|
||||
secattr->attr.mls.cat =
|
||||
netlbl_secattr_catmap_alloc(GFP_ATOMIC);
|
||||
if (secattr->attr.mls.cat == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
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,
|
||||
secattr);
|
||||
if (ret_val != 0) {
|
||||
netlbl_secattr_catmap_free(secattr->mls_cat);
|
||||
netlbl_secattr_catmap_free(secattr->attr.mls.cat);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
if (ret_val == 0)
|
||||
secattr->type = NETLBL_NLTYPE_CIPSOV4;
|
||||
|
||||
getattr_return:
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -72,12 +72,13 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info)
|
|||
return false;
|
||||
}
|
||||
|
||||
err = selinux_relabel_packet_permission(sel->selsid);
|
||||
err = selinux_secmark_relabel_packet_permission(sel->selsid);
|
||||
if (err) {
|
||||
printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
selinux_secmark_refcount_inc();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -110,11 +111,20 @@ secmark_tg_check(const char *tablename, const void *entry,
|
|||
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 = {
|
||||
{
|
||||
.name = "SECMARK",
|
||||
.family = AF_INET,
|
||||
.checkentry = secmark_tg_check,
|
||||
.destroy = secmark_tg_destroy,
|
||||
.target = secmark_tg,
|
||||
.targetsize = sizeof(struct xt_secmark_target_info),
|
||||
.table = "mangle",
|
||||
|
@ -124,6 +134,7 @@ static struct xt_target secmark_tg_reg[] __read_mostly = {
|
|||
.name = "SECMARK",
|
||||
.family = AF_INET6,
|
||||
.checkentry = secmark_tg_check,
|
||||
.destroy = secmark_tg_destroy,
|
||||
.target = secmark_tg,
|
||||
.targetsize = sizeof(struct xt_secmark_target_info),
|
||||
.table = "mangle",
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_cipso_v4.h"
|
||||
|
@ -421,7 +422,7 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
|
|||
break;
|
||||
}
|
||||
if (ret_val == 0)
|
||||
netlbl_mgmt_protocount_inc();
|
||||
atomic_inc(&netlabel_mgmt_protocount);
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
|
||||
&audit_info);
|
||||
|
@ -698,7 +699,7 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
|
|||
&audit_info,
|
||||
netlbl_cipsov4_doi_free);
|
||||
if (ret_val == 0)
|
||||
netlbl_mgmt_protocount_dec();
|
||||
atomic_dec(&netlabel_mgmt_protocount);
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
|
||||
&audit_info);
|
||||
|
|
|
@ -54,9 +54,6 @@ struct netlbl_domhsh_tbl {
|
|||
* hash table should be okay */
|
||||
static DEFINE_SPINLOCK(netlbl_domhsh_lock);
|
||||
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;
|
||||
|
||||
/*
|
||||
|
@ -109,17 +106,14 @@ static u32 netlbl_domhsh_hash(const char *key)
|
|||
/**
|
||||
* netlbl_domhsh_search - 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 found, otherwise NULL is returned. If @def is non-zero and a
|
||||
* match is not found in the domain hash table the default mapping is returned
|
||||
* if it exists. The caller is responsibile for the rcu hash table locks
|
||||
* (i.e. the caller much call rcu_read_[un]lock()).
|
||||
* entry if found, 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(const char *domain, u32 def)
|
||||
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
|
||||
{
|
||||
u32 bkt;
|
||||
struct netlbl_dom_map *iter;
|
||||
|
@ -133,10 +127,31 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def)
|
|||
return iter;
|
||||
}
|
||||
|
||||
if (def != 0) {
|
||||
iter = rcu_dereference(netlbl_domhsh_def);
|
||||
if (iter != NULL && iter->valid)
|
||||
return iter;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
@ -221,24 +236,22 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
|||
INIT_RCU_HEAD(&entry->rcu);
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->domain != NULL) {
|
||||
bkt = netlbl_domhsh_hash(entry->domain);
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (netlbl_domhsh_search(entry->domain, 0) == NULL)
|
||||
if (netlbl_domhsh_search(entry->domain) == NULL)
|
||||
list_add_tail_rcu(&entry->list,
|
||||
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
|
||||
else
|
||||
ret_val = -EEXIST;
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
} else {
|
||||
INIT_LIST_HEAD(&entry->list);
|
||||
spin_lock(&netlbl_domhsh_def_lock);
|
||||
if (rcu_dereference(netlbl_domhsh_def) == NULL)
|
||||
rcu_assign_pointer(netlbl_domhsh_def, entry);
|
||||
else
|
||||
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);
|
||||
if (audit_buf != NULL) {
|
||||
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;
|
||||
|
||||
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)
|
||||
goto remove_return;
|
||||
switch (entry->type) {
|
||||
|
@ -316,23 +332,16 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
|
|||
entry->domain);
|
||||
break;
|
||||
}
|
||||
if (entry != rcu_dereference(netlbl_domhsh_def)) {
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
if (entry != rcu_dereference(netlbl_domhsh_def))
|
||||
list_del_rcu(&entry->list);
|
||||
ret_val = 0;
|
||||
}
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
} else {
|
||||
spin_lock(&netlbl_domhsh_def_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
else
|
||||
rcu_assign_pointer(netlbl_domhsh_def, NULL);
|
||||
ret_val = 0;
|
||||
}
|
||||
spin_unlock(&netlbl_domhsh_def_lock);
|
||||
ret_val = 0;
|
||||
}
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
|
||||
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)
|
||||
{
|
||||
return netlbl_domhsh_search(domain, 1);
|
||||
return netlbl_domhsh_search_def(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "netlabel_domainhash.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
|
||||
* as well so that admins can toggle NetLabel regardless of the
|
||||
* configuration */
|
||||
return (netlbl_mgmt_protocount_value() > 0 ? 1 : 0);
|
||||
return (atomic_read(&netlabel_mgmt_protocount) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -311,7 +312,7 @@ socket_setattr_return:
|
|||
* @secattr: the security attributes
|
||||
*
|
||||
* 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
|
||||
* security attributes in @secattr. Returns zero on success, negative values
|
||||
* on failure.
|
||||
|
@ -319,18 +320,13 @@ socket_setattr_return:
|
|||
*/
|
||||
int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = cipso_v4_sock_getattr(sk, secattr);
|
||||
if (ret_val == 0)
|
||||
return 0;
|
||||
|
||||
return netlbl_unlabel_getattr(secattr);
|
||||
return cipso_v4_sock_getattr(sk, secattr);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_skbuff_getattr - Determine the security attributes of a packet
|
||||
* @skb: the packet
|
||||
* @family: protocol family
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* 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,
|
||||
u16 family,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if (CIPSO_V4_OPTEXIST(skb) &&
|
||||
cipso_v4_skbuff_getattr(skb, secattr) == 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)
|
||||
goto init_failure;
|
||||
|
||||
ret_val = netlbl_unlabel_init(NETLBL_UNLHSH_BITSIZE);
|
||||
if (ret_val != 0)
|
||||
goto init_failure;
|
||||
|
||||
ret_val = netlbl_netlink_init();
|
||||
if (ret_val != 0)
|
||||
goto init_failure;
|
||||
|
|
|
@ -37,14 +37,14 @@
|
|||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_mgmt.h"
|
||||
|
||||
/* NetLabel configured protocol count */
|
||||
static DEFINE_SPINLOCK(netlabel_mgmt_protocount_lock);
|
||||
static u32 netlabel_mgmt_protocount = 0;
|
||||
/* NetLabel configured protocol counter */
|
||||
atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
|
||||
|
||||
/* Argument struct for netlbl_domhsh_walk() */
|
||||
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 },
|
||||
};
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#define _NETLABEL_MGMT_H
|
||||
|
||||
#include <net/netlabel.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
/*
|
||||
* The following NetLabel payloads are supported by the management interface.
|
||||
|
@ -168,9 +169,7 @@ enum {
|
|||
/* NetLabel protocol functions */
|
||||
int netlbl_mgmt_genl_init(void);
|
||||
|
||||
/* NetLabel misc management functions */
|
||||
void netlbl_mgmt_protocount_inc(void);
|
||||
void netlbl_mgmt_protocount_dec(void);
|
||||
u32 netlbl_mgmt_protocount_value(void);
|
||||
/* NetLabel configured protocol reference counter */
|
||||
extern atomic_t netlabel_mgmt_protocount;
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,6 +36,116 @@
|
|||
/*
|
||||
* 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
|
||||
* 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
|
||||
|
@ -62,6 +172,12 @@ enum {
|
|||
NLBL_UNLABEL_C_UNSPEC,
|
||||
NLBL_UNLABEL_C_ACCEPT,
|
||||
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,
|
||||
};
|
||||
#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
|
||||
|
@ -73,6 +189,24 @@ enum {
|
|||
/* (NLA_U8)
|
||||
* if true then unlabeled packets are allowed to pass, else unlabeled
|
||||
* 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,
|
||||
};
|
||||
#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
|
||||
|
@ -80,8 +214,17 @@ enum {
|
|||
/* NetLabel protocol functions */
|
||||
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 */
|
||||
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 */
|
||||
int netlbl_unlabel_defconf(void);
|
||||
|
|
|
@ -76,6 +76,7 @@ config SECURITY_NETWORK_XFRM
|
|||
config SECURITY_CAPABILITIES
|
||||
bool "Default Linux Capabilities"
|
||||
depends on SECURITY
|
||||
default y
|
||||
help
|
||||
This enables the "default" Linux capabilities functionality.
|
||||
If you are unsure how to answer this question, answer Y.
|
||||
|
|
|
@ -145,7 +145,7 @@ config SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
|||
config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||
int "NSA SELinux maximum supported policy format version value"
|
||||
depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
range 15 21
|
||||
range 15 22
|
||||
default 19
|
||||
help
|
||||
This option sets the value for the maximum policy format version
|
||||
|
|
|
@ -4,7 +4,14 @@
|
|||
|
||||
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
|
||||
|
||||
|
|
|
@ -661,9 +661,18 @@ void avc_audit(u32 ssid, u32 tsid,
|
|||
"daddr", "dest");
|
||||
break;
|
||||
}
|
||||
if (a->u.net.netif)
|
||||
audit_log_format(ab, " netif=%s",
|
||||
a->u.net.netif);
|
||||
if (a->u.net.netif > 0) {
|
||||
struct net_device *dev;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,10 +17,14 @@
|
|||
#include <linux/selinux.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/ipc.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "security.h"
|
||||
#include "objsec.h"
|
||||
|
||||
/* SECMARK reference count */
|
||||
extern atomic_t selinux_secmark_refcount;
|
||||
|
||||
int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
|
||||
{
|
||||
if (selinux_enabled)
|
||||
|
@ -74,7 +78,7 @@ int selinux_string_to_sid(char *str, u32 *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) {
|
||||
struct task_security_struct *tsec = current->security;
|
||||
|
@ -84,4 +88,16 @@ int selinux_relabel_packet_permission(u32 sid)
|
|||
}
|
||||
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);
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
||||
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
|
||||
* <dgoeddel@trustedcs.com>
|
||||
* Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
|
||||
* Paul Moore, <paul.moore@hp.com>
|
||||
* Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
|
||||
* Paul Moore <paul.moore@hp.com>
|
||||
* Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
|
||||
* Yuichi Nakamura <ynakam@hitachisoft.jp>
|
||||
*
|
||||
|
@ -50,8 +50,11 @@
|
|||
#include <net/icmp.h>
|
||||
#include <net/ip.h> /* for local_port_range[] */
|
||||
#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/ioctls.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/netdevice.h> /* for network interface checks */
|
||||
|
@ -76,6 +79,7 @@
|
|||
#include "avc.h"
|
||||
#include "objsec.h"
|
||||
#include "netif.h"
|
||||
#include "netnode.h"
|
||||
#include "xfrm.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 struct security_operations *security_ops;
|
||||
|
||||
/* SECMARK reference count */
|
||||
atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
|
||||
|
||||
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
|
||||
int selinux_enforcing = 0;
|
||||
|
||||
|
@ -155,6 +162,21 @@ getsecurity_exit:
|
|||
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. */
|
||||
|
||||
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
|
||||
* labeling information.
|
||||
*/
|
||||
int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
|
||||
int *flags, int num_opts)
|
||||
static int selinux_set_mnt_opts(struct super_block *sb, char **mount_options,
|
||||
int *flags, int num_opts)
|
||||
{
|
||||
int rc = 0, i;
|
||||
struct task_security_struct *tsec = current->security;
|
||||
|
@ -3395,7 +3417,7 @@ out:
|
|||
#endif /* IPV6 */
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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);
|
||||
if (ret || !addrp)
|
||||
break;
|
||||
*len = 4;
|
||||
*addrp = (char *)(src ? &ad->u.net.v4info.saddr :
|
||||
&ad->u.net.v4info.daddr);
|
||||
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);
|
||||
if (ret || !addrp)
|
||||
break;
|
||||
*len = 16;
|
||||
*addrp = (char *)(src ? &ad->u.net.v6info.saddr :
|
||||
&ad->u.net.v6info.daddr);
|
||||
break;
|
||||
|
@ -3423,36 +3443,48 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
|
|||
break;
|
||||
}
|
||||
|
||||
if (unlikely(ret))
|
||||
printk(KERN_WARNING
|
||||
"SELinux: failure in selinux_parse_skb(),"
|
||||
" unable to parse packet\n");
|
||||
|
||||
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
|
||||
* @sid: the packet's SID
|
||||
* @family: protocol family
|
||||
* @sid: the packet's peer label SID
|
||||
*
|
||||
* Description:
|
||||
* Check the various different forms of external packet labeling and determine
|
||||
* the external SID for the packet. If only one form of external labeling is
|
||||
* present then it is used, if both labeled IPsec and NetLabel labels are
|
||||
* present then the SELinux type information is taken from the labeled IPsec
|
||||
* SA and the MLS sensitivity label information is taken from the NetLabel
|
||||
* security attributes. This bit of "magic" is done in the call to
|
||||
* selinux_netlbl_skbuff_getsid().
|
||||
* Check the various different forms of network peer labeling and determine
|
||||
* the peer label/SID for the packet; most of the magic actually occurs in
|
||||
* the security server function security_net_peersid_cmp(). The function
|
||||
* returns zero if the value in @sid is valid (although it may be SECSID_NULL)
|
||||
* or -EACCES if @sid is invalid due to inconsistencies with the different
|
||||
* peer labels.
|
||||
*
|
||||
*/
|
||||
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 nlbl_sid;
|
||||
u32 nlbl_type;
|
||||
|
||||
selinux_skb_xfrm_sid(skb, &xfrm_sid);
|
||||
if (selinux_netlbl_skbuff_getsid(skb,
|
||||
(xfrm_sid == SECSID_NULL ?
|
||||
SECINITSID_NETMSG : xfrm_sid),
|
||||
&nlbl_sid) != 0)
|
||||
nlbl_sid = SECSID_NULL;
|
||||
*sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid);
|
||||
selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
|
||||
|
||||
err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
|
||||
if (unlikely(err)) {
|
||||
printk(KERN_WARNING
|
||||
"SELinux: failure in selinux_skb_peerlbl_sid(),"
|
||||
" unable to determine packet's peer label\n");
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* socket security operations */
|
||||
|
@ -3518,6 +3550,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
|
|||
if (sock->sk) {
|
||||
sksec = sock->sk->sk_security;
|
||||
sksec->sid = isec->sid;
|
||||
sksec->sclass = isec->sclass;
|
||||
err = selinux_netlbl_socket_post_create(sock);
|
||||
}
|
||||
|
||||
|
@ -3610,7 +3643,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
|
|||
break;
|
||||
}
|
||||
|
||||
err = security_node_sid(family, addrp, addrlen, &sid);
|
||||
err = sel_netnode_sid(addrp, family, &sid);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
@ -3821,131 +3854,182 @@ static int selinux_socket_unix_may_send(struct socket *sock,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
||||
struct avc_audit_data *ad, u16 family, char *addrp, int len)
|
||||
static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
|
||||
u32 peer_sid,
|
||||
struct avc_audit_data *ad)
|
||||
{
|
||||
int err = 0;
|
||||
u32 netif_perm, node_perm, node_sid, if_sid, recv_perm = 0;
|
||||
struct socket *sock;
|
||||
u16 sock_class = 0;
|
||||
u32 sock_sid = 0;
|
||||
int err;
|
||||
u32 if_sid;
|
||||
u32 node_sid;
|
||||
|
||||
read_lock_bh(&sk->sk_callback_lock);
|
||||
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);
|
||||
err = sel_netif_sid(ifindex, &if_sid);
|
||||
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:
|
||||
netif_perm = NETIF__UDP_RECV;
|
||||
node_perm = NODE__UDP_RECV;
|
||||
recv_perm = UDP_SOCKET__RECV_MSG;
|
||||
break;
|
||||
|
||||
case SECCLASS_TCP_SOCKET:
|
||||
netif_perm = NETIF__TCP_RECV;
|
||||
node_perm = NODE__TCP_RECV;
|
||||
recv_perm = TCP_SOCKET__RECV_MSG;
|
||||
break;
|
||||
|
||||
case SECCLASS_DCCP_SOCKET:
|
||||
netif_perm = NETIF__DCCP_RECV;
|
||||
node_perm = NODE__DCCP_RECV;
|
||||
recv_perm = DCCP_SOCKET__RECV_MSG;
|
||||
break;
|
||||
|
||||
default:
|
||||
netif_perm = NETIF__RAWIP_RECV;
|
||||
node_perm = NODE__RAWIP_RECV;
|
||||
recv_perm = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
err = avc_has_perm(sock_sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
|
||||
err = sel_netif_sid(skb->iif, &if_sid);
|
||||
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)
|
||||
goto out;
|
||||
|
||||
err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, ad);
|
||||
return err;
|
||||
err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
if (recv_perm) {
|
||||
u32 port_sid;
|
||||
if (!recv_perm)
|
||||
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,
|
||||
sk->sk_protocol, ntohs(ad->u.net.sport),
|
||||
&port_sid);
|
||||
static int selinux_sock_rcv_skb_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;
|
||||
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)
|
||||
goto out;
|
||||
|
||||
err = avc_has_perm(sock_sid, port_sid,
|
||||
sock_class, recv_perm, ad);
|
||||
return err;
|
||||
err = avc_has_perm(sk_sid, peer_sid,
|
||||
SECCLASS_PEER, PEER__RECV, 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;
|
||||
}
|
||||
|
||||
static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
u16 family;
|
||||
char *addrp;
|
||||
int len, err = 0;
|
||||
struct avc_audit_data ad;
|
||||
int err;
|
||||
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)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
/* Handle mapped IPv4 packets arriving via IPv6 sockets */
|
||||
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
|
||||
family = PF_INET;
|
||||
|
||||
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;
|
||||
|
||||
err = selinux_parse_skb(skb, &ad, &addrp, &len, 1, NULL);
|
||||
err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
if (selinux_compat_net)
|
||||
err = selinux_sock_rcv_skb_compat(sk, skb, &ad, family,
|
||||
addrp, len);
|
||||
else
|
||||
err = avc_has_perm(sksec->sid, skb->secmark, SECCLASS_PACKET,
|
||||
/* If any sort of compatibility mode is enabled then handoff processing
|
||||
* to the selinux_sock_rcv_skb_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_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);
|
||||
if (err)
|
||||
goto out;
|
||||
if (err)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -3996,18 +4080,25 @@ out:
|
|||
static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
|
||||
{
|
||||
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);
|
||||
else if (skb)
|
||||
selinux_skb_extlbl_sid(skb, &peer_secid);
|
||||
selinux_skb_peerlbl_sid(skb, family, &peer_secid);
|
||||
|
||||
if (peer_secid == SECSID_NULL)
|
||||
err = -EINVAL;
|
||||
out:
|
||||
*secid = peer_secid;
|
||||
|
||||
return err;
|
||||
if (peer_secid == SECSID_NULL)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->peer_sid = ssec->peer_sid;
|
||||
newssec->sclass = ssec->sclass;
|
||||
|
||||
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 ||
|
||||
sk->sk_family == PF_UNIX)
|
||||
isec->sid = sksec->sid;
|
||||
sksec->sclass = isec->sclass;
|
||||
|
||||
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 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) {
|
||||
req->secid = sksec->sid;
|
||||
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;
|
||||
|
||||
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,
|
||||
|
@ -4147,149 +4242,260 @@ out:
|
|||
|
||||
#ifdef CONFIG_NETFILTER
|
||||
|
||||
static int selinux_ip_postroute_last_compat(struct sock *sk, struct net_device *dev,
|
||||
struct avc_audit_data *ad,
|
||||
u16 family, char *addrp, int len)
|
||||
static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
|
||||
u16 family)
|
||||
{
|
||||
int err = 0;
|
||||
u32 netif_perm, node_perm, node_sid, if_sid, send_perm = 0;
|
||||
struct socket *sock;
|
||||
struct inode *inode;
|
||||
struct inode_security_struct *isec;
|
||||
char *addrp;
|
||||
u32 peer_sid;
|
||||
struct avc_audit_data ad;
|
||||
u8 secmark_active;
|
||||
u8 peerlbl_active;
|
||||
|
||||
sock = sk->sk_socket;
|
||||
if (!sock)
|
||||
goto out;
|
||||
if (!selinux_policycap_netpeer)
|
||||
return NF_ACCEPT;
|
||||
|
||||
inode = SOCK_INODE(sock);
|
||||
if (!inode)
|
||||
goto out;
|
||||
secmark_active = selinux_secmark_enabled();
|
||||
peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
|
||||
if (!secmark_active && !peerlbl_active)
|
||||
return NF_ACCEPT;
|
||||
|
||||
isec = inode->i_security;
|
||||
|
||||
err = sel_netif_sids(dev, &if_sid, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
AVC_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.u.net.netif = ifindex;
|
||||
ad.u.net.family = family;
|
||||
if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
|
||||
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:
|
||||
netif_perm = NETIF__UDP_SEND;
|
||||
node_perm = NODE__UDP_SEND;
|
||||
send_perm = UDP_SOCKET__SEND_MSG;
|
||||
break;
|
||||
|
||||
case SECCLASS_TCP_SOCKET:
|
||||
netif_perm = NETIF__TCP_SEND;
|
||||
node_perm = NODE__TCP_SEND;
|
||||
send_perm = TCP_SOCKET__SEND_MSG;
|
||||
break;
|
||||
|
||||
case SECCLASS_DCCP_SOCKET:
|
||||
netif_perm = NETIF__DCCP_SEND;
|
||||
node_perm = NODE__DCCP_SEND;
|
||||
send_perm = DCCP_SOCKET__SEND_MSG;
|
||||
break;
|
||||
|
||||
default:
|
||||
netif_perm = NETIF__RAWIP_SEND;
|
||||
node_perm = NODE__RAWIP_SEND;
|
||||
send_perm = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
err = avc_has_perm(isec->sid, if_sid, SECCLASS_NETIF, netif_perm, ad);
|
||||
err = sel_netif_sid(ifindex, &if_sid);
|
||||
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)
|
||||
goto out;
|
||||
|
||||
err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, ad);
|
||||
return err;
|
||||
err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad);
|
||||
if (err)
|
||||
goto out;
|
||||
return err;
|
||||
|
||||
if (send_perm) {
|
||||
u32 port_sid;
|
||||
|
||||
err = security_port_sid(sk->sk_family,
|
||||
sk->sk_type,
|
||||
sk->sk_protocol,
|
||||
ntohs(ad->u.net.dport),
|
||||
&port_sid);
|
||||
if (err)
|
||||
goto out;
|
||||
if (send_perm != 0)
|
||||
return 0;
|
||||
|
||||
err = avc_has_perm(isec->sid, port_sid, isec->sclass,
|
||||
send_perm, ad);
|
||||
err = security_port_sid(sk->sk_family, sk->sk_type,
|
||||
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 err;
|
||||
return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad);
|
||||
}
|
||||
|
||||
static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *),
|
||||
u16 family)
|
||||
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
||||
int ifindex,
|
||||
struct avc_audit_data *ad,
|
||||
u16 family,
|
||||
char *addrp,
|
||||
u8 proto)
|
||||
{
|
||||
char *addrp;
|
||||
int len, err = 0;
|
||||
struct sock *sk;
|
||||
struct avc_audit_data ad;
|
||||
struct net_device *dev = (struct net_device *)out;
|
||||
struct sock *sk = skb->sk;
|
||||
struct sk_security_struct *sksec;
|
||||
u8 proto;
|
||||
|
||||
sk = skb->sk;
|
||||
if (!sk)
|
||||
goto out;
|
||||
|
||||
if (sk == NULL)
|
||||
return NF_ACCEPT;
|
||||
sksec = sk->sk_security;
|
||||
|
||||
AVC_AUDIT_DATA_INIT(&ad, NET);
|
||||
ad.u.net.netif = dev->name;
|
||||
ad.u.net.family = family;
|
||||
if (selinux_compat_net) {
|
||||
if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
|
||||
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 (err)
|
||||
goto out;
|
||||
if (selinux_policycap_netpeer)
|
||||
if (selinux_xfrm_postroute_last(sksec->sid, skb, ad, proto))
|
||||
return NF_DROP;
|
||||
|
||||
if (selinux_compat_net)
|
||||
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;
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static unsigned int selinux_ipv4_postroute_last(unsigned int hooknum,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
|
||||
u16 family)
|
||||
{
|
||||
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)
|
||||
|
||||
static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
|
||||
struct sk_buff *skb,
|
||||
const struct net_device *in,
|
||||
const struct net_device *out,
|
||||
int (*okfn)(struct sk_buff *))
|
||||
static unsigned int selinux_ipv6_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_last(hooknum, skb, in, out, okfn, PF_INET6);
|
||||
return selinux_ip_postroute(skb, out->ifindex, PF_INET6);
|
||||
}
|
||||
|
||||
#endif /* IPV6 */
|
||||
|
||||
#endif /* CONFIG_NETFILTER */
|
||||
|
@ -5277,22 +5483,40 @@ security_initcall(selinux_init);
|
|||
|
||||
#if defined(CONFIG_NETFILTER)
|
||||
|
||||
static struct nf_hook_ops selinux_ipv4_op = {
|
||||
.hook = selinux_ipv4_postroute_last,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.hooknum = NF_INET_POST_ROUTING,
|
||||
.priority = NF_IP_PRI_SELINUX_LAST,
|
||||
static struct nf_hook_ops selinux_ipv4_ops[] = {
|
||||
{
|
||||
.hook = selinux_ipv4_postroute,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET,
|
||||
.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)
|
||||
|
||||
static struct nf_hook_ops selinux_ipv6_op = {
|
||||
.hook = selinux_ipv6_postroute_last,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET6,
|
||||
.hooknum = NF_INET_POST_ROUTING,
|
||||
.priority = NF_IP6_PRI_SELINUX_LAST,
|
||||
static struct nf_hook_ops selinux_ipv6_ops[] = {
|
||||
{
|
||||
.hook = selinux_ipv6_postroute,
|
||||
.owner = THIS_MODULE,
|
||||
.pf = PF_INET6,
|
||||
.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 */
|
||||
|
@ -5300,22 +5524,27 @@ static struct nf_hook_ops selinux_ipv6_op = {
|
|||
static int __init selinux_nf_ip_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
u32 iter;
|
||||
|
||||
if (!selinux_enabled)
|
||||
goto out;
|
||||
|
||||
printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n");
|
||||
|
||||
err = nf_register_hook(&selinux_ipv4_op);
|
||||
if (err)
|
||||
panic("SELinux: nf_register_hook for IPv4: error %d\n", err);
|
||||
for (iter = 0; iter < ARRAY_SIZE(selinux_ipv4_ops); iter++) {
|
||||
err = nf_register_hook(&selinux_ipv4_ops[iter]);
|
||||
if (err)
|
||||
panic("SELinux: nf_register_hook for IPv4: error %d\n",
|
||||
err);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
|
||||
err = nf_register_hook(&selinux_ipv6_op);
|
||||
if (err)
|
||||
panic("SELinux: nf_register_hook for IPv6: error %d\n", err);
|
||||
|
||||
for (iter = 0; iter < ARRAY_SIZE(selinux_ipv6_ops); iter++) {
|
||||
err = nf_register_hook(&selinux_ipv6_ops[iter]);
|
||||
if (err)
|
||||
panic("SELinux: nf_register_hook for IPv6: error %d\n",
|
||||
err);
|
||||
}
|
||||
#endif /* IPV6 */
|
||||
|
||||
out:
|
||||
|
@ -5327,11 +5556,15 @@ __initcall(selinux_nf_ip_init);
|
|||
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
|
||||
static void selinux_nf_ip_exit(void)
|
||||
{
|
||||
u32 iter;
|
||||
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
S_(SECCLASS_NODE, NODE__ENFORCE_DEST, "enforce_dest")
|
||||
S_(SECCLASS_NODE, NODE__DCCP_RECV, "dccp_recv")
|
||||
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_SEND, "tcp_send")
|
||||
S_(SECCLASS_NETIF, NETIF__UDP_RECV, "udp_recv")
|
||||
|
@ -45,6 +47,8 @@
|
|||
S_(SECCLASS_NETIF, NETIF__RAWIP_SEND, "rawip_send")
|
||||
S_(SECCLASS_NETIF, NETIF__DCCP_RECV, "dccp_recv")
|
||||
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__NEWCONN, "newconn")
|
||||
S_(SECCLASS_UNIX_STREAM_SOCKET, UNIX_STREAM_SOCKET__ACCEPTFROM, "acceptfrom")
|
||||
|
@ -149,6 +153,10 @@
|
|||
S_(SECCLASS_PACKET, PACKET__SEND, "send")
|
||||
S_(SECCLASS_PACKET, PACKET__RECV, "recv")
|
||||
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__READ, "read")
|
||||
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__NAME_CONNECT, "name_connect")
|
||||
S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
|
||||
S_(SECCLASS_PEER, PEER__RECV, "recv")
|
||||
|
|
|
@ -292,6 +292,8 @@
|
|||
#define NODE__ENFORCE_DEST 0x00000040UL
|
||||
#define NODE__DCCP_RECV 0x00000080UL
|
||||
#define NODE__DCCP_SEND 0x00000100UL
|
||||
#define NODE__RECVFROM 0x00000200UL
|
||||
#define NODE__SENDTO 0x00000400UL
|
||||
#define NETIF__TCP_RECV 0x00000001UL
|
||||
#define NETIF__TCP_SEND 0x00000002UL
|
||||
#define NETIF__UDP_RECV 0x00000004UL
|
||||
|
@ -300,6 +302,8 @@
|
|||
#define NETIF__RAWIP_SEND 0x00000020UL
|
||||
#define NETIF__DCCP_RECV 0x00000040UL
|
||||
#define NETIF__DCCP_SEND 0x00000080UL
|
||||
#define NETIF__INGRESS 0x00000100UL
|
||||
#define NETIF__EGRESS 0x00000200UL
|
||||
#define NETLINK_SOCKET__IOCTL 0x00000001UL
|
||||
#define NETLINK_SOCKET__READ 0x00000002UL
|
||||
#define NETLINK_SOCKET__WRITE 0x00000004UL
|
||||
|
@ -792,6 +796,10 @@
|
|||
#define PACKET__SEND 0x00000001UL
|
||||
#define PACKET__RECV 0x00000002UL
|
||||
#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__READ 0x00000002UL
|
||||
#define KEY__WRITE 0x00000004UL
|
||||
|
@ -824,3 +832,4 @@
|
|||
#define DCCP_SOCKET__NODE_BIND 0x00400000UL
|
||||
#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL
|
||||
#define MEMPROTECT__MMAP_ZERO 0x00000001UL
|
||||
#define PEER__RECV 0x00000001UL
|
||||
|
|
|
@ -51,7 +51,7 @@ struct avc_audit_data {
|
|||
struct inode *inode;
|
||||
} fs;
|
||||
struct {
|
||||
char *netif;
|
||||
int netif;
|
||||
struct sock *sk;
|
||||
u16 family;
|
||||
__be16 dport;
|
||||
|
|
|
@ -64,3 +64,10 @@
|
|||
S_(NULL)
|
||||
S_("dccp_socket")
|
||||
S_("memprotect")
|
||||
S_(NULL)
|
||||
S_(NULL)
|
||||
S_(NULL)
|
||||
S_(NULL)
|
||||
S_(NULL)
|
||||
S_(NULL)
|
||||
S_("peer")
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define SECCLASS_KEY 58
|
||||
#define SECCLASS_DCCP_SOCKET 60
|
||||
#define SECCLASS_MEMPROTECT 61
|
||||
#define SECCLASS_PEER 68
|
||||
|
||||
/*
|
||||
* Security identifier indices for initial entities
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* Author: 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
|
||||
* it under the terms of the GNU General Public License version 2,
|
||||
|
@ -15,7 +17,7 @@
|
|||
#ifndef _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_ */
|
||||
|
||||
|
|
|
@ -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,
|
||||
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);
|
||||
int selinux_netlbl_socket_post_create(struct socket *sock);
|
||||
int selinux_netlbl_inode_permission(struct inode *inode, int mask);
|
||||
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
||||
struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct avc_audit_data *ad);
|
||||
int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
||||
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,
|
||||
u32 base_sid,
|
||||
u16 family,
|
||||
u32 *type,
|
||||
u32 *sid)
|
||||
{
|
||||
*type = NETLBL_NLTYPE_NONE;
|
||||
*sid = SECSID_NULL;
|
||||
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,
|
||||
struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct avc_audit_data *ad)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -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
|
|
@ -96,17 +96,25 @@ struct bprm_security_struct {
|
|||
};
|
||||
|
||||
struct netif_security_struct {
|
||||
struct net_device *dev; /* back pointer */
|
||||
u32 if_sid; /* SID for this interface */
|
||||
u32 msg_sid; /* default SID for messages received on this interface */
|
||||
int ifindex; /* device index */
|
||||
u32 sid; /* SID for 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 sock *sk; /* back pointer to sk object */
|
||||
u32 sid; /* SID of this object */
|
||||
u32 peer_sid; /* SID of peer */
|
||||
#ifdef CONFIG_NETLABEL
|
||||
u16 sclass; /* sock security class */
|
||||
#ifdef CONFIG_NETLABEL
|
||||
enum { /* NetLabel state */
|
||||
NLBL_UNSET = 0,
|
||||
NLBL_REQUIRE,
|
||||
|
|
|
@ -25,13 +25,14 @@
|
|||
#define POLICYDB_VERSION_MLS 19
|
||||
#define POLICYDB_VERSION_AVTAB 20
|
||||
#define POLICYDB_VERSION_RANGETRANS 21
|
||||
#define POLICYDB_VERSION_POLCAP 22
|
||||
|
||||
/* Range of policy versions we understand*/
|
||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||
#else
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_RANGETRANS
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_POLCAP
|
||||
#endif
|
||||
|
||||
struct netlbl_lsm_secattr;
|
||||
|
@ -39,8 +40,19 @@ struct netlbl_lsm_secattr;
|
|||
extern int selinux_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_policycap_supported(unsigned int req_cap);
|
||||
|
||||
#define SEL_VEC_MAX 32
|
||||
struct av_decision {
|
||||
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,
|
||||
u32 *out_sid);
|
||||
|
||||
int security_netif_sid(char *name, u32 *if_sid,
|
||||
u32 *msg_sid);
|
||||
int security_netif_sid(char *name, u32 *if_sid);
|
||||
|
||||
int security_node_sid(u16 domain, void *addr, u32 addrlen,
|
||||
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_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_permissions(char *class, char ***perms, int *nperms);
|
||||
int security_get_reject_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_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
|
||||
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
||||
u32 base_sid,
|
||||
u32 *sid);
|
||||
|
||||
int security_netlbl_sid_to_secattr(u32 sid,
|
||||
|
@ -116,7 +131,6 @@ int security_netlbl_sid_to_secattr(u32 sid,
|
|||
#else
|
||||
static inline int security_netlbl_secattr_to_sid(
|
||||
struct netlbl_lsm_secattr *secattr,
|
||||
u32 base_sid,
|
||||
u32 *sid)
|
||||
{
|
||||
return -EIDRM;
|
||||
|
|
|
@ -32,6 +32,13 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk)
|
|||
}
|
||||
|
||||
#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,
|
||||
struct avc_audit_data *ad);
|
||||
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);
|
||||
}
|
||||
#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,
|
||||
struct avc_audit_data *ad)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* Author: 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
|
||||
* 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_MAX 1024
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DEBUGP printk
|
||||
#else
|
||||
#define DEBUGP(format, args...)
|
||||
#endif
|
||||
|
||||
struct sel_netif
|
||||
{
|
||||
struct list_head list;
|
||||
|
@ -49,174 +43,226 @@ static LIST_HEAD(sel_netif_list);
|
|||
static DEFINE_SPINLOCK(sel_netif_lock);
|
||||
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
|
||||
* for that case.
|
||||
/**
|
||||
* sel_netif_find - Search for an interface record
|
||||
* @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_hasfn(dev);
|
||||
int idx = sel_netif_hashfn(ifindex);
|
||||
struct sel_netif *netif;
|
||||
|
||||
__list_for_each_rcu(pos, &sel_netif_hash[idx]) {
|
||||
struct sel_netif *netif = list_entry(pos,
|
||||
struct sel_netif, list);
|
||||
if (likely(netif->nsec.dev == dev))
|
||||
list_for_each_entry_rcu(netif, &sel_netif_hash[idx], list)
|
||||
/* all of the devices should normally fit in the hash, so we
|
||||
* optimize for that case */
|
||||
if (likely(netif->nsec.ifindex == ifindex))
|
||||
return netif;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int idx, ret = 0;
|
||||
int idx;
|
||||
|
||||
if (sel_netif_total >= SEL_NETIF_HASH_MAX) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
if (sel_netif_total >= SEL_NETIF_HASH_MAX)
|
||||
return -ENOSPC;
|
||||
|
||||
idx = sel_netif_hasfn(netif->nsec.dev);
|
||||
idx = sel_netif_hashfn(netif->nsec.ifindex);
|
||||
list_add_rcu(&netif->list, &sel_netif_hash[idx]);
|
||||
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)
|
||||
{
|
||||
struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head);
|
||||
|
||||
DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
|
||||
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)
|
||||
{
|
||||
DEBUGP("%s: %s\n", __FUNCTION__, netif->nsec.dev->name);
|
||||
|
||||
list_del_rcu(&netif->list);
|
||||
sel_netif_total--;
|
||||
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;
|
||||
struct sel_netif *netif, *new;
|
||||
struct netif_security_struct *nsec;
|
||||
struct sel_netif *netif;
|
||||
struct sel_netif *new = NULL;
|
||||
struct net_device *dev;
|
||||
|
||||
netif = sel_netif_find(dev);
|
||||
if (likely(netif != NULL))
|
||||
goto out;
|
||||
|
||||
new = kzalloc(sizeof(*new), GFP_ATOMIC);
|
||||
if (!new) {
|
||||
netif = ERR_PTR(-ENOMEM);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nsec = &new->nsec;
|
||||
/* NOTE: we always use init's network namespace since we don't
|
||||
* currently support containers */
|
||||
|
||||
ret = security_netif_sid(dev->name, &nsec->if_sid, &nsec->msg_sid);
|
||||
if (ret < 0) {
|
||||
kfree(new);
|
||||
netif = ERR_PTR(ret);
|
||||
goto out;
|
||||
dev = dev_get_by_index(&init_net, ifindex);
|
||||
if (unlikely(dev == NULL)) {
|
||||
printk(KERN_WARNING
|
||||
"SELinux: failure in sel_netif_sid_slow(),"
|
||||
" invalid network interface (%d)\n", ifindex);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
nsec->dev = dev;
|
||||
|
||||
spin_lock_bh(&sel_netif_lock);
|
||||
|
||||
netif = sel_netif_find(dev);
|
||||
if (netif) {
|
||||
spin_unlock_bh(&sel_netif_lock);
|
||||
kfree(new);
|
||||
netif = sel_netif_find(ifindex);
|
||||
if (netif != NULL) {
|
||||
*sid = netif->nsec.sid;
|
||||
ret = 0;
|
||||
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);
|
||||
spin_unlock_bh(&sel_netif_lock);
|
||||
|
||||
if (ret) {
|
||||
kfree(new);
|
||||
netif = ERR_PTR(ret);
|
||||
if (ret != 0)
|
||||
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:
|
||||
return netif;
|
||||
}
|
||||
|
||||
static void sel_netif_assign_sids(u32 if_sid_in, u32 msg_sid_in, u32 *if_sid_out, u32 *msg_sid_out)
|
||||
{
|
||||
if (if_sid_out)
|
||||
*if_sid_out = if_sid_in;
|
||||
if (msg_sid_out)
|
||||
*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);
|
||||
spin_unlock_bh(&sel_netif_lock);
|
||||
dev_put(dev);
|
||||
if (unlikely(ret)) {
|
||||
printk(KERN_WARNING
|
||||
"SELinux: failure in sel_netif_sid_slow(),"
|
||||
" unable to determine network interface label (%d)\n",
|
||||
ifindex);
|
||||
kfree(new);
|
||||
}
|
||||
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;
|
||||
|
||||
rcu_read_lock();
|
||||
netif = sel_netif_lookup(dev);
|
||||
if (IS_ERR(netif)) {
|
||||
netif = sel_netif_find(ifindex);
|
||||
if (likely(netif != NULL)) {
|
||||
*sid = netif->nsec.sid;
|
||||
rcu_read_unlock();
|
||||
ret = sel_netif_sids_slow(dev, if_sid, msg_sid);
|
||||
goto out;
|
||||
return 0;
|
||||
}
|
||||
sel_netif_assign_sids(netif->nsec.if_sid, netif->nsec.msg_sid, if_sid, msg_sid);
|
||||
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;
|
||||
|
||||
spin_lock_bh(&sel_netif_lock);
|
||||
netif = sel_netif_find(dev);
|
||||
netif = sel_netif_find(ifindex);
|
||||
if (netif)
|
||||
sel_netif_destroy(netif);
|
||||
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)
|
||||
{
|
||||
int idx;
|
||||
struct sel_netif *netif;
|
||||
|
||||
spin_lock_bh(&sel_netif_lock);
|
||||
for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++) {
|
||||
struct sel_netif *netif;
|
||||
|
||||
for (idx = 0; idx < SEL_NETIF_HASH_SIZE; idx++)
|
||||
list_for_each_entry(netif, &sel_netif_hash[idx], list)
|
||||
sel_netif_destroy(netif);
|
||||
}
|
||||
spin_unlock_bh(&sel_netif_lock);
|
||||
}
|
||||
|
||||
|
@ -239,7 +285,7 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this,
|
|||
return NOTIFY_DONE;
|
||||
|
||||
if (event == NETDEV_DOWN)
|
||||
sel_netif_kill(dev);
|
||||
sel_netif_kill(dev->ifindex);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
@ -250,10 +296,10 @@ static struct notifier_block sel_netif_netdev_notifier = {
|
|||
|
||||
static __init int sel_netif_init(void)
|
||||
{
|
||||
int i, err = 0;
|
||||
int i, err;
|
||||
|
||||
if (!selinux_enabled)
|
||||
goto out;
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
|
||||
INIT_LIST_HEAD(&sel_netif_hash[i]);
|
||||
|
@ -265,7 +311,6 @@ static __init int sel_netif_init(void)
|
|||
if (err)
|
||||
panic("avc_add_callback() failed, error %d\n", err);
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,33 @@
|
|||
#include "objsec.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
|
||||
* @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 */
|
||||
rcu_read_lock();
|
||||
selinux_netlbl_sk_security_reset(newssec, ssec->sk->sk_family);
|
||||
newssec->sclass = ssec->sclass;
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
|
||||
* @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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
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);
|
||||
rc = netlbl_skbuff_getattr(skb, &secattr);
|
||||
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) {
|
||||
rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid);
|
||||
if (rc == 0 &&
|
||||
(secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
|
||||
(secattr.flags & NETLBL_SECATTR_CACHE))
|
||||
netlbl_cache_add(skb, &secattr);
|
||||
} else
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
||||
rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
|
||||
else
|
||||
*sid = SECSID_NULL;
|
||||
*type = secattr.type;
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
|
||||
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)
|
||||
{
|
||||
struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
u32 nlbl_peer_sid;
|
||||
|
||||
sksec->sclass = isec->sclass;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
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);
|
||||
if (netlbl_sock_getattr(sk, &secattr) == 0 &&
|
||||
secattr.flags != NETLBL_SECATTR_NONE &&
|
||||
security_netlbl_secattr_to_sid(&secattr,
|
||||
SECINITSID_NETMSG,
|
||||
&nlbl_peer_sid) == 0)
|
||||
security_netlbl_secattr_to_sid(&secattr, &nlbl_peer_sid) == 0)
|
||||
sksec->peer_sid = nlbl_peer_sid;
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
|
||||
|
@ -234,11 +256,8 @@ int selinux_netlbl_socket_post_create(struct socket *sock)
|
|||
{
|
||||
int rc = 0;
|
||||
struct sock *sk = sock->sk;
|
||||
struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
|
||||
sksec->sclass = isec->sclass;
|
||||
|
||||
rcu_read_lock();
|
||||
if (sksec->nlbl_state == NLBL_REQUIRE)
|
||||
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
|
||||
* @sksec: the sock's sk_security_struct
|
||||
* @skb: the packet
|
||||
* @family: protocol family
|
||||
* @ad: the audit data
|
||||
*
|
||||
* 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,
|
||||
struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct avc_audit_data *ad)
|
||||
{
|
||||
int rc;
|
||||
|
@ -313,16 +334,10 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
|||
return 0;
|
||||
|
||||
netlbl_secattr_init(&secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, &secattr);
|
||||
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE) {
|
||||
rc = security_netlbl_secattr_to_sid(&secattr,
|
||||
SECINITSID_NETMSG,
|
||||
&nlbl_sid);
|
||||
if (rc == 0 &&
|
||||
(secattr.flags & NETLBL_SECATTR_CACHEABLE) &&
|
||||
(secattr.flags & NETLBL_SECATTR_CACHE))
|
||||
netlbl_cache_add(skb, &secattr);
|
||||
} else
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
||||
rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
|
||||
else
|
||||
nlbl_sid = SECINITSID_UNLABELED;
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
if (rc != 0)
|
||||
|
|
|
@ -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);
|
|
@ -2,6 +2,11 @@
|
|||
*
|
||||
* 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) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -35,6 +40,11 @@
|
|||
#include "objsec.h"
|
||||
#include "conditional.h"
|
||||
|
||||
/* Policy capability filenames */
|
||||
static char *policycap_names[] = {
|
||||
"network_peer_controls"
|
||||
};
|
||||
|
||||
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
|
||||
|
||||
#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
|
||||
|
@ -72,6 +82,9 @@ static int *bool_pending_values = NULL;
|
|||
static struct dentry *class_dir = NULL;
|
||||
static unsigned long last_class_ino;
|
||||
|
||||
/* global data for policy capabilities */
|
||||
static struct dentry *policycap_dir = NULL;
|
||||
|
||||
extern void selnl_notify_setenforce(int val);
|
||||
|
||||
/* 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;
|
||||
|
||||
#define SEL_INITCON_INO_OFFSET 0x01000000
|
||||
#define SEL_BOOL_INO_OFFSET 0x02000000
|
||||
#define SEL_CLASS_INO_OFFSET 0x04000000
|
||||
#define SEL_INO_MASK 0x00ffffff
|
||||
#define SEL_INITCON_INO_OFFSET 0x01000000
|
||||
#define SEL_BOOL_INO_OFFSET 0x02000000
|
||||
#define SEL_CLASS_INO_OFFSET 0x04000000
|
||||
#define SEL_POLICYCAP_INO_OFFSET 0x08000000
|
||||
#define SEL_INO_MASK 0x00ffffff
|
||||
|
||||
#define TMPBUFLEN 12
|
||||
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 */
|
||||
static int sel_make_bools(void);
|
||||
static int sel_make_classes(void);
|
||||
static int sel_make_policycap(void);
|
||||
|
||||
/* declaration for sel_make_class_dirs */
|
||||
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();
|
||||
if (ret) {
|
||||
length = ret;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
ret = sel_make_policycap();
|
||||
if (ret)
|
||||
length = ret;
|
||||
else
|
||||
|
@ -1399,6 +1420,24 @@ static const struct file_operations sel_perm_ops = {
|
|||
.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,
|
||||
struct dentry *dir)
|
||||
{
|
||||
|
@ -1545,6 +1584,36 @@ out:
|
|||
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,
|
||||
unsigned long *ino)
|
||||
{
|
||||
|
@ -1673,6 +1742,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
|
|||
|
||||
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:
|
||||
return ret;
|
||||
err:
|
||||
|
|
|
@ -562,7 +562,7 @@ void mls_export_netlbl_lvl(struct context *context,
|
|||
if (!selinux_mls_enabled)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -582,7 +582,7 @@ void mls_import_netlbl_lvl(struct context *context,
|
|||
if (!selinux_mls_enabled)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -605,8 +605,8 @@ int mls_export_netlbl_cat(struct context *context,
|
|||
return 0;
|
||||
|
||||
rc = ebitmap_netlbl_export(&context->range.level[0].cat,
|
||||
&secattr->mls_cat);
|
||||
if (rc == 0 && secattr->mls_cat != NULL)
|
||||
&secattr->attr.mls.cat);
|
||||
if (rc == 0 && secattr->attr.mls.cat != NULL)
|
||||
secattr->flags |= NETLBL_SECATTR_MLS_CAT;
|
||||
|
||||
return rc;
|
||||
|
@ -633,7 +633,7 @@ int mls_import_netlbl_cat(struct context *context,
|
|||
return 0;
|
||||
|
||||
rc = ebitmap_netlbl_import(&context->range.level[0].cat,
|
||||
secattr->mls_cat);
|
||||
secattr->attr.mls.cat);
|
||||
if (rc != 0)
|
||||
goto import_netlbl_cat_failure;
|
||||
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
*
|
||||
* 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) 2003 - 2004 Tresys Technology, LLC
|
||||
* 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,
|
||||
.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)
|
||||
|
@ -183,6 +193,8 @@ static int policydb_init(struct policydb *p)
|
|||
if (rc)
|
||||
goto out_free_symtab;
|
||||
|
||||
ebitmap_init(&p->policycaps);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
||||
|
@ -673,8 +685,8 @@ void policydb_destroy(struct policydb *p)
|
|||
ebitmap_destroy(&p->type_attr_map[i]);
|
||||
}
|
||||
kfree(p->type_attr_map);
|
||||
|
||||
kfree(p->undefined_perms);
|
||||
ebitmap_destroy(&p->policycaps);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1554,6 +1566,10 @@ int policydb_read(struct policydb *p, void *fp)
|
|||
p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_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);
|
||||
if (!info) {
|
||||
printk(KERN_ERR "security: unable to find policy compat info "
|
||||
|
|
|
@ -241,6 +241,8 @@ struct policydb {
|
|||
/* type -> attribute reverse mapping */
|
||||
struct ebitmap *type_attr_map;
|
||||
|
||||
struct ebitmap policycaps;
|
||||
|
||||
unsigned int policyvers;
|
||||
|
||||
unsigned int reject_unknown : 1;
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
* Updated: Hewlett-Packard <paul.moore@hp.com>
|
||||
*
|
||||
* Added support for NetLabel
|
||||
* Added support for the policy capability bitmap
|
||||
*
|
||||
* Updated: Chad Sellers <csellers@tresys.com>
|
||||
*
|
||||
* 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) 2003 - 2004, 2006 Tresys Technology, LLC
|
||||
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
||||
|
@ -59,6 +60,8 @@
|
|||
extern void selnl_notify_policyload(u32 seqno);
|
||||
unsigned int policydb_loaded_version;
|
||||
|
||||
int selinux_policycap_netpeer;
|
||||
|
||||
/*
|
||||
* This is declared in avc.c
|
||||
*/
|
||||
|
@ -1299,6 +1302,12 @@ bad:
|
|||
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);
|
||||
static int security_preserve_bools(struct policydb *p);
|
||||
|
||||
|
@ -1346,6 +1355,7 @@ int security_load_policy(void *data, size_t len)
|
|||
avtab_cache_destroy();
|
||||
return -EINVAL;
|
||||
}
|
||||
security_load_policycaps();
|
||||
policydb_loaded_version = policydb.policyvers;
|
||||
ss_initialized = 1;
|
||||
seqno = ++latest_granting;
|
||||
|
@ -1404,6 +1414,7 @@ int security_load_policy(void *data, size_t len)
|
|||
POLICY_WRLOCK;
|
||||
memcpy(&policydb, &newpolicydb, sizeof policydb);
|
||||
sidtab_set(&sidtab, &newsidtab);
|
||||
security_load_policycaps();
|
||||
seqno = ++latest_granting;
|
||||
policydb_loaded_version = policydb.policyvers;
|
||||
POLICY_WRUNLOCK;
|
||||
|
@ -1478,11 +1489,8 @@ out:
|
|||
* security_netif_sid - Obtain the SID for a network interface.
|
||||
* @name: interface name
|
||||
* @if_sid: interface SID
|
||||
* @msg_sid: default SID for received packets
|
||||
*/
|
||||
int security_netif_sid(char *name,
|
||||
u32 *if_sid,
|
||||
u32 *msg_sid)
|
||||
int security_netif_sid(char *name, u32 *if_sid)
|
||||
{
|
||||
int rc = 0;
|
||||
struct ocontext *c;
|
||||
|
@ -1510,11 +1518,8 @@ int security_netif_sid(char *name,
|
|||
goto out;
|
||||
}
|
||||
*if_sid = c->sid[0];
|
||||
*msg_sid = c->sid[1];
|
||||
} else {
|
||||
} else
|
||||
*if_sid = SECINITSID_NETIF;
|
||||
*msg_sid = SECINITSID_NETMSG;
|
||||
}
|
||||
|
||||
out:
|
||||
POLICY_RDUNLOCK;
|
||||
|
@ -2049,6 +2054,91 @@ out:
|
|||
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)
|
||||
{
|
||||
struct class_datum *datum = d;
|
||||
|
@ -2154,6 +2244,60 @@ int security_get_allow_unknown(void)
|
|||
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 {
|
||||
u32 au_seqno;
|
||||
struct context au_ctxt;
|
||||
|
@ -2403,50 +2547,10 @@ void selinux_audit_set_callback(int (*callback)(void))
|
|||
}
|
||||
|
||||
#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
|
||||
* @secattr: the NetLabel packet security attributes
|
||||
* @ctx: the SELinux context
|
||||
* @sid: the SELinux SID
|
||||
*
|
||||
* Description:
|
||||
* 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,
|
||||
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);
|
||||
if (secattr->cache == NULL)
|
||||
return;
|
||||
|
||||
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);
|
||||
if (secattr->cache == NULL) {
|
||||
kfree(sid_cache);
|
||||
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;
|
||||
secattr->cache->data = (void *)cache;
|
||||
*sid_cache = sid;
|
||||
secattr->cache->free = kfree;
|
||||
secattr->cache->data = sid_cache;
|
||||
secattr->flags |= NETLBL_SECATTR_CACHE;
|
||||
}
|
||||
|
||||
/**
|
||||
* security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
|
||||
* @secattr: the NetLabel packet security attributes
|
||||
* @base_sid: the SELinux SID to use as a context for MLS only attributes
|
||||
* @sid: the SELinux SID
|
||||
*
|
||||
* Description:
|
||||
* Convert the given NetLabel security attributes in @secattr into a
|
||||
* 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
|
||||
* possibile the 'cache' field of @secattr is set and the CACHE flag is set;
|
||||
* this is to allow the @secattr to be used by NetLabel to cache the secattr to
|
||||
* SID conversion for future lookups. Returns zero on success, negative
|
||||
* values on failure.
|
||||
* SID/context then use SECINITSID_NETMSG as the foundation. If possibile the
|
||||
* 'cache' field of @secattr is set and the CACHE flag is set; this is to
|
||||
* allow the @secattr to be used by NetLabel to cache the secattr to SID
|
||||
* conversion for future lookups. Returns zero on success, negative values on
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
||||
u32 base_sid,
|
||||
u32 *sid)
|
||||
{
|
||||
int rc = -EIDRM;
|
||||
struct context *ctx;
|
||||
struct context ctx_new;
|
||||
struct selinux_netlbl_cache *cache;
|
||||
|
||||
if (!ss_initialized) {
|
||||
*sid = SECSID_NULL;
|
||||
|
@ -2518,40 +2608,13 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
|
|||
POLICY_RDLOCK;
|
||||
|
||||
if (secattr->flags & NETLBL_SECATTR_CACHE) {
|
||||
cache = NETLBL_CACHE(secattr->cache->data);
|
||||
switch (cache->type) {
|
||||
case NETLBL_CACHE_T_SID:
|
||||
*sid = cache->data.sid;
|
||||
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;
|
||||
}
|
||||
*sid = *(u32 *)secattr->cache->data;
|
||||
rc = 0;
|
||||
} else if (secattr->flags & NETLBL_SECATTR_SECID) {
|
||||
*sid = secattr->attr.secid;
|
||||
rc = 0;
|
||||
} else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
|
||||
ctx = sidtab_search(&sidtab, base_sid);
|
||||
ctx = sidtab_search(&sidtab, SECINITSID_NETMSG);
|
||||
if (ctx == NULL)
|
||||
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);
|
||||
if (secattr->flags & NETLBL_SECATTR_MLS_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;
|
||||
ctx_new.range.level[1].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)
|
||||
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);
|
||||
} else {
|
||||
|
|
|
@ -46,11 +46,14 @@
|
|||
#include <net/checksum.h>
|
||||
#include <net/udp.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "avc.h"
|
||||
#include "objsec.h"
|
||||
#include "xfrm.h"
|
||||
|
||||
/* Labeled XFRM instance counter */
|
||||
atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
|
||||
|
||||
/*
|
||||
* Returns true if an LSM/SELinux context
|
||||
|
@ -293,6 +296,9 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,
|
|||
BUG_ON(!uctx);
|
||||
|
||||
err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0);
|
||||
if (err == 0)
|
||||
atomic_inc(&selinux_xfrm_refcount);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -340,10 +346,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)
|
|||
struct xfrm_sec_ctx *ctx = xp->security;
|
||||
int rc = 0;
|
||||
|
||||
if (ctx)
|
||||
if (ctx) {
|
||||
rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
|
||||
SECCLASS_ASSOCIATION,
|
||||
ASSOCIATION__SETCONTEXT, NULL);
|
||||
if (rc == 0)
|
||||
atomic_dec(&selinux_xfrm_refcount);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -360,6 +369,8 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
|
|||
BUG_ON(!x);
|
||||
|
||||
err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
|
||||
if (err == 0)
|
||||
atomic_inc(&selinux_xfrm_refcount);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -382,10 +393,13 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
|
|||
struct xfrm_sec_ctx *ctx = x->security;
|
||||
int rc = 0;
|
||||
|
||||
if (ctx)
|
||||
if (ctx) {
|
||||
rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
|
||||
SECCLASS_ASSOCIATION,
|
||||
ASSOCIATION__SETCONTEXT, NULL);
|
||||
if (rc == 0)
|
||||
atomic_dec(&selinux_xfrm_refcount);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue