Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: CRED: Fix regression in cap_capable() as shown up by sys_faccessat() [ver #3] Revert "CRED: Fix regression in cap_capable() as shown up by sys_faccessat() [ver #2]" SELinux: shrink sizeof av_inhert selinux_class_perm and context CRED: Fix regression in cap_capable() as shown up by sys_faccessat() [ver #2] keys: fix sparse warning by adding __user annotation to cast smack: Add support for unlabeled network hosts and networks selinux: Deprecate and schedule the removal of the the compat_net functionality netlabel: Update kernel configuration API
This commit is contained in:
commit
c861ea2cb2
|
@ -315,3 +315,15 @@ When: 2.6.29 (ideally) or 2.6.30 (more likely)
|
|||
Why: Deprecated by the new (standard) device driver binding model. Use
|
||||
i2c_driver->probe() and ->remove() instead.
|
||||
Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: SELinux "compat_net" functionality
|
||||
When: 2.6.30 at the earliest
|
||||
Why: In 2.6.18 the Secmark concept was introduced to replace the "compat_net"
|
||||
network access control functionality of SELinux. Secmark offers both
|
||||
better performance and greater flexibility than the "compat_net"
|
||||
mechanism. Now that the major Linux distributions have moved to
|
||||
Secmark, it is time to deprecate the older mechanism and start the
|
||||
process of removing the old code.
|
||||
Who: Paul Moore <paul.moore@hp.com>
|
||||
|
|
|
@ -529,8 +529,21 @@ extern const kernel_cap_t __cap_init_eff_set;
|
|||
*
|
||||
* Note that this does not set PF_SUPERPRIV on the task.
|
||||
*/
|
||||
#define has_capability(t, cap) (security_capable((t), (cap)) == 0)
|
||||
#define has_capability_noaudit(t, cap) (security_capable_noaudit((t), (cap)) == 0)
|
||||
#define has_capability(t, cap) (security_real_capable((t), (cap)) == 0)
|
||||
|
||||
/**
|
||||
* has_capability_noaudit - Determine if a task has a superior capability available (unaudited)
|
||||
* @t: The task in question
|
||||
* @cap: The capability to be tested for
|
||||
*
|
||||
* Return true if the specified task has the given superior capability
|
||||
* currently in effect, false if not, but don't write an audit message for the
|
||||
* check.
|
||||
*
|
||||
* Note that this does not set PF_SUPERPRIV on the task.
|
||||
*/
|
||||
#define has_capability_noaudit(t, cap) \
|
||||
(security_real_capable_noaudit((t), (cap)) == 0)
|
||||
|
||||
extern int capable(int cap);
|
||||
|
||||
|
|
|
@ -48,7 +48,8 @@ struct audit_krule;
|
|||
* These functions are in security/capability.c and are used
|
||||
* as the default capabilities functions
|
||||
*/
|
||||
extern int cap_capable(struct task_struct *tsk, int cap, int audit);
|
||||
extern int cap_capable(struct task_struct *tsk, const struct cred *cred,
|
||||
int cap, int audit);
|
||||
extern int cap_settime(struct timespec *ts, struct timezone *tz);
|
||||
extern int cap_ptrace_may_access(struct task_struct *child, unsigned int mode);
|
||||
extern int cap_ptrace_traceme(struct task_struct *parent);
|
||||
|
@ -1251,9 +1252,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
|||
* @permitted contains the permitted capability set.
|
||||
* Return 0 and update @new if permission is granted.
|
||||
* @capable:
|
||||
* Check whether the @tsk process has the @cap capability.
|
||||
* Check whether the @tsk process has the @cap capability in the indicated
|
||||
* credentials.
|
||||
* @tsk contains the task_struct for the process.
|
||||
* @cred contains the credentials to use.
|
||||
* @cap contains the capability <include/linux/capability.h>.
|
||||
* @audit: Whether to write an audit message or not
|
||||
* Return 0 if the capability is granted for @tsk.
|
||||
* @acct:
|
||||
* Check permission before enabling or disabling process accounting. If
|
||||
|
@ -1346,7 +1350,8 @@ struct security_operations {
|
|||
const kernel_cap_t *effective,
|
||||
const kernel_cap_t *inheritable,
|
||||
const kernel_cap_t *permitted);
|
||||
int (*capable) (struct task_struct *tsk, int cap, int audit);
|
||||
int (*capable) (struct task_struct *tsk, const struct cred *cred,
|
||||
int cap, int audit);
|
||||
int (*acct) (struct file *file);
|
||||
int (*sysctl) (struct ctl_table *table, int op);
|
||||
int (*quotactl) (int cmds, int type, int id, struct super_block *sb);
|
||||
|
@ -1628,8 +1633,9 @@ int security_capset(struct cred *new, const struct cred *old,
|
|||
const kernel_cap_t *effective,
|
||||
const kernel_cap_t *inheritable,
|
||||
const kernel_cap_t *permitted);
|
||||
int security_capable(struct task_struct *tsk, int cap);
|
||||
int security_capable_noaudit(struct task_struct *tsk, int cap);
|
||||
int security_capable(int cap);
|
||||
int security_real_capable(struct task_struct *tsk, int cap);
|
||||
int security_real_capable_noaudit(struct task_struct *tsk, int cap);
|
||||
int security_acct(struct file *file);
|
||||
int security_sysctl(struct ctl_table *table, int op);
|
||||
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
|
||||
|
@ -1826,14 +1832,31 @@ static inline int security_capset(struct cred *new,
|
|||
return cap_capset(new, old, effective, inheritable, permitted);
|
||||
}
|
||||
|
||||
static inline int security_capable(struct task_struct *tsk, int cap)
|
||||
static inline int security_capable(int cap)
|
||||
{
|
||||
return cap_capable(tsk, cap, SECURITY_CAP_AUDIT);
|
||||
return cap_capable(current, current_cred(), cap, SECURITY_CAP_AUDIT);
|
||||
}
|
||||
|
||||
static inline int security_capable_noaudit(struct task_struct *tsk, int cap)
|
||||
static inline int security_real_capable(struct task_struct *tsk, int cap)
|
||||
{
|
||||
return cap_capable(tsk, cap, SECURITY_CAP_NOAUDIT);
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
ret = cap_capable(tsk, __task_cred(tsk), cap, SECURITY_CAP_AUDIT);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
int security_real_capable_noaudit(struct task_struct *tsk, int cap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
ret = cap_capable(tsk, __task_cred(tsk), cap,
|
||||
SECURITY_CAP_NOAUDIT);
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int security_acct(struct file *file)
|
||||
|
|
|
@ -131,7 +131,8 @@ extern int cipso_v4_rbm_strictvalid;
|
|||
*/
|
||||
|
||||
#ifdef CONFIG_NETLABEL
|
||||
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
|
||||
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
|
||||
struct netlbl_audit *audit_info);
|
||||
void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
|
||||
int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
|
||||
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
|
||||
|
@ -140,7 +141,8 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
|
|||
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
|
||||
void *cb_arg);
|
||||
#else
|
||||
static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
|
||||
static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
|
@ -353,13 +355,37 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
|
|||
/*
|
||||
* LSM configuration operations
|
||||
*/
|
||||
int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info);
|
||||
int netlbl_cfg_unlbl_add_map(const char *domain,
|
||||
int netlbl_cfg_map_del(const char *domain,
|
||||
u16 family,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_cfg_unlbl_map_add(const char *domain,
|
||||
u16 family,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
|
||||
int netlbl_cfg_unlbl_static_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u16 family,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_cfg_unlbl_static_del(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u16 family,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
|
||||
struct netlbl_audit *audit_info);
|
||||
void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info);
|
||||
int netlbl_cfg_cipsov4_map_add(u32 doi,
|
||||
const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info);
|
||||
|
||||
/*
|
||||
* LSM security attribute operations
|
||||
*/
|
||||
|
@ -401,19 +427,62 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
|
|||
void netlbl_cache_invalidate(void);
|
||||
int netlbl_cache_add(const struct sk_buff *skb,
|
||||
const struct netlbl_lsm_secattr *secattr);
|
||||
|
||||
/*
|
||||
* Protocol engine operations
|
||||
*/
|
||||
struct audit_buffer *netlbl_audit_start(int type,
|
||||
struct netlbl_audit *audit_info);
|
||||
#else
|
||||
static inline int netlbl_cfg_map_del(const char *domain,
|
||||
u16 family,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int netlbl_cfg_unlbl_add_map(const char *domain,
|
||||
static inline int netlbl_cfg_unlbl_map_add(const char *domain,
|
||||
u16 family,
|
||||
void *addr,
|
||||
void *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
|
||||
static inline int netlbl_cfg_unlbl_static_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u16 family,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int netlbl_cfg_unlbl_static_del(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u16 family,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
static inline void netlbl_cfg_cipsov4_del(u32 doi,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
|
||||
const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return -ENOSYS;
|
||||
|
@ -495,6 +564,11 @@ static inline int netlbl_cache_add(const struct sk_buff *skb,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
static inline struct audit_buffer *netlbl_audit_start(int type,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_NETLABEL */
|
||||
|
||||
#endif /* _NETLABEL_H */
|
||||
|
|
|
@ -306,7 +306,7 @@ int capable(int cap)
|
|||
BUG();
|
||||
}
|
||||
|
||||
if (has_capability(current, cap)) {
|
||||
if (security_capable(cap) == 0) {
|
||||
current->flags |= PF_SUPERPRIV;
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/audit.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/icmp.h>
|
||||
#include <net/tcp.h>
|
||||
|
@ -449,6 +450,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
|
|||
/**
|
||||
* cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
|
||||
* @doi_def: the DOI structure
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* The caller defines a new DOI for use by the CIPSO engine and calls this
|
||||
|
@ -458,50 +460,78 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
|
|||
* zero on success and non-zero on failure.
|
||||
*
|
||||
*/
|
||||
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
|
||||
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
u32 iter;
|
||||
u32 doi;
|
||||
u32 doi_type;
|
||||
struct audit_buffer *audit_buf;
|
||||
|
||||
doi = doi_def->doi;
|
||||
doi_type = doi_def->type;
|
||||
|
||||
if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
|
||||
return -EINVAL;
|
||||
goto doi_add_return;
|
||||
for (iter = 0; iter < CIPSO_V4_TAG_MAXCNT; iter++) {
|
||||
switch (doi_def->tags[iter]) {
|
||||
case CIPSO_V4_TAG_RBITMAP:
|
||||
break;
|
||||
case CIPSO_V4_TAG_RANGE:
|
||||
if (doi_def->type != CIPSO_V4_MAP_PASS)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case CIPSO_V4_TAG_INVALID:
|
||||
if (iter == 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case CIPSO_V4_TAG_ENUM:
|
||||
if (doi_def->type != CIPSO_V4_MAP_PASS)
|
||||
return -EINVAL;
|
||||
goto doi_add_return;
|
||||
break;
|
||||
case CIPSO_V4_TAG_LOCAL:
|
||||
if (doi_def->type != CIPSO_V4_MAP_LOCAL)
|
||||
return -EINVAL;
|
||||
goto doi_add_return;
|
||||
break;
|
||||
case CIPSO_V4_TAG_INVALID:
|
||||
if (iter == 0)
|
||||
goto doi_add_return;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
goto doi_add_return;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_set(&doi_def->refcount, 1);
|
||||
|
||||
spin_lock(&cipso_v4_doi_list_lock);
|
||||
if (cipso_v4_doi_search(doi_def->doi) != NULL)
|
||||
goto doi_add_failure;
|
||||
if (cipso_v4_doi_search(doi_def->doi) != NULL) {
|
||||
spin_unlock(&cipso_v4_doi_list_lock);
|
||||
ret_val = -EEXIST;
|
||||
goto doi_add_return;
|
||||
}
|
||||
list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
|
||||
spin_unlock(&cipso_v4_doi_list_lock);
|
||||
ret_val = 0;
|
||||
|
||||
return 0;
|
||||
doi_add_return:
|
||||
audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_ADD, audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
const char *type_str;
|
||||
switch (doi_type) {
|
||||
case CIPSO_V4_MAP_TRANS:
|
||||
type_str = "trans";
|
||||
break;
|
||||
case CIPSO_V4_MAP_PASS:
|
||||
type_str = "pass";
|
||||
break;
|
||||
case CIPSO_V4_MAP_LOCAL:
|
||||
type_str = "local";
|
||||
break;
|
||||
default:
|
||||
type_str = "(unknown)";
|
||||
}
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u cipso_type=%s res=%u",
|
||||
doi, type_str, ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
doi_add_failure:
|
||||
spin_unlock(&cipso_v4_doi_list_lock);
|
||||
return -EEXIST;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -559,25 +589,39 @@ static void cipso_v4_doi_free_rcu(struct rcu_head *entry)
|
|||
*/
|
||||
int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct cipso_v4_doi *doi_def;
|
||||
struct audit_buffer *audit_buf;
|
||||
|
||||
spin_lock(&cipso_v4_doi_list_lock);
|
||||
doi_def = cipso_v4_doi_search(doi);
|
||||
if (doi_def == NULL) {
|
||||
spin_unlock(&cipso_v4_doi_list_lock);
|
||||
return -ENOENT;
|
||||
ret_val = -ENOENT;
|
||||
goto doi_remove_return;
|
||||
}
|
||||
if (!atomic_dec_and_test(&doi_def->refcount)) {
|
||||
spin_unlock(&cipso_v4_doi_list_lock);
|
||||
return -EBUSY;
|
||||
ret_val = -EBUSY;
|
||||
goto doi_remove_return;
|
||||
}
|
||||
list_del_rcu(&doi_def->list);
|
||||
spin_unlock(&cipso_v4_doi_list_lock);
|
||||
|
||||
cipso_v4_cache_invalidate();
|
||||
call_rcu(&doi_def->rcu, cipso_v4_doi_free_rcu);
|
||||
ret_val = 0;
|
||||
|
||||
return 0;
|
||||
doi_remove_return:
|
||||
audit_buf = netlbl_audit_start(AUDIT_MAC_CIPSOV4_DEL, audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u res=%u",
|
||||
doi, ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -130,6 +130,7 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
|
|||
/**
|
||||
* netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
|
||||
|
@ -137,7 +138,8 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
|
|||
* non-zero on error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_std(struct genl_info *info)
|
||||
static int netlbl_cipsov4_add_std(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct cipso_v4_doi *doi_def = NULL;
|
||||
|
@ -316,7 +318,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
|
|||
}
|
||||
}
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def);
|
||||
ret_val = cipso_v4_doi_add(doi_def, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_std_failure;
|
||||
return 0;
|
||||
|
@ -330,6 +332,7 @@ add_std_failure:
|
|||
/**
|
||||
* netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
|
||||
|
@ -337,7 +340,8 @@ add_std_failure:
|
|||
* error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_pass(struct genl_info *info)
|
||||
static int netlbl_cipsov4_add_pass(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct cipso_v4_doi *doi_def = NULL;
|
||||
|
@ -354,7 +358,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
|
|||
if (ret_val != 0)
|
||||
goto add_pass_failure;
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def);
|
||||
ret_val = cipso_v4_doi_add(doi_def, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_pass_failure;
|
||||
return 0;
|
||||
|
@ -367,6 +371,7 @@ add_pass_failure:
|
|||
/**
|
||||
* netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
|
||||
|
@ -374,7 +379,8 @@ add_pass_failure:
|
|||
* non-zero on error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_local(struct genl_info *info)
|
||||
static int netlbl_cipsov4_add_local(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct cipso_v4_doi *doi_def = NULL;
|
||||
|
@ -391,7 +397,7 @@ static int netlbl_cipsov4_add_local(struct genl_info *info)
|
|||
if (ret_val != 0)
|
||||
goto add_local_failure;
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def);
|
||||
ret_val = cipso_v4_doi_add(doi_def, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_local_failure;
|
||||
return 0;
|
||||
|
@ -415,48 +421,31 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
|
|||
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
u32 type;
|
||||
u32 doi;
|
||||
const char *type_str = "(unknown)";
|
||||
struct audit_buffer *audit_buf;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
|
||||
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
|
||||
return -EINVAL;
|
||||
|
||||
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
|
||||
switch (type) {
|
||||
switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
|
||||
case CIPSO_V4_MAP_TRANS:
|
||||
type_str = "trans";
|
||||
ret_val = netlbl_cipsov4_add_std(info);
|
||||
ret_val = netlbl_cipsov4_add_std(info, &audit_info);
|
||||
break;
|
||||
case CIPSO_V4_MAP_PASS:
|
||||
type_str = "pass";
|
||||
ret_val = netlbl_cipsov4_add_pass(info);
|
||||
ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
|
||||
break;
|
||||
case CIPSO_V4_MAP_LOCAL:
|
||||
type_str = "local";
|
||||
ret_val = netlbl_cipsov4_add_local(info);
|
||||
ret_val = netlbl_cipsov4_add_local(info, &audit_info);
|
||||
break;
|
||||
}
|
||||
if (ret_val == 0)
|
||||
atomic_inc(&netlabel_mgmt_protocount);
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
|
||||
&audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u cipso_type=%s res=%u",
|
||||
doi,
|
||||
type_str,
|
||||
ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
@ -725,9 +714,7 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
|
|||
static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
u32 doi = 0;
|
||||
struct netlbl_domhsh_walk_arg cb_arg;
|
||||
struct audit_buffer *audit_buf;
|
||||
struct netlbl_audit audit_info;
|
||||
u32 skip_bkt = 0;
|
||||
u32 skip_chain = 0;
|
||||
|
@ -735,29 +722,17 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
|
|||
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
|
||||
return -EINVAL;
|
||||
|
||||
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
cb_arg.doi = doi;
|
||||
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
cb_arg.audit_info = &audit_info;
|
||||
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
|
||||
netlbl_cipsov4_remove_cb, &cb_arg);
|
||||
if (ret_val == 0 || ret_val == -ENOENT) {
|
||||
ret_val = cipso_v4_doi_remove(doi, &audit_info);
|
||||
ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
|
||||
if (ret_val == 0)
|
||||
atomic_dec(&netlabel_mgmt_protocount);
|
||||
}
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
|
||||
&audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u res=%u",
|
||||
doi,
|
||||
ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
|
|
@ -482,6 +482,73 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_remove_af4 - Removes an address selector entry
|
||||
* @domain: the domain
|
||||
* @addr: IPv4 address
|
||||
* @mask: IPv4 address mask
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes an individual address selector from a domain mapping and potentially
|
||||
* the entire mapping if it is empty. Returns zero on success, negative values
|
||||
* on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_remove_af4(const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
struct netlbl_dom_map *entry_map;
|
||||
struct netlbl_af4list *entry_addr;
|
||||
struct netlbl_af4list *iter4;
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
struct netlbl_af6list *iter6;
|
||||
#endif /* IPv6 */
|
||||
struct netlbl_domaddr4_map *entry;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (domain)
|
||||
entry_map = netlbl_domhsh_search(domain);
|
||||
else
|
||||
entry_map = netlbl_domhsh_search_def(domain);
|
||||
if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
|
||||
goto remove_af4_failure;
|
||||
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
|
||||
&entry_map->type_def.addrsel->list4);
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
|
||||
if (entry_addr == NULL)
|
||||
goto remove_af4_failure;
|
||||
netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
|
||||
goto remove_af4_single_addr;
|
||||
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||
netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
|
||||
goto remove_af4_single_addr;
|
||||
#endif /* IPv6 */
|
||||
/* the domain mapping is empty so remove it from the mapping table */
|
||||
netlbl_domhsh_remove_entry(entry_map, audit_info);
|
||||
|
||||
remove_af4_single_addr:
|
||||
rcu_read_unlock();
|
||||
/* yick, we can't use call_rcu here because we don't have a rcu head
|
||||
* pointer but hopefully this should be a rare case so the pause
|
||||
* shouldn't be a problem */
|
||||
synchronize_rcu();
|
||||
entry = netlbl_domhsh_addr4_entry(entry_addr);
|
||||
cipso_v4_doi_putdef(entry->type_def.cipsov4);
|
||||
kfree(entry);
|
||||
return 0;
|
||||
|
||||
remove_af4_failure:
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_remove - Removes an entry from the domain hash table
|
||||
* @domain: the domain to remove
|
||||
|
|
|
@ -90,6 +90,10 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
|
|||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove_af4(const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
|
||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/bug.h>
|
||||
|
@ -42,6 +45,7 @@
|
|||
#include "netlabel_cipso_v4.h"
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_addrlist.h"
|
||||
|
||||
/*
|
||||
* Configuration Functions
|
||||
|
@ -50,6 +54,9 @@
|
|||
/**
|
||||
* netlbl_cfg_map_del - Remove a NetLabel/LSM domain mapping
|
||||
* @domain: the domain mapping to remove
|
||||
* @family: address family
|
||||
* @addr: IP address
|
||||
* @mask: IP address mask
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
|
@ -58,14 +65,32 @@
|
|||
* values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
|
||||
int netlbl_cfg_map_del(const char *domain,
|
||||
u16 family,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return netlbl_domhsh_remove(domain, audit_info);
|
||||
if (addr == NULL && mask == NULL) {
|
||||
return netlbl_domhsh_remove(domain, audit_info);
|
||||
} else if (addr != NULL && mask != NULL) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return netlbl_domhsh_remove_af4(domain, addr, mask,
|
||||
audit_info);
|
||||
default:
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
} else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cfg_unlbl_add_map - Add an unlabeled NetLabel/LSM domain mapping
|
||||
* netlbl_cfg_unlbl_map_add - Add a new unlabeled mapping
|
||||
* @domain: the domain mapping to add
|
||||
* @family: address family
|
||||
* @addr: IP address
|
||||
* @mask: IP address mask
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
|
@ -74,11 +99,19 @@ int netlbl_cfg_map_del(const char *domain, struct netlbl_audit *audit_info)
|
|||
* negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_cfg_unlbl_add_map(const char *domain,
|
||||
int netlbl_cfg_unlbl_map_add(const char *domain,
|
||||
u16 family,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
struct netlbl_dom_map *entry;
|
||||
struct netlbl_domaddr_map *addrmap = NULL;
|
||||
struct netlbl_domaddr4_map *map4 = NULL;
|
||||
struct netlbl_domaddr6_map *map6 = NULL;
|
||||
const struct in_addr *addr4, *mask4;
|
||||
const struct in6_addr *addr6, *mask6;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (entry == NULL)
|
||||
|
@ -86,49 +119,225 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
|
|||
if (domain != NULL) {
|
||||
entry->domain = kstrdup(domain, GFP_ATOMIC);
|
||||
if (entry->domain == NULL)
|
||||
goto cfg_unlbl_add_map_failure;
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
}
|
||||
|
||||
if (addr == NULL && mask == NULL)
|
||||
entry->type = NETLBL_NLTYPE_UNLABELED;
|
||||
else if (addr != NULL && mask != NULL) {
|
||||
addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
|
||||
if (addrmap == NULL)
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
INIT_LIST_HEAD(&addrmap->list4);
|
||||
INIT_LIST_HEAD(&addrmap->list6);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
addr4 = addr;
|
||||
mask4 = mask;
|
||||
map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
|
||||
if (map4 == NULL)
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
map4->type = NETLBL_NLTYPE_UNLABELED;
|
||||
map4->list.addr = addr4->s_addr & mask4->s_addr;
|
||||
map4->list.mask = mask4->s_addr;
|
||||
map4->list.valid = 1;
|
||||
ret_val = netlbl_af4list_add(&map4->list,
|
||||
&addrmap->list4);
|
||||
if (ret_val != 0)
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr6 = addr;
|
||||
mask6 = mask;
|
||||
map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
|
||||
if (map4 == NULL)
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
map6->type = NETLBL_NLTYPE_UNLABELED;
|
||||
ipv6_addr_copy(&map6->list.addr, addr6);
|
||||
map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
|
||||
map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
|
||||
map6->list.addr.s6_addr32[2] &= mask6->s6_addr32[2];
|
||||
map6->list.addr.s6_addr32[3] &= mask6->s6_addr32[3];
|
||||
ipv6_addr_copy(&map6->list.mask, mask6);
|
||||
map6->list.valid = 1;
|
||||
ret_val = netlbl_af4list_add(&map4->list,
|
||||
&addrmap->list4);
|
||||
if (ret_val != 0)
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
break;
|
||||
default:
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
break;
|
||||
}
|
||||
|
||||
entry->type_def.addrsel = addrmap;
|
||||
entry->type = NETLBL_NLTYPE_ADDRSELECT;
|
||||
} else {
|
||||
ret_val = -EINVAL;
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
}
|
||||
entry->type = NETLBL_NLTYPE_UNLABELED;
|
||||
|
||||
ret_val = netlbl_domhsh_add(entry, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto cfg_unlbl_add_map_failure;
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
|
||||
return 0;
|
||||
|
||||
cfg_unlbl_add_map_failure:
|
||||
cfg_unlbl_map_add_failure:
|
||||
if (entry != NULL)
|
||||
kfree(entry->domain);
|
||||
kfree(entry);
|
||||
kfree(addrmap);
|
||||
kfree(map4);
|
||||
kfree(map6);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
|
||||
* @doi_def: the DOI definition
|
||||
* @domain: the domain mapping to add
|
||||
* netlbl_cfg_unlbl_static_add - Adds a new static label
|
||||
* @net: network namespace
|
||||
* @dev_name: interface name
|
||||
* @addr: IP address in network byte order (struct in[6]_addr)
|
||||
* @mask: address mask in network byte order (struct in[6]_addr)
|
||||
* @family: address family
|
||||
* @secid: LSM secid value for the entry
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Add a new CIPSOv4 DOI definition and NetLabel/LSM domain mapping for this
|
||||
* new DOI definition to the NetLabel subsystem. A @domain value of NULL adds
|
||||
* a new default domain mapping. Returns zero on success, negative values on
|
||||
* failure.
|
||||
* Adds a new NetLabel static label to be used when protocol provided labels
|
||||
* are not present on incoming traffic. If @dev_name is NULL then the default
|
||||
* interface will be used. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
|
||||
int netlbl_cfg_unlbl_static_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u16 family,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
u32 addr_len;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
addr_len = sizeof(struct in_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr_len = sizeof(struct in6_addr);
|
||||
break;
|
||||
default:
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
return netlbl_unlhsh_add(net,
|
||||
dev_name, addr, mask, addr_len,
|
||||
secid, audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cfg_unlbl_static_del - Removes an existing static label
|
||||
* @net: network namespace
|
||||
* @dev_name: interface name
|
||||
* @addr: IP address in network byte order (struct in[6]_addr)
|
||||
* @mask: address mask in network byte order (struct in[6]_addr)
|
||||
* @family: address family
|
||||
* @secid: LSM secid value for the entry
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes an existing NetLabel static label used when protocol provided labels
|
||||
* are not present on incoming traffic. If @dev_name is NULL then the default
|
||||
* interface will be used. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_cfg_unlbl_static_del(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u16 family,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
u32 addr_len;
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
addr_len = sizeof(struct in_addr);
|
||||
break;
|
||||
case AF_INET6:
|
||||
addr_len = sizeof(struct in6_addr);
|
||||
break;
|
||||
default:
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
||||
return netlbl_unlhsh_remove(net,
|
||||
dev_name, addr, mask, addr_len,
|
||||
audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
|
||||
* @doi_def: CIPSO DOI definition
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Add a new CIPSO DOI definition as defined by @doi_def. Returns zero on
|
||||
* success and negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return cipso_v4_doi_add(doi_def, audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cfg_cipsov4_del - Remove an existing CIPSOv4 DOI definition
|
||||
* @doi: CIPSO DOI
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Remove an existing CIPSO DOI definition matching @doi. Returns zero on
|
||||
* success and negative values on failure.
|
||||
*
|
||||
*/
|
||||
void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info)
|
||||
{
|
||||
cipso_v4_doi_remove(doi, audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cfg_cipsov4_map_add - Add a new CIPSOv4 DOI mapping
|
||||
* @doi: the CIPSO DOI
|
||||
* @domain: the domain mapping to add
|
||||
* @addr: IP address
|
||||
* @mask: IP address mask
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Add a new NetLabel/LSM domain mapping for the given CIPSO DOI to the NetLabel
|
||||
* subsystem. A @domain value of NULL adds a new default domain mapping.
|
||||
* Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_cfg_cipsov4_map_add(u32 doi,
|
||||
const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
u32 doi;
|
||||
u32 doi_type;
|
||||
struct cipso_v4_doi *doi_def;
|
||||
struct netlbl_dom_map *entry;
|
||||
const char *type_str;
|
||||
struct audit_buffer *audit_buf;
|
||||
struct netlbl_domaddr_map *addrmap = NULL;
|
||||
struct netlbl_domaddr4_map *addrinfo = NULL;
|
||||
|
||||
doi = doi_def->doi;
|
||||
doi_type = doi_def->type;
|
||||
doi_def = cipso_v4_doi_getdef(doi);
|
||||
if (doi_def == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (entry == NULL)
|
||||
|
@ -136,56 +345,52 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
|
|||
if (domain != NULL) {
|
||||
entry->domain = kstrdup(domain, GFP_ATOMIC);
|
||||
if (entry->domain == NULL)
|
||||
goto cfg_cipsov4_add_map_failure;
|
||||
goto cfg_cipsov4_map_add_failure;
|
||||
}
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def);
|
||||
if (ret_val != 0)
|
||||
goto cfg_cipsov4_add_map_failure_remove_doi;
|
||||
entry->type = NETLBL_NLTYPE_CIPSOV4;
|
||||
entry->type_def.cipsov4 = cipso_v4_doi_getdef(doi);
|
||||
if (entry->type_def.cipsov4 == NULL) {
|
||||
ret_val = -ENOENT;
|
||||
goto cfg_cipsov4_add_map_failure_remove_doi;
|
||||
if (addr == NULL && mask == NULL) {
|
||||
entry->type_def.cipsov4 = doi_def;
|
||||
entry->type = NETLBL_NLTYPE_CIPSOV4;
|
||||
} else if (addr != NULL && mask != NULL) {
|
||||
addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
|
||||
if (addrmap == NULL)
|
||||
goto cfg_cipsov4_map_add_failure;
|
||||
INIT_LIST_HEAD(&addrmap->list4);
|
||||
INIT_LIST_HEAD(&addrmap->list6);
|
||||
|
||||
addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
|
||||
if (addrinfo == NULL)
|
||||
goto cfg_cipsov4_map_add_failure;
|
||||
addrinfo->type_def.cipsov4 = doi_def;
|
||||
addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
|
||||
addrinfo->list.addr = addr->s_addr & mask->s_addr;
|
||||
addrinfo->list.mask = mask->s_addr;
|
||||
addrinfo->list.valid = 1;
|
||||
ret_val = netlbl_af4list_add(&addrinfo->list, &addrmap->list4);
|
||||
if (ret_val != 0)
|
||||
goto cfg_cipsov4_map_add_failure;
|
||||
|
||||
entry->type_def.addrsel = addrmap;
|
||||
entry->type = NETLBL_NLTYPE_ADDRSELECT;
|
||||
} else {
|
||||
ret_val = -EINVAL;
|
||||
goto cfg_cipsov4_map_add_failure;
|
||||
}
|
||||
|
||||
ret_val = netlbl_domhsh_add(entry, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto cfg_cipsov4_add_map_failure_release_doi;
|
||||
goto cfg_cipsov4_map_add_failure;
|
||||
|
||||
cfg_cipsov4_add_map_return:
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
|
||||
audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
switch (doi_type) {
|
||||
case CIPSO_V4_MAP_TRANS:
|
||||
type_str = "trans";
|
||||
break;
|
||||
case CIPSO_V4_MAP_PASS:
|
||||
type_str = "pass";
|
||||
break;
|
||||
case CIPSO_V4_MAP_LOCAL:
|
||||
type_str = "local";
|
||||
break;
|
||||
default:
|
||||
type_str = "(unknown)";
|
||||
}
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u cipso_type=%s res=%u",
|
||||
doi, type_str, ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
return 0;
|
||||
|
||||
return ret_val;
|
||||
|
||||
cfg_cipsov4_add_map_failure_release_doi:
|
||||
cfg_cipsov4_map_add_failure:
|
||||
cipso_v4_doi_putdef(doi_def);
|
||||
cfg_cipsov4_add_map_failure_remove_doi:
|
||||
cipso_v4_doi_remove(doi, audit_info);
|
||||
cfg_cipsov4_add_map_failure:
|
||||
if (entry != NULL)
|
||||
kfree(entry->domain);
|
||||
kfree(entry);
|
||||
goto cfg_cipsov4_add_map_return;
|
||||
kfree(addrmap);
|
||||
kfree(addrinfo);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -690,6 +895,28 @@ int netlbl_cache_add(const struct sk_buff *skb,
|
|||
return -ENOMSG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Protocol Engine Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_audit_start - Start an audit message
|
||||
* @type: audit message type
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Start an audit message using the type specified in @type and fill the audit
|
||||
* message with some fields common to all NetLabel audit messages. This
|
||||
* function should only be used by protocol engines, not LSMs. Returns a
|
||||
* pointer to the audit buffer on success, NULL on failure.
|
||||
*
|
||||
*/
|
||||
struct audit_buffer *netlbl_audit_start(int type,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return netlbl_audit_start_common(type, audit_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup Functions
|
||||
*/
|
||||
|
|
|
@ -450,13 +450,13 @@ add_iface_failure:
|
|||
* success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_unlhsh_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info)
|
||||
int netlbl_unlhsh_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
int ifindex;
|
||||
|
@ -720,12 +720,12 @@ unlhsh_condremove_failure:
|
|||
* Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_unlhsh_remove(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
struct netlbl_audit *audit_info)
|
||||
int netlbl_unlhsh_remove(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct net_device *dev;
|
||||
|
|
|
@ -221,6 +221,21 @@ int netlbl_unlabel_genl_init(void);
|
|||
/* General Unlabeled init function */
|
||||
int netlbl_unlabel_init(u32 size);
|
||||
|
||||
/* Static/Fallback label management functions */
|
||||
int netlbl_unlhsh_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_unlhsh_remove(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
struct netlbl_audit *audit_info);
|
||||
|
||||
/* Process Unlabeled incoming network packets */
|
||||
int netlbl_unlabel_getattr(const struct sk_buff *skb,
|
||||
u16 family,
|
||||
|
|
|
@ -45,26 +45,22 @@ EXPORT_SYMBOL(cap_netlink_recv);
|
|||
/**
|
||||
* cap_capable - Determine whether a task has a particular effective capability
|
||||
* @tsk: The task to query
|
||||
* @cred: The credentials to use
|
||||
* @cap: The capability to check for
|
||||
* @audit: Whether to write an audit message or not
|
||||
*
|
||||
* Determine whether the nominated task has the specified capability amongst
|
||||
* its effective set, returning 0 if it does, -ve if it does not.
|
||||
*
|
||||
* NOTE WELL: cap_capable() cannot be used like the kernel's capable()
|
||||
* function. That is, it has the reverse semantics: cap_capable() returns 0
|
||||
* when a task has a capability, but the kernel's capable() returns 1 for this
|
||||
* case.
|
||||
* NOTE WELL: cap_has_capability() cannot be used like the kernel's capable()
|
||||
* and has_capability() functions. That is, it has the reverse semantics:
|
||||
* cap_has_capability() returns 0 when a task has a capability, but the
|
||||
* kernel's capable() and has_capability() returns 1 for this case.
|
||||
*/
|
||||
int cap_capable(struct task_struct *tsk, int cap, int audit)
|
||||
int cap_capable(struct task_struct *tsk, const struct cred *cred, int cap,
|
||||
int audit)
|
||||
{
|
||||
__u32 cap_raised;
|
||||
|
||||
/* Derived from include/linux/sched.h:capable. */
|
||||
rcu_read_lock();
|
||||
cap_raised = cap_raised(__task_cred(tsk)->cap_effective, cap);
|
||||
rcu_read_unlock();
|
||||
return cap_raised ? 0 : -EPERM;
|
||||
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,7 +156,8 @@ static inline int cap_inh_is_capped(void)
|
|||
/* they are so limited unless the current task has the CAP_SETPCAP
|
||||
* capability
|
||||
*/
|
||||
if (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
|
||||
if (cap_capable(current, current_cred(), CAP_SETPCAP,
|
||||
SECURITY_CAP_AUDIT) == 0)
|
||||
return 0;
|
||||
#endif
|
||||
return 1;
|
||||
|
@ -869,7 +866,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|||
& (new->securebits ^ arg2)) /*[1]*/
|
||||
|| ((new->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|
||||
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
||||
|| (cap_capable(current, CAP_SETPCAP, SECURITY_CAP_AUDIT) != 0) /*[4]*/
|
||||
|| (cap_capable(current, current_cred(), CAP_SETPCAP,
|
||||
SECURITY_CAP_AUDIT) != 0) /*[4]*/
|
||||
/*
|
||||
* [1] no changing of bits that are locked
|
||||
* [2] no unlocking of locks
|
||||
|
@ -950,7 +948,8 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
|
|||
{
|
||||
int cap_sys_admin = 0;
|
||||
|
||||
if (cap_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT) == 0)
|
||||
if (cap_capable(current, current_cred(), CAP_SYS_ADMIN,
|
||||
SECURITY_CAP_NOAUDIT) == 0)
|
||||
cap_sys_admin = 1;
|
||||
return __vm_enough_memory(mm, pages, cap_sys_admin);
|
||||
}
|
||||
|
|
|
@ -1294,7 +1294,7 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
|
|||
|
||||
case KEYCTL_GET_SECURITY:
|
||||
return keyctl_get_security((key_serial_t) arg2,
|
||||
(char *) arg3,
|
||||
(char __user *) arg3,
|
||||
(size_t) arg4);
|
||||
|
||||
default:
|
||||
|
|
|
@ -154,14 +154,32 @@ int security_capset(struct cred *new, const struct cred *old,
|
|||
effective, inheritable, permitted);
|
||||
}
|
||||
|
||||
int security_capable(struct task_struct *tsk, int cap)
|
||||
int security_capable(int cap)
|
||||
{
|
||||
return security_ops->capable(tsk, cap, SECURITY_CAP_AUDIT);
|
||||
return security_ops->capable(current, current_cred(), cap,
|
||||
SECURITY_CAP_AUDIT);
|
||||
}
|
||||
|
||||
int security_capable_noaudit(struct task_struct *tsk, int cap)
|
||||
int security_real_capable(struct task_struct *tsk, int cap)
|
||||
{
|
||||
return security_ops->capable(tsk, cap, SECURITY_CAP_NOAUDIT);
|
||||
const struct cred *cred;
|
||||
int ret;
|
||||
|
||||
cred = get_task_cred(tsk);
|
||||
ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_AUDIT);
|
||||
put_cred(cred);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int security_real_capable_noaudit(struct task_struct *tsk, int cap)
|
||||
{
|
||||
const struct cred *cred;
|
||||
int ret;
|
||||
|
||||
cred = get_task_cred(tsk);
|
||||
ret = security_ops->capable(tsk, cred, cap, SECURITY_CAP_NOAUDIT);
|
||||
put_cred(cred);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int security_acct(struct file *file)
|
||||
|
|
|
@ -94,33 +94,6 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
|
|||
|
||||
If you are unsure how to answer this question, answer 1.
|
||||
|
||||
config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
|
||||
bool "NSA SELinux enable new secmark network controls by default"
|
||||
depends on SECURITY_SELINUX
|
||||
default n
|
||||
help
|
||||
This option determines whether the new secmark-based network
|
||||
controls will be enabled by default. If not, the old internal
|
||||
per-packet controls will be enabled by default, preserving
|
||||
old behavior.
|
||||
|
||||
If you enable the new controls, you will need updated
|
||||
SELinux userspace libraries, tools and policy. Typically,
|
||||
your distribution will provide these and enable the new controls
|
||||
in the kernel they also distribute.
|
||||
|
||||
Note that this option can be overridden at boot with the
|
||||
selinux_compat_net parameter, and after boot via
|
||||
/selinux/compat_net. See Documentation/kernel-parameters.txt
|
||||
for details on this parameter.
|
||||
|
||||
If you enable the new network controls, you will likely
|
||||
also require the SECMARK and CONNSECMARK targets, as
|
||||
well as any conntrack helpers for protocols which you
|
||||
wish to control.
|
||||
|
||||
If you are unsure what to do here, select N.
|
||||
|
||||
config SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
bool "NSA SELinux maximum supported policy format version"
|
||||
depends on SECURITY_SELINUX
|
||||
|
|
|
@ -53,18 +53,20 @@ static const char *class_to_string[] = {
|
|||
#undef S_
|
||||
|
||||
static const struct av_inherit av_inherit[] = {
|
||||
#define S_(c, i, b) { c, common_##i##_perm_to_string, b },
|
||||
#define S_(c, i, b) { .tclass = c,\
|
||||
.common_pts = common_##i##_perm_to_string,\
|
||||
.common_base = b },
|
||||
#include "av_inherit.h"
|
||||
#undef S_
|
||||
};
|
||||
|
||||
const struct selinux_class_perm selinux_class_perm = {
|
||||
av_perm_to_string,
|
||||
ARRAY_SIZE(av_perm_to_string),
|
||||
class_to_string,
|
||||
ARRAY_SIZE(class_to_string),
|
||||
av_inherit,
|
||||
ARRAY_SIZE(av_inherit)
|
||||
.av_perm_to_string = av_perm_to_string,
|
||||
.av_pts_len = ARRAY_SIZE(av_perm_to_string),
|
||||
.class_to_string = class_to_string,
|
||||
.cts_len = ARRAY_SIZE(class_to_string),
|
||||
.av_inherit = av_inherit,
|
||||
.av_inherit_len = ARRAY_SIZE(av_inherit)
|
||||
};
|
||||
|
||||
#define AVC_CACHE_SLOTS 512
|
||||
|
|
|
@ -1433,12 +1433,13 @@ static int current_has_perm(const struct task_struct *tsk,
|
|||
|
||||
/* Check whether a task is allowed to use a capability. */
|
||||
static int task_has_capability(struct task_struct *tsk,
|
||||
const struct cred *cred,
|
||||
int cap, int audit)
|
||||
{
|
||||
struct avc_audit_data ad;
|
||||
struct av_decision avd;
|
||||
u16 sclass;
|
||||
u32 sid = task_sid(tsk);
|
||||
u32 sid = cred_sid(cred);
|
||||
u32 av = CAP_TO_MASK(cap);
|
||||
int rc;
|
||||
|
||||
|
@ -1865,15 +1866,16 @@ static int selinux_capset(struct cred *new, const struct cred *old,
|
|||
return cred_has_perm(old, new, PROCESS__SETCAP);
|
||||
}
|
||||
|
||||
static int selinux_capable(struct task_struct *tsk, int cap, int audit)
|
||||
static int selinux_capable(struct task_struct *tsk, const struct cred *cred,
|
||||
int cap, int audit)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = secondary_ops->capable(tsk, cap, audit);
|
||||
rc = secondary_ops->capable(tsk, cred, cap, audit);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return task_has_capability(tsk, cap, audit);
|
||||
return task_has_capability(tsk, cred, cap, audit);
|
||||
}
|
||||
|
||||
static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid)
|
||||
|
@ -2037,7 +2039,8 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
|
|||
{
|
||||
int rc, cap_sys_admin = 0;
|
||||
|
||||
rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT);
|
||||
rc = selinux_capable(current, current_cred(), CAP_SYS_ADMIN,
|
||||
SECURITY_CAP_NOAUDIT);
|
||||
if (rc == 0)
|
||||
cap_sys_admin = 1;
|
||||
|
||||
|
@ -2880,7 +2883,8 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
|
|||
* and lack of permission just means that we fall back to the
|
||||
* in-core context value, not a denial.
|
||||
*/
|
||||
error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT);
|
||||
error = selinux_capable(current, current_cred(), CAP_MAC_ADMIN,
|
||||
SECURITY_CAP_NOAUDIT);
|
||||
if (!error)
|
||||
error = security_sid_to_context_force(isec->sid, &context,
|
||||
&size);
|
||||
|
@ -4185,7 +4189,7 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
|
|||
static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
||||
u16 family)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
u32 peer_sid;
|
||||
u32 sk_sid = sksec->sid;
|
||||
|
@ -4202,7 +4206,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
|
|||
if (selinux_compat_net)
|
||||
err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad,
|
||||
family, addrp);
|
||||
else
|
||||
else if (selinux_secmark_enabled())
|
||||
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
|
||||
PACKET__RECV, &ad);
|
||||
if (err)
|
||||
|
@ -4705,7 +4709,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
|||
if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex,
|
||||
&ad, family, addrp))
|
||||
return NF_DROP;
|
||||
} else {
|
||||
} else if (selinux_secmark_enabled()) {
|
||||
if (avc_has_perm(sksec->sid, skb->secmark,
|
||||
SECCLASS_PACKET, PACKET__SEND, &ad))
|
||||
return NF_DROP;
|
||||
|
|
|
@ -17,16 +17,16 @@ struct av_perm_to_string {
|
|||
};
|
||||
|
||||
struct av_inherit {
|
||||
u16 tclass;
|
||||
const char **common_pts;
|
||||
u32 common_base;
|
||||
u16 tclass;
|
||||
};
|
||||
|
||||
struct selinux_class_perm {
|
||||
const struct av_perm_to_string *av_perm_to_string;
|
||||
u32 av_pts_len;
|
||||
const char **class_to_string;
|
||||
u32 cts_len;
|
||||
const char **class_to_string;
|
||||
const struct av_inherit *av_inherit;
|
||||
u32 av_inherit_len;
|
||||
};
|
||||
|
|
|
@ -47,13 +47,7 @@ static char *policycap_names[] = {
|
|||
|
||||
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
|
||||
|
||||
#ifdef CONFIG_SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
|
||||
#define SELINUX_COMPAT_NET_VALUE 0
|
||||
#else
|
||||
#define SELINUX_COMPAT_NET_VALUE 1
|
||||
#endif
|
||||
|
||||
int selinux_compat_net = SELINUX_COMPAT_NET_VALUE;
|
||||
int selinux_compat_net = 0;
|
||||
|
||||
static int __init checkreqprot_setup(char *str)
|
||||
{
|
||||
|
@ -494,7 +488,13 @@ static ssize_t sel_write_compat_net(struct file *file, const char __user *buf,
|
|||
if (sscanf(page, "%d", &new_value) != 1)
|
||||
goto out;
|
||||
|
||||
selinux_compat_net = new_value ? 1 : 0;
|
||||
if (new_value) {
|
||||
printk(KERN_NOTICE
|
||||
"SELinux: compat_net is deprecated, please use secmark"
|
||||
" instead\n");
|
||||
selinux_compat_net = 1;
|
||||
} else
|
||||
selinux_compat_net = 0;
|
||||
length = count;
|
||||
out:
|
||||
free_page((unsigned long) page);
|
||||
|
|
|
@ -27,9 +27,9 @@ struct context {
|
|||
u32 user;
|
||||
u32 role;
|
||||
u32 type;
|
||||
u32 len; /* length of string in bytes */
|
||||
struct mls_range range;
|
||||
char *str; /* string representation if context cannot be mapped. */
|
||||
u32 len; /* length of string in bytes */
|
||||
};
|
||||
|
||||
static inline void mls_context_init(struct context *c)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <linux/capability.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/in.h>
|
||||
#include <net/netlabel.h>
|
||||
|
||||
/*
|
||||
|
@ -39,6 +40,7 @@ struct superblock_smack {
|
|||
struct socket_smack {
|
||||
char *smk_out; /* outbound label */
|
||||
char *smk_in; /* inbound label */
|
||||
int smk_labeled; /* label scheme */
|
||||
char smk_packet[SMK_LABELLEN]; /* TCP peer label */
|
||||
};
|
||||
|
||||
|
@ -79,6 +81,16 @@ struct smack_cipso {
|
|||
char smk_catset[SMK_LABELLEN];
|
||||
};
|
||||
|
||||
/*
|
||||
* An entry in the table identifying hosts.
|
||||
*/
|
||||
struct smk_netlbladdr {
|
||||
struct smk_netlbladdr *smk_next;
|
||||
struct sockaddr_in smk_host; /* network address */
|
||||
struct in_addr smk_mask; /* network mask */
|
||||
char *smk_label; /* label */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the repository for labels seen so that it is
|
||||
* not necessary to keep allocating tiny chuncks of memory
|
||||
|
@ -127,6 +139,20 @@ struct smack_known {
|
|||
#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT
|
||||
|
||||
/*
|
||||
* How communications on this socket are treated.
|
||||
* Usually it's determined by the underlying netlabel code
|
||||
* but there are certain cases, including single label hosts
|
||||
* and potentially single label interfaces for which the
|
||||
* treatment can not be known in advance.
|
||||
*
|
||||
* The possibility of additional labeling schemes being
|
||||
* introduced in the future exists as well.
|
||||
*/
|
||||
#define SMACK_UNLABELED_SOCKET 0
|
||||
#define SMACK_CIPSO_SOCKET 1
|
||||
|
||||
/*
|
||||
* smackfs magic number
|
||||
* smackfs macic number
|
||||
*/
|
||||
#define SMACK_MAGIC 0x43415d53 /* "SMAC" */
|
||||
|
@ -141,6 +167,7 @@ struct smack_known {
|
|||
* CIPSO defaults.
|
||||
*/
|
||||
#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
|
||||
#define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */
|
||||
#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */
|
||||
#define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */
|
||||
#define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */
|
||||
|
@ -176,7 +203,6 @@ u32 smack_to_secid(const char *);
|
|||
* Shared data.
|
||||
*/
|
||||
extern int smack_cipso_direct;
|
||||
extern int smack_net_nltype;
|
||||
extern char *smack_net_ambient;
|
||||
extern char *smack_onlycap;
|
||||
|
||||
|
@ -186,9 +212,10 @@ extern struct smack_known smack_known_hat;
|
|||
extern struct smack_known smack_known_huh;
|
||||
extern struct smack_known smack_known_invalid;
|
||||
extern struct smack_known smack_known_star;
|
||||
extern struct smack_known smack_known_unset;
|
||||
extern struct smack_known smack_known_web;
|
||||
|
||||
extern struct smk_list_entry *smack_list;
|
||||
extern struct smk_netlbladdr *smack_netlbladdrs;
|
||||
extern struct security_operations smack_ops;
|
||||
|
||||
/*
|
||||
|
|
|
@ -15,15 +15,8 @@
|
|||
#include <linux/sched.h>
|
||||
#include "smack.h"
|
||||
|
||||
struct smack_known smack_known_unset = {
|
||||
.smk_next = NULL,
|
||||
.smk_known = "UNSET",
|
||||
.smk_secid = 1,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known smack_known_huh = {
|
||||
.smk_next = &smack_known_unset,
|
||||
.smk_next = NULL,
|
||||
.smk_known = "?",
|
||||
.smk_secid = 2,
|
||||
.smk_cipso = NULL,
|
||||
|
@ -57,7 +50,14 @@ struct smack_known smack_known_invalid = {
|
|||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known *smack_known = &smack_known_invalid;
|
||||
struct smack_known smack_known_web = {
|
||||
.smk_next = &smack_known_invalid,
|
||||
.smk_known = "@",
|
||||
.smk_secid = 7,
|
||||
.smk_cipso = NULL,
|
||||
};
|
||||
|
||||
struct smack_known *smack_known = &smack_known_web;
|
||||
|
||||
/*
|
||||
* The initial value needs to be bigger than any of the
|
||||
|
@ -98,6 +98,16 @@ int smk_access(char *subject_label, char *object_label, int request)
|
|||
if (subject_label == smack_known_star.smk_known ||
|
||||
strcmp(subject_label, smack_known_star.smk_known) == 0)
|
||||
return -EACCES;
|
||||
/*
|
||||
* An internet object can be accessed by any subject.
|
||||
* Tasks cannot be assigned the internet label.
|
||||
* An internet subject can access any object.
|
||||
*/
|
||||
if (object_label == smack_known_web.smk_known ||
|
||||
subject_label == smack_known_web.smk_known ||
|
||||
strcmp(object_label, smack_known_web.smk_known) == 0 ||
|
||||
strcmp(subject_label, smack_known_web.smk_known) == 0)
|
||||
return 0;
|
||||
/*
|
||||
* A star object can be accessed by any subject.
|
||||
*/
|
||||
|
|
|
@ -1277,6 +1277,7 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
|
|||
|
||||
ssp->smk_in = csp;
|
||||
ssp->smk_out = csp;
|
||||
ssp->smk_labeled = SMACK_CIPSO_SOCKET;
|
||||
ssp->smk_packet[0] = '\0';
|
||||
|
||||
sk->sk_security = ssp;
|
||||
|
@ -1341,45 +1342,69 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)
|
|||
struct smack_cipso cipso;
|
||||
int rc;
|
||||
|
||||
switch (smack_net_nltype) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
nlsp->domain = smack;
|
||||
nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
|
||||
nlsp->domain = smack;
|
||||
nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
|
||||
|
||||
rc = smack_to_cipso(smack, &cipso);
|
||||
if (rc == 0) {
|
||||
nlsp->attr.mls.lvl = cipso.smk_level;
|
||||
smack_set_catset(cipso.smk_catset, nlsp);
|
||||
} else {
|
||||
nlsp->attr.mls.lvl = smack_cipso_direct;
|
||||
smack_set_catset(smack, nlsp);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
rc = smack_to_cipso(smack, &cipso);
|
||||
if (rc == 0) {
|
||||
nlsp->attr.mls.lvl = cipso.smk_level;
|
||||
smack_set_catset(cipso.smk_catset, nlsp);
|
||||
} else {
|
||||
nlsp->attr.mls.lvl = smack_cipso_direct;
|
||||
smack_set_catset(smack, nlsp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_netlabel - Set the secattr on a socket
|
||||
* @sk: the socket
|
||||
* @labeled: socket label scheme
|
||||
*
|
||||
* Convert the outbound smack value (smk_out) to a
|
||||
* secattr and attach it to the socket.
|
||||
*
|
||||
* Returns 0 on success or an error code
|
||||
*/
|
||||
static int smack_netlabel(struct sock *sk)
|
||||
static int smack_netlabel(struct sock *sk, int labeled)
|
||||
{
|
||||
struct socket_smack *ssp;
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
ssp = sk->sk_security;
|
||||
netlbl_secattr_init(&secattr);
|
||||
smack_to_secattr(ssp->smk_out, &secattr);
|
||||
rc = netlbl_sock_setattr(sk, &secattr);
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
/*
|
||||
* Usually the netlabel code will handle changing the
|
||||
* packet labeling based on the label.
|
||||
* The case of a single label host is different, because
|
||||
* a single label host should never get a labeled packet
|
||||
* even though the label is usually associated with a packet
|
||||
* label.
|
||||
*/
|
||||
local_bh_disable();
|
||||
bh_lock_sock_nested(sk);
|
||||
|
||||
if (ssp->smk_out == smack_net_ambient ||
|
||||
labeled == SMACK_UNLABELED_SOCKET)
|
||||
netlbl_sock_delattr(sk);
|
||||
else {
|
||||
netlbl_secattr_init(&secattr);
|
||||
smack_to_secattr(ssp->smk_out, &secattr);
|
||||
rc = netlbl_sock_setattr(sk, &secattr);
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
}
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
local_bh_enable();
|
||||
/*
|
||||
* Remember the label scheme used so that it is not
|
||||
* necessary to do the netlabel setting if it has not
|
||||
* changed the next time through.
|
||||
*
|
||||
* The -EDESTADDRREQ case is an indication that there's
|
||||
* a single level host involved.
|
||||
*/
|
||||
if (rc == 0)
|
||||
ssp->smk_labeled = labeled;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -1432,7 +1457,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
|
|||
ssp->smk_in = sp;
|
||||
else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) {
|
||||
ssp->smk_out = sp;
|
||||
rc = smack_netlabel(sock->sk);
|
||||
rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
|
@ -1462,7 +1487,108 @@ static int smack_socket_post_create(struct socket *sock, int family,
|
|||
/*
|
||||
* Set the outbound netlbl.
|
||||
*/
|
||||
return smack_netlabel(sock->sk);
|
||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* smack_host_label - check host based restrictions
|
||||
* @sip: the object end
|
||||
*
|
||||
* looks for host based access restrictions
|
||||
*
|
||||
* This version will only be appropriate for really small
|
||||
* sets of single label hosts. Because of the masking
|
||||
* it cannot shortcut out on the first match. There are
|
||||
* numerious ways to address the problem, but none of them
|
||||
* have been applied here.
|
||||
*
|
||||
* Returns the label of the far end or NULL if it's not special.
|
||||
*/
|
||||
static char *smack_host_label(struct sockaddr_in *sip)
|
||||
{
|
||||
struct smk_netlbladdr *snp;
|
||||
char *bestlabel = NULL;
|
||||
struct in_addr *siap = &sip->sin_addr;
|
||||
struct in_addr *liap;
|
||||
struct in_addr *miap;
|
||||
struct in_addr bestmask;
|
||||
|
||||
if (siap->s_addr == 0)
|
||||
return NULL;
|
||||
|
||||
bestmask.s_addr = 0;
|
||||
|
||||
for (snp = smack_netlbladdrs; snp != NULL; snp = snp->smk_next) {
|
||||
liap = &snp->smk_host.sin_addr;
|
||||
miap = &snp->smk_mask;
|
||||
/*
|
||||
* If the addresses match after applying the list entry mask
|
||||
* the entry matches the address. If it doesn't move along to
|
||||
* the next entry.
|
||||
*/
|
||||
if ((liap->s_addr & miap->s_addr) !=
|
||||
(siap->s_addr & miap->s_addr))
|
||||
continue;
|
||||
/*
|
||||
* If the list entry mask identifies a single address
|
||||
* it can't get any more specific.
|
||||
*/
|
||||
if (miap->s_addr == 0xffffffff)
|
||||
return snp->smk_label;
|
||||
/*
|
||||
* If the list entry mask is less specific than the best
|
||||
* already found this entry is uninteresting.
|
||||
*/
|
||||
if ((miap->s_addr | bestmask.s_addr) == bestmask.s_addr)
|
||||
continue;
|
||||
/*
|
||||
* This is better than any entry found so far.
|
||||
*/
|
||||
bestmask.s_addr = miap->s_addr;
|
||||
bestlabel = snp->smk_label;
|
||||
}
|
||||
|
||||
return bestlabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_socket_connect - connect access check
|
||||
* @sock: the socket
|
||||
* @sap: the other end
|
||||
* @addrlen: size of sap
|
||||
*
|
||||
* Verifies that a connection may be possible
|
||||
*
|
||||
* Returns 0 on success, and error code otherwise
|
||||
*/
|
||||
static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
|
||||
int addrlen)
|
||||
{
|
||||
struct socket_smack *ssp = sock->sk->sk_security;
|
||||
char *hostsp;
|
||||
int rc;
|
||||
|
||||
if (sock->sk == NULL || sock->sk->sk_family != PF_INET)
|
||||
return 0;
|
||||
|
||||
if (addrlen < sizeof(struct sockaddr_in))
|
||||
return -EINVAL;
|
||||
|
||||
hostsp = smack_host_label((struct sockaddr_in *)sap);
|
||||
if (hostsp == NULL) {
|
||||
if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2101,8 +2227,14 @@ static int smack_setprocattr(struct task_struct *p, char *name,
|
|||
if (newsmack == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* No process is ever allowed the web ("@") label.
|
||||
*/
|
||||
if (newsmack == smack_known_web.smk_known)
|
||||
return -EPERM;
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
if (new == NULL)
|
||||
return -ENOMEM;
|
||||
new->security = newsmack;
|
||||
commit_creds(new);
|
||||
|
@ -2143,6 +2275,49 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
|
|||
return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_socket_sendmsg - Smack check based on destination host
|
||||
* @sock: the socket
|
||||
* @msghdr: the message
|
||||
* @size: the size of the message
|
||||
*
|
||||
* Return 0 if the current subject can write to the destination
|
||||
* host. This is only a question if the destination is a single
|
||||
* label host.
|
||||
*/
|
||||
static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
int size)
|
||||
{
|
||||
struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
|
||||
struct socket_smack *ssp = sock->sk->sk_security;
|
||||
char *hostsp;
|
||||
int rc;
|
||||
|
||||
/*
|
||||
* Perfectly reasonable for this to be NULL
|
||||
*/
|
||||
if (sip == NULL || sip->sin_family != PF_INET)
|
||||
return 0;
|
||||
|
||||
hostsp = smack_host_label(sip);
|
||||
if (hostsp == NULL) {
|
||||
if (ssp->smk_labeled != SMACK_CIPSO_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
if (ssp->smk_labeled != SMACK_UNLABELED_SOCKET)
|
||||
return smack_netlabel(sock->sk, SMACK_UNLABELED_SOCKET);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat
|
||||
* pair to smack
|
||||
|
@ -2154,44 +2329,66 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)
|
|||
static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)
|
||||
{
|
||||
char smack[SMK_LABELLEN];
|
||||
char *sp;
|
||||
int pcat;
|
||||
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) == 0) {
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {
|
||||
/*
|
||||
* Looks like a CIPSO packet.
|
||||
* If there are flags but no level netlabel isn't
|
||||
* behaving the way we expect it to.
|
||||
*
|
||||
* Get the categories, if any
|
||||
* Without guidance regarding the smack value
|
||||
* for the packet fall back on the network
|
||||
* ambient value.
|
||||
*/
|
||||
strncpy(sip, smack_net_ambient, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Get the categories, if any
|
||||
*/
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
|
||||
for (pcat = -1;;) {
|
||||
pcat = netlbl_secattr_catmap_walk(sap->attr.mls.cat,
|
||||
pcat + 1);
|
||||
if (pcat < 0)
|
||||
break;
|
||||
smack_catset_bit(pcat, smack);
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0)
|
||||
for (pcat = -1;;) {
|
||||
pcat = netlbl_secattr_catmap_walk(
|
||||
sap->attr.mls.cat, pcat + 1);
|
||||
if (pcat < 0)
|
||||
break;
|
||||
smack_catset_bit(pcat, smack);
|
||||
}
|
||||
/*
|
||||
* If it is CIPSO using smack direct mapping
|
||||
* we are already done. WeeHee.
|
||||
*/
|
||||
if (sap->attr.mls.lvl == smack_cipso_direct) {
|
||||
memcpy(sip, smack, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* If it is CIPSO using smack direct mapping
|
||||
* we are already done. WeeHee.
|
||||
*/
|
||||
if (sap->attr.mls.lvl == smack_cipso_direct) {
|
||||
memcpy(sip, smack, SMK_MAXLEN);
|
||||
/*
|
||||
* Look it up in the supplied table if it is not
|
||||
* a direct mapping.
|
||||
*/
|
||||
smack_from_cipso(sap->attr.mls.lvl, smack, sip);
|
||||
return;
|
||||
}
|
||||
if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {
|
||||
/*
|
||||
* Looks like a fallback, which gives us a secid.
|
||||
*/
|
||||
sp = smack_from_secid(sap->attr.secid);
|
||||
/*
|
||||
* This has got to be a bug because it is
|
||||
* impossible to specify a fallback without
|
||||
* specifying the label, which will ensure
|
||||
* it has a secid, and the only way to get a
|
||||
* secid is from a fallback.
|
||||
*/
|
||||
BUG_ON(sp == NULL);
|
||||
strncpy(sip, sp, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Look it up in the supplied table if it is not a direct mapping.
|
||||
* Without guidance regarding the smack value
|
||||
* for the packet fall back on the network
|
||||
* ambient value.
|
||||
*/
|
||||
smack_from_cipso(sap->attr.mls.lvl, smack, sip);
|
||||
strncpy(sip, smack_net_ambient, SMK_MAXLEN);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2207,6 +2404,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||
struct netlbl_lsm_secattr secattr;
|
||||
struct socket_smack *ssp = sk->sk_security;
|
||||
char smack[SMK_LABELLEN];
|
||||
char *csp;
|
||||
int rc;
|
||||
|
||||
if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)
|
||||
|
@ -2215,21 +2413,24 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||
/*
|
||||
* Translate what netlabel gave us.
|
||||
*/
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
netlbl_secattr_init(&secattr);
|
||||
|
||||
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr);
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
smack_from_secattr(&secattr, smack);
|
||||
else
|
||||
strncpy(smack, smack_net_ambient, SMK_MAXLEN);
|
||||
csp = smack;
|
||||
} else
|
||||
csp = smack_net_ambient;
|
||||
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
|
||||
/*
|
||||
* Receiving a packet requires that the other end
|
||||
* be able to write here. Read access is not required.
|
||||
* This is the simplist possible security model
|
||||
* for networking.
|
||||
*/
|
||||
rc = smk_access(smack, ssp->smk_in, MAY_WRITE);
|
||||
rc = smk_access(csp, ssp->smk_in, MAY_WRITE);
|
||||
if (rc != 0)
|
||||
netlbl_skbuff_err(skb, rc, 0);
|
||||
return rc;
|
||||
|
@ -2298,7 +2499,6 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
|
|||
/*
|
||||
* Translate what netlabel gave us.
|
||||
*/
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
netlbl_secattr_init(&secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
if (rc == 0)
|
||||
|
@ -2341,7 +2541,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
|
|||
ssp->smk_in = ssp->smk_out = current_security();
|
||||
ssp->smk_packet[0] = '\0';
|
||||
|
||||
rc = smack_netlabel(sk);
|
||||
rc = smack_netlabel(sk, SMACK_CIPSO_SOCKET);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n",
|
||||
__func__, -rc);
|
||||
|
@ -2367,7 +2567,6 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
|||
if (skb == NULL)
|
||||
return -EACCES;
|
||||
|
||||
memset(smack, '\0', SMK_LABELLEN);
|
||||
netlbl_secattr_init(&skb_secattr);
|
||||
rc = netlbl_skbuff_getattr(skb, sk->sk_family, &skb_secattr);
|
||||
if (rc == 0)
|
||||
|
@ -2732,6 +2931,8 @@ struct security_operations smack_ops = {
|
|||
.unix_may_send = smack_unix_may_send,
|
||||
|
||||
.socket_post_create = smack_socket_post_create,
|
||||
.socket_connect = smack_socket_connect,
|
||||
.socket_sendmsg = smack_socket_sendmsg,
|
||||
.socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
|
||||
.socket_getpeersec_stream = smack_socket_getpeersec_stream,
|
||||
.socket_getpeersec_dgram = smack_socket_getpeersec_dgram,
|
||||
|
@ -2783,7 +2984,6 @@ static __init int smack_init(void)
|
|||
/*
|
||||
* Initialize locks
|
||||
*/
|
||||
spin_lock_init(&smack_known_unset.smk_cipsolock);
|
||||
spin_lock_init(&smack_known_huh.smk_cipsolock);
|
||||
spin_lock_init(&smack_known_hat.smk_cipsolock);
|
||||
spin_lock_init(&smack_known_star.smk_cipsolock);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/vmalloc.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
@ -38,7 +39,7 @@ enum smk_inos {
|
|||
SMK_DOI = 5, /* CIPSO DOI */
|
||||
SMK_DIRECT = 6, /* CIPSO level indicating direct label */
|
||||
SMK_AMBIENT = 7, /* internet ambient label */
|
||||
SMK_NLTYPE = 8, /* label scheme to use by default */
|
||||
SMK_NETLBLADDR = 8, /* single label hosts */
|
||||
SMK_ONLYCAP = 9, /* the only "capable" label */
|
||||
};
|
||||
|
||||
|
@ -48,6 +49,7 @@ enum smk_inos {
|
|||
static DEFINE_MUTEX(smack_list_lock);
|
||||
static DEFINE_MUTEX(smack_cipso_lock);
|
||||
static DEFINE_MUTEX(smack_ambient_lock);
|
||||
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
||||
|
||||
/*
|
||||
* This is the "ambient" label for network traffic.
|
||||
|
@ -56,12 +58,6 @@ static DEFINE_MUTEX(smack_ambient_lock);
|
|||
*/
|
||||
char *smack_net_ambient = smack_known_floor.smk_known;
|
||||
|
||||
/*
|
||||
* This is the default packet marking scheme for network traffic.
|
||||
* It can be reset via smackfs/nltype
|
||||
*/
|
||||
int smack_net_nltype = NETLBL_NLTYPE_CIPSOV4;
|
||||
|
||||
/*
|
||||
* This is the level in a CIPSO header that indicates a
|
||||
* smack label is contained directly in the category set.
|
||||
|
@ -79,6 +75,13 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
|
|||
*/
|
||||
char *smack_onlycap;
|
||||
|
||||
/*
|
||||
* Certain IP addresses may be designated as single label hosts.
|
||||
* Packets are sent there unlabeled, but only from tasks that
|
||||
* can write to the specified label.
|
||||
*/
|
||||
struct smk_netlbladdr *smack_netlbladdrs;
|
||||
|
||||
static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
|
||||
struct smk_list_entry *smack_list;
|
||||
|
||||
|
@ -104,6 +107,24 @@ struct smk_list_entry *smack_list;
|
|||
#define SMK_ACCESSLEN (sizeof(SMK_ACCESS) - 1)
|
||||
#define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN)
|
||||
|
||||
/**
|
||||
* smk_netlabel_audit_set - fill a netlbl_audit struct
|
||||
* @nap: structure to fill
|
||||
*/
|
||||
static void smk_netlabel_audit_set(struct netlbl_audit *nap)
|
||||
{
|
||||
nap->loginuid = audit_get_loginuid(current);
|
||||
nap->sessionid = audit_get_sessionid(current);
|
||||
nap->secid = smack_to_secid(current_security());
|
||||
}
|
||||
|
||||
/*
|
||||
* Values for parsing single label host rules
|
||||
* "1.2.3.4 X"
|
||||
* "192.168.138.129/32 abcdefghijklmnopqrstuvw"
|
||||
*/
|
||||
#define SMK_NETLBLADDRMIN 9
|
||||
#define SMK_NETLBLADDRMAX 42
|
||||
|
||||
/*
|
||||
* Seq_file read operations for /smack/load
|
||||
|
@ -344,13 +365,11 @@ static void smk_cipso_doi(void)
|
|||
{
|
||||
int rc;
|
||||
struct cipso_v4_doi *doip;
|
||||
struct netlbl_audit audit_info;
|
||||
struct netlbl_audit nai;
|
||||
|
||||
audit_info.loginuid = audit_get_loginuid(current);
|
||||
audit_info.sessionid = audit_get_sessionid(current);
|
||||
audit_info.secid = smack_to_secid(current_security());
|
||||
smk_netlabel_audit_set(&nai);
|
||||
|
||||
rc = netlbl_cfg_map_del(NULL, &audit_info);
|
||||
rc = netlbl_cfg_map_del(NULL, PF_INET, NULL, NULL, &nai);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "%s:%d remove rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
|
@ -365,11 +384,19 @@ static void smk_cipso_doi(void)
|
|||
for (rc = 1; rc < CIPSO_V4_TAG_MAXCNT; rc++)
|
||||
doip->tags[rc] = CIPSO_V4_TAG_INVALID;
|
||||
|
||||
rc = netlbl_cfg_cipsov4_add_map(doip, NULL, &audit_info);
|
||||
rc = netlbl_cfg_cipsov4_add(doip, &nai);
|
||||
if (rc != 0) {
|
||||
printk(KERN_WARNING "%s:%d add rc = %d\n",
|
||||
printk(KERN_WARNING "%s:%d cipso add rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
kfree(doip);
|
||||
return;
|
||||
}
|
||||
rc = netlbl_cfg_cipsov4_map_add(doip->doi, NULL, NULL, NULL, &nai);
|
||||
if (rc != 0) {
|
||||
printk(KERN_WARNING "%s:%d map add rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
kfree(doip);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,20 +406,19 @@ static void smk_cipso_doi(void)
|
|||
static void smk_unlbl_ambient(char *oldambient)
|
||||
{
|
||||
int rc;
|
||||
struct netlbl_audit audit_info;
|
||||
struct netlbl_audit nai;
|
||||
|
||||
audit_info.loginuid = audit_get_loginuid(current);
|
||||
audit_info.sessionid = audit_get_sessionid(current);
|
||||
audit_info.secid = smack_to_secid(current_security());
|
||||
smk_netlabel_audit_set(&nai);
|
||||
|
||||
if (oldambient != NULL) {
|
||||
rc = netlbl_cfg_map_del(oldambient, &audit_info);
|
||||
rc = netlbl_cfg_map_del(oldambient, PF_INET, NULL, NULL, &nai);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "%s:%d remove rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
}
|
||||
|
||||
rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info);
|
||||
rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET,
|
||||
NULL, NULL, &nai);
|
||||
if (rc != 0)
|
||||
printk(KERN_WARNING "%s:%d add rc = %d\n",
|
||||
__func__, __LINE__, rc);
|
||||
|
@ -603,6 +629,201 @@ static const struct file_operations smk_cipso_ops = {
|
|||
.release = seq_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Seq_file read operations for /smack/netlabel
|
||||
*/
|
||||
|
||||
static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
|
||||
{
|
||||
if (*pos == SEQ_READ_FINISHED)
|
||||
return NULL;
|
||||
|
||||
return smack_netlbladdrs;
|
||||
}
|
||||
|
||||
static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
|
||||
{
|
||||
struct smk_netlbladdr *skp = ((struct smk_netlbladdr *) v)->smk_next;
|
||||
|
||||
if (skp == NULL)
|
||||
*pos = SEQ_READ_FINISHED;
|
||||
|
||||
return skp;
|
||||
}
|
||||
/*
|
||||
#define BEMASK 0x80000000
|
||||
*/
|
||||
#define BEMASK 0x00000001
|
||||
#define BEBITS (sizeof(__be32) * 8)
|
||||
|
||||
/*
|
||||
* Print host/label pairs
|
||||
*/
|
||||
static int netlbladdr_seq_show(struct seq_file *s, void *v)
|
||||
{
|
||||
struct smk_netlbladdr *skp = (struct smk_netlbladdr *) v;
|
||||
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
|
||||
__be32 bebits;
|
||||
int maskn = 0;
|
||||
|
||||
for (bebits = BEMASK; bebits != 0; maskn++, bebits <<= 1)
|
||||
if ((skp->smk_mask.s_addr & bebits) == 0)
|
||||
break;
|
||||
|
||||
seq_printf(s, "%u.%u.%u.%u/%d %s\n",
|
||||
hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void netlbladdr_seq_stop(struct seq_file *s, void *v)
|
||||
{
|
||||
/* No-op */
|
||||
}
|
||||
|
||||
static struct seq_operations netlbladdr_seq_ops = {
|
||||
.start = netlbladdr_seq_start,
|
||||
.stop = netlbladdr_seq_stop,
|
||||
.next = netlbladdr_seq_next,
|
||||
.show = netlbladdr_seq_show,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_open_netlbladdr - open() for /smack/netlabel
|
||||
* @inode: inode structure representing file
|
||||
* @file: "netlabel" file pointer
|
||||
*
|
||||
* Connect our netlbladdr_seq_* operations with /smack/netlabel
|
||||
* file_operations
|
||||
*/
|
||||
static int smk_open_netlbladdr(struct inode *inode, struct file *file)
|
||||
{
|
||||
return seq_open(file, &netlbladdr_seq_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_netlbladdr - write() for /smack/netlabel
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to get the data from
|
||||
* @count: bytes sent
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Accepts only one netlbladdr per write call.
|
||||
* Returns number of bytes written or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct smk_netlbladdr *skp;
|
||||
struct sockaddr_in newname;
|
||||
char smack[SMK_LABELLEN];
|
||||
char *sp;
|
||||
char data[SMK_NETLBLADDRMAX];
|
||||
char *host = (char *)&newname.sin_addr.s_addr;
|
||||
int rc;
|
||||
struct netlbl_audit audit_info;
|
||||
struct in_addr mask;
|
||||
unsigned int m;
|
||||
__be32 bebits = BEMASK;
|
||||
__be32 nsa;
|
||||
|
||||
/*
|
||||
* Must have privilege.
|
||||
* No partial writes.
|
||||
* Enough data must be present.
|
||||
* "<addr/mask, as a.b.c.d/e><space><label>"
|
||||
* "<addr, as a.b.c.d><space><label>"
|
||||
*/
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
if (*ppos != 0)
|
||||
return -EINVAL;
|
||||
if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX)
|
||||
return -EINVAL;
|
||||
if (copy_from_user(data, buf, count) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
data[count] = '\0';
|
||||
|
||||
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%d %s",
|
||||
&host[0], &host[1], &host[2], &host[3], &m, smack);
|
||||
if (rc != 6) {
|
||||
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s",
|
||||
&host[0], &host[1], &host[2], &host[3], smack);
|
||||
if (rc != 5)
|
||||
return -EINVAL;
|
||||
m = BEBITS;
|
||||
}
|
||||
if (m > BEBITS)
|
||||
return -EINVAL;
|
||||
|
||||
sp = smk_import(smack, 0);
|
||||
if (sp == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
for (mask.s_addr = 0; m > 0; m--) {
|
||||
mask.s_addr |= bebits;
|
||||
bebits <<= 1;
|
||||
}
|
||||
/*
|
||||
* Only allow one writer at a time. Writes should be
|
||||
* quite rare and small in any case.
|
||||
*/
|
||||
mutex_lock(&smk_netlbladdr_lock);
|
||||
|
||||
nsa = newname.sin_addr.s_addr;
|
||||
for (skp = smack_netlbladdrs; skp != NULL; skp = skp->smk_next)
|
||||
if (skp->smk_host.sin_addr.s_addr == nsa &&
|
||||
skp->smk_mask.s_addr == mask.s_addr)
|
||||
break;
|
||||
|
||||
smk_netlabel_audit_set(&audit_info);
|
||||
|
||||
if (skp == NULL) {
|
||||
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
|
||||
if (skp == NULL)
|
||||
rc = -ENOMEM;
|
||||
else {
|
||||
rc = 0;
|
||||
skp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr;
|
||||
skp->smk_mask.s_addr = mask.s_addr;
|
||||
skp->smk_next = smack_netlbladdrs;
|
||||
skp->smk_label = sp;
|
||||
smack_netlbladdrs = skp;
|
||||
}
|
||||
} else {
|
||||
rc = netlbl_cfg_unlbl_static_del(&init_net, NULL,
|
||||
&skp->smk_host.sin_addr, &skp->smk_mask,
|
||||
PF_INET, &audit_info);
|
||||
skp->smk_label = sp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now tell netlabel about the single label nature of
|
||||
* this host so that incoming packets get labeled.
|
||||
*/
|
||||
|
||||
if (rc == 0)
|
||||
rc = netlbl_cfg_unlbl_static_add(&init_net, NULL,
|
||||
&skp->smk_host.sin_addr, &skp->smk_mask, PF_INET,
|
||||
smack_to_secid(skp->smk_label), &audit_info);
|
||||
|
||||
if (rc == 0)
|
||||
rc = count;
|
||||
|
||||
mutex_unlock(&smk_netlbladdr_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations smk_netlbladdr_ops = {
|
||||
.open = smk_open_netlbladdr,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.write = smk_write_netlbladdr,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_read_doi - read() for /smack/doi
|
||||
* @filp: file pointer, not actually used
|
||||
|
@ -891,110 +1112,6 @@ static const struct file_operations smk_onlycap_ops = {
|
|||
.write = smk_write_onlycap,
|
||||
};
|
||||
|
||||
struct option_names {
|
||||
int o_number;
|
||||
char *o_name;
|
||||
char *o_alias;
|
||||
};
|
||||
|
||||
static struct option_names netlbl_choices[] = {
|
||||
{ NETLBL_NLTYPE_RIPSO,
|
||||
NETLBL_NLTYPE_RIPSO_NAME, "ripso" },
|
||||
{ NETLBL_NLTYPE_CIPSOV4,
|
||||
NETLBL_NLTYPE_CIPSOV4_NAME, "cipsov4" },
|
||||
{ NETLBL_NLTYPE_CIPSOV4,
|
||||
NETLBL_NLTYPE_CIPSOV4_NAME, "cipso" },
|
||||
{ NETLBL_NLTYPE_CIPSOV6,
|
||||
NETLBL_NLTYPE_CIPSOV6_NAME, "cipsov6" },
|
||||
{ NETLBL_NLTYPE_UNLABELED,
|
||||
NETLBL_NLTYPE_UNLABELED_NAME, "unlabeled" },
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_read_nltype - read() for /smack/nltype
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to put the result
|
||||
* @count: maximum to send along
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Returns number of bytes read or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_read_nltype(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char bound[40];
|
||||
ssize_t rc;
|
||||
int i;
|
||||
|
||||
if (count < SMK_LABELLEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
sprintf(bound, "unknown");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
|
||||
if (smack_net_nltype == netlbl_choices[i].o_number) {
|
||||
sprintf(bound, "%s", netlbl_choices[i].o_name);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = simple_read_from_buffer(buf, count, ppos, bound, strlen(bound));
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_nltype - write() for /smack/nltype
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to get the data from
|
||||
* @count: bytes sent
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Returns number of bytes written or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_write_nltype(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char bound[40];
|
||||
char *cp;
|
||||
int i;
|
||||
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
if (count >= 40)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(bound, buf, count) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
bound[count] = '\0';
|
||||
cp = strchr(bound, ' ');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
cp = strchr(bound, '\n');
|
||||
if (cp != NULL)
|
||||
*cp = '\0';
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(netlbl_choices); i++)
|
||||
if (strcmp(bound, netlbl_choices[i].o_name) == 0 ||
|
||||
strcmp(bound, netlbl_choices[i].o_alias) == 0) {
|
||||
smack_net_nltype = netlbl_choices[i].o_number;
|
||||
return count;
|
||||
}
|
||||
/*
|
||||
* Not a valid choice.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct file_operations smk_nltype_ops = {
|
||||
.read = smk_read_nltype,
|
||||
.write = smk_write_nltype,
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_fill_super - fill the /smackfs superblock
|
||||
* @sb: the empty superblock
|
||||
|
@ -1021,8 +1138,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
|||
{"direct", &smk_direct_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_AMBIENT] =
|
||||
{"ambient", &smk_ambient_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_NLTYPE] =
|
||||
{"nltype", &smk_nltype_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_NETLBLADDR] =
|
||||
{"netlabel", &smk_netlbladdr_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_ONLYCAP] =
|
||||
{"onlycap", &smk_onlycap_ops, S_IRUGO|S_IWUSR},
|
||||
/* last one */ {""}
|
||||
|
|
Loading…
Reference in New Issue