Commit c861ea2c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

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
parents 3610639d ac8cc0fa
......@@ -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;
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 0;
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 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
/**
* 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 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
* 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 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
/**
* 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 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
* 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);
......
This diff is collapsed.
......@@ -450,13 +450,13 @@ static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)
* 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 @@ static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)
* 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.
*/
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment