summaryrefslogtreecommitdiff
path: root/security/selinux
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /security/selinux
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/hooks.c158
-rw-r--r--security/selinux/include/objsec.h4
-rw-r--r--security/selinux/include/security.h13
-rw-r--r--security/selinux/include/xfrm.h45
-rw-r--r--security/selinux/netlabel.c6
-rw-r--r--security/selinux/netnode.c2
-rw-r--r--security/selinux/nlmsgtab.c2
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/ebitmap.c20
-rw-r--r--security/selinux/ss/ebitmap.h10
-rw-r--r--security/selinux/ss/mls.c22
-rw-r--r--security/selinux/ss/mls_types.h2
-rw-r--r--security/selinux/ss/policydb.c3
-rw-r--r--security/selinux/ss/services.c66
-rw-r--r--security/selinux/xfrm.c453
15 files changed, 385 insertions, 425 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 794c3ca..5b52310 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -95,9 +95,7 @@
#include "audit.h"
#include "avc_ss.h"
-#define SB_TYPE_FMT "%s%s%s"
-#define SB_SUBTYPE(sb) (sb->s_subtype && sb->s_subtype[0])
-#define SB_TYPE_ARGS(sb) sb->s_type->name, SB_SUBTYPE(sb) ? "." : "", SB_SUBTYPE(sb) ? sb->s_subtype : ""
+#define NUM_SEL_MNT_OPTS 5
extern struct security_operations *security_ops;
@@ -141,28 +139,12 @@ static struct kmem_cache *sel_inode_cache;
* This function checks the SECMARK reference counter to see if any SECMARK
* targets are currently configured, if the reference counter is greater than
* zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
- * enabled, false (0) if SECMARK is disabled. If the always_check_network
- * policy capability is enabled, SECMARK is always considered enabled.
+ * enabled, false (0) if SECMARK is disabled.
*
*/
static int selinux_secmark_enabled(void)
{
- return (selinux_policycap_alwaysnetwork || atomic_read(&selinux_secmark_refcount));
-}
-
-/**
- * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled
- *
- * Description:
- * This function checks if NetLabel or labeled IPSEC is enabled. Returns true
- * (1) if any are enabled or false (0) if neither are enabled. If the
- * always_check_network policy capability is enabled, peer labeling
- * is always considered enabled.
- *
- */
-static int selinux_peerlbl_enabled(void)
-{
- return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
+ return (atomic_read(&selinux_secmark_refcount) > 0);
}
/*
@@ -327,11 +309,8 @@ enum {
Opt_defcontext = 3,
Opt_rootcontext = 4,
Opt_labelsupport = 5,
- Opt_nextmntopt = 6,
};
-#define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1)
-
static const match_table_t tokens = {
{Opt_context, CONTEXT_STR "%s"},
{Opt_fscontext, FSCONTEXT_STR "%s"},
@@ -376,29 +355,6 @@ static int may_context_mount_inode_relabel(u32 sid,
return rc;
}
-static int selinux_is_sblabel_mnt(struct super_block *sb)
-{
- struct superblock_security_struct *sbsec = sb->s_security;
-
- if (sbsec->behavior == SECURITY_FS_USE_XATTR ||
- sbsec->behavior == SECURITY_FS_USE_TRANS ||
- sbsec->behavior == SECURITY_FS_USE_TASK)
- return 1;
-
- /* Special handling for sysfs. Is genfs but also has setxattr handler*/
- if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
- return 1;
-
- /*
- * Special handling for rootfs. Is genfs but supports
- * setting SELinux context on in-core inodes.
- */
- if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
- return 1;
-
- return 0;
-}
-
static int sb_finish_set_opts(struct super_block *sb)
{
struct superblock_security_struct *sbsec = sb->s_security;
@@ -413,8 +369,8 @@ static int sb_finish_set_opts(struct super_block *sb)
the first boot of the SELinux kernel before we have
assigned xattr values to the filesystem. */
if (!root_inode->i_op->getxattr) {
- printk(KERN_WARNING "SELinux: (dev %s, type "SB_TYPE_FMT") has no "
- "xattr support\n", sb->s_id, SB_TYPE_ARGS(sb));
+ printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
+ "xattr support\n", sb->s_id, sb->s_type->name);
rc = -EOPNOTSUPP;
goto out;
}
@@ -422,27 +378,35 @@ static int sb_finish_set_opts(struct super_block *sb)
if (rc < 0 && rc != -ENODATA) {
if (rc == -EOPNOTSUPP)
printk(KERN_WARNING "SELinux: (dev %s, type "
- SB_TYPE_FMT") has no security xattr handler\n",
- sb->s_id, SB_TYPE_ARGS(sb));
+ "%s) has no security xattr handler\n",
+ sb->s_id, sb->s_type->name);
else
printk(KERN_WARNING "SELinux: (dev %s, type "
- SB_TYPE_FMT") getxattr errno %d\n", sb->s_id,
- SB_TYPE_ARGS(sb), -rc);
+ "%s) getxattr errno %d\n", sb->s_id,
+ sb->s_type->name, -rc);
goto out;
}
}
+ sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
+
if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
- printk(KERN_ERR "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), unknown behavior\n",
- sb->s_id, SB_TYPE_ARGS(sb));
+ printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
+ sb->s_id, sb->s_type->name);
else
- printk(KERN_DEBUG "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), %s\n",
- sb->s_id, SB_TYPE_ARGS(sb),
+ printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n",
+ sb->s_id, sb->s_type->name,
labeling_behaviors[sbsec->behavior-1]);
- sbsec->flags |= SE_SBINITIALIZED;
- if (selinux_is_sblabel_mnt(sb))
- sbsec->flags |= SBLABEL_MNT;
+ if (sbsec->behavior == SECURITY_FS_USE_GENFS ||
+ sbsec->behavior == SECURITY_FS_USE_MNTPOINT ||
+ sbsec->behavior == SECURITY_FS_USE_NONE ||
+ sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
+ sbsec->flags &= ~SE_SBLABELSUPP;
+
+ /* Special handling for sysfs. Is genfs but also has setxattr handler*/
+ if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
+ sbsec->flags |= SE_SBLABELSUPP;
/* Initialize the root inode. */
rc = inode_doinit_with_dentry(root_inode, root);
@@ -496,18 +460,15 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
if (!ss_initialized)
return -EINVAL;
- /* make sure we always check enough bits to cover the mask */
- BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS));
-
tmp = sbsec->flags & SE_MNTMASK;
/* count the number of mount options for this sb */
- for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
+ for (i = 0; i < 8; i++) {
if (tmp & 0x01)
opts->num_mnt_opts++;
tmp >>= 1;
}
/* Check if the Label support flag is set */
- if (sbsec->flags & SBLABEL_MNT)
+ if (sbsec->flags & SE_SBLABELSUPP)
opts->num_mnt_opts++;
opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
@@ -554,9 +515,9 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
}
- if (sbsec->flags & SBLABEL_MNT) {
+ if (sbsec->flags & SE_SBLABELSUPP) {
opts->mnt_opts[i] = NULL;
- opts->mnt_opts_flags[i++] = SBLABEL_MNT;
+ opts->mnt_opts_flags[i++] = SE_SBLABELSUPP;
}
BUG_ON(i != opts->num_mnt_opts);
@@ -600,6 +561,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
const struct cred *cred = current_cred();
int rc = 0, i;
struct superblock_security_struct *sbsec = sb->s_security;
+ const char *name = sb->s_type->name;
struct inode *inode = sbsec->sb->s_root->d_inode;
struct inode_security_struct *root_isec = inode->i_security;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
@@ -652,14 +614,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
for (i = 0; i < num_opts; i++) {
u32 sid;
- if (flags[i] == SBLABEL_MNT)
+ if (flags[i] == SE_SBLABELSUPP)
continue;
rc = security_context_to_sid(mount_options[i],
strlen(mount_options[i]), &sid);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
- "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n",
- mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc);
+ "(%s) failed for (dev %s, type %s) errno=%d\n",
+ mount_options[i], sb->s_id, name, rc);
goto out;
}
switch (flags[i]) {
@@ -723,7 +685,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this
* filesystem type.
*/
- rc = security_fs_use(sb);
+ rc = security_fs_use((sbsec->flags & SE_SBPROC) ?
+ "proc" : sb->s_type->name,
+ &sbsec->behavior, &sbsec->sid);
if (rc) {
printk(KERN_WARNING
"%s: security_fs_use(%s) returned %d\n",
@@ -806,8 +770,7 @@ out:
out_double_mount:
rc = -EINVAL;
printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
- "security settings for (dev %s, type "SB_TYPE_FMT")\n", sb->s_id,
- SB_TYPE_ARGS(sb));
+ "security settings for (dev %s, type %s)\n", sb->s_id, name);
goto out;
}
@@ -1074,7 +1037,7 @@ static void selinux_write_opts(struct seq_file *m,
case DEFCONTEXT_MNT:
prefix = DEFCONTEXT_STR;
break;
- case SBLABEL_MNT:
+ case SE_SBLABELSUPP:
seq_putc(m, ',');
seq_puts(m, LABELSUPP_STR);
continue;
@@ -1686,7 +1649,7 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- if (!newsid || !(sbsec->flags & SBLABEL_MNT)) {
+ if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
rc = security_transition_sid(sid, dsec->sid, tclass,
&dentry->d_name, &newsid);
if (rc)
@@ -2474,14 +2437,14 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
u32 sid;
size_t len;
- if (flags[i] == SBLABEL_MNT)
+ if (flags[i] == SE_SBLABELSUPP)
continue;
len = strlen(mount_options[i]);
rc = security_context_to_sid(mount_options[i], len, &sid);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid"
- "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n",
- mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc);
+ "(%s) failed for (dev %s, type %s) errno=%d\n",
+ mount_options[i], sb->s_id, sb->s_type->name, rc);
goto out_free_opts;
}
rc = -EINVAL;
@@ -2519,8 +2482,8 @@ out_free_secdata:
return rc;
out_bad_option:
printk(KERN_WARNING "SELinux: unable to change security options "
- "during remount (dev %s, type "SB_TYPE_FMT")\n", sb->s_id,
- SB_TYPE_ARGS(sb));
+ "during remount (dev %s, type=%s)\n", sb->s_id,
+ sb->s_type->name);
goto out_free_opts;
}
@@ -2643,7 +2606,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
if ((sbsec->flags & SE_SBINITIALIZED) &&
(sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
newsid = sbsec->mntpoint_sid;
- else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) {
+ else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
rc = security_transition_sid(sid, dsec->sid,
inode_mode_to_security_class(inode->i_mode),
qstr, &newsid);
@@ -2665,7 +2628,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec->initialized = 1;
}
- if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT))
+ if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP))
return -EOPNOTSUPP;
if (name)
@@ -2867,7 +2830,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return selinux_inode_setotherxattr(dentry, name);
sbsec = inode->i_sb->s_security;
- if (!(sbsec->flags & SBLABEL_MNT))
+ if (!(sbsec->flags & SE_SBLABELSUPP))
return -EOPNOTSUPP;
if (!inode_owner_or_capable(inode))
@@ -3828,12 +3791,8 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
u32 nlbl_sid;
u32 nlbl_type;
- err = selinux_skb_xfrm_sid(skb, &xfrm_sid);
- if (unlikely(err))
- return -EACCES;
- err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
- if (unlikely(err))
- return -EACCES;
+ selinux_skb_xfrm_sid(skb, &xfrm_sid);
+ selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
if (unlikely(err)) {
@@ -3969,7 +3928,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (snum) {
int low, high;
- inet_get_local_port_range(sock_net(sk), &low, &high);
+ inet_get_local_port_range(&low, &high);
if (snum < max(PROT_SOCK, low) || snum > high) {
err = sel_netport_sid(sk->sk_protocol,
@@ -4287,7 +4246,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return selinux_sock_rcv_skb_compat(sk, skb, family);
secmark_active = selinux_secmark_enabled();
- peerlbl_active = selinux_peerlbl_enabled();
+ peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
if (!secmark_active && !peerlbl_active)
return 0;
@@ -4669,7 +4628,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
secmark_active = selinux_secmark_enabled();
netlbl_active = netlbl_enabled();
- peerlbl_active = selinux_peerlbl_enabled();
+ peerlbl_active = netlbl_active || selinux_xfrm_enabled();
if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
@@ -4708,7 +4667,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
return NF_ACCEPT;
}
-static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
+static unsigned int selinux_ipv4_forward(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -4718,7 +4677,7 @@ static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
+static unsigned int selinux_ipv6_forward(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -4750,7 +4709,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
return NF_ACCEPT;
}
-static unsigned int selinux_ipv4_output(const struct nf_hook_ops *ops,
+static unsigned int selinux_ipv4_output(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -4821,7 +4780,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
return NF_ACCEPT;
#endif
secmark_active = selinux_secmark_enabled();
- peerlbl_active = selinux_peerlbl_enabled();
+ peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled();
if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
@@ -4877,7 +4836,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
return NF_ACCEPT;
}
-static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
+static unsigned int selinux_ipv4_postroute(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -4887,7 +4846,7 @@ static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
+static unsigned int selinux_ipv6_postroute(unsigned int hooknum,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -5825,8 +5784,7 @@ static struct security_operations selinux_ops = {
.xfrm_policy_clone_security = selinux_xfrm_policy_clone,
.xfrm_policy_free_security = selinux_xfrm_policy_free,
.xfrm_policy_delete_security = selinux_xfrm_policy_delete,
- .xfrm_state_alloc = selinux_xfrm_state_alloc,
- .xfrm_state_alloc_acquire = selinux_xfrm_state_alloc_acquire,
+ .xfrm_state_alloc_security = selinux_xfrm_state_alloc,
.xfrm_state_free_security = selinux_xfrm_state_free,
.xfrm_state_delete_security = selinux_xfrm_state_delete,
.xfrm_policy_lookup = selinux_xfrm_policy_lookup,
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index b1dfe10..aa47bca 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -58,8 +58,8 @@ struct superblock_security_struct {
u32 sid; /* SID of file system superblock */
u32 def_sid; /* default SID for labeling */
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
- unsigned short behavior; /* labeling behavior */
- unsigned short flags; /* which mount options were specified */
+ unsigned int behavior; /* labeling behavior */
+ unsigned char flags; /* which mount options were specified */
struct mutex lock;
struct list_head isec_head;
spinlock_t isec_lock;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index fe341ae..8fd8e18 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -45,15 +45,14 @@
/* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f
/* Super block security struct flags for mount options */
-/* BE CAREFUL, these need to be the low order bits for selinux_get_mnt_opts */
#define CONTEXT_MNT 0x01
#define FSCONTEXT_MNT 0x02
#define ROOTCONTEXT_MNT 0x04
#define DEFCONTEXT_MNT 0x08
-#define SBLABEL_MNT 0x10
/* Non-mount related flags */
-#define SE_SBINITIALIZED 0x0100
-#define SE_SBPROC 0x0200
+#define SE_SBINITIALIZED 0x10
+#define SE_SBPROC 0x20
+#define SE_SBLABELSUPP 0x40
#define CONTEXT_STR "context="
#define FSCONTEXT_STR "fscontext="
@@ -69,15 +68,12 @@ extern int selinux_enabled;
enum {
POLICYDB_CAPABILITY_NETPEER,
POLICYDB_CAPABILITY_OPENPERM,
- POLICYDB_CAPABILITY_REDHAT1,
- POLICYDB_CAPABILITY_ALWAYSNETWORK,
__POLICYDB_CAPABILITY_MAX
};
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
extern int selinux_policycap_netpeer;
extern int selinux_policycap_openperm;
-extern int selinux_policycap_alwaysnetwork;
/*
* type_datum properties
@@ -176,7 +172,8 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
-int security_fs_use(struct super_block *sb);
+int security_fs_use(const char *fstype, unsigned int *behavior,
+ u32 *sid);
int security_genfs_sid(const char *fstype, char *name, u16 sclass,
u32 *sid);
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 0dec76c..6713f04 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -10,21 +10,29 @@
#include <net/flow.h>
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *uctx);
+ struct xfrm_user_sec_ctx *sec_ctx);
int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp);
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
int selinux_xfrm_state_alloc(struct xfrm_state *x,
- struct xfrm_user_sec_ctx *uctx);
-int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
- struct xfrm_sec_ctx *polsec, u32 secid);
+ struct xfrm_user_sec_ctx *sec_ctx, u32 secid);
void selinux_xfrm_state_free(struct xfrm_state *x);
int selinux_xfrm_state_delete(struct xfrm_state *x);
int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
- struct xfrm_policy *xp,
- const struct flowi *fl);
+ struct xfrm_policy *xp, const struct flowi *fl);
+
+/*
+ * Extract the security blob from the sock (it's actually on the socket)
+ */
+static inline struct inode_security_struct *get_sock_isec(struct sock *sk)
+{
+ if (!sk->sk_socket)
+ return NULL;
+
+ return SOCK_INODE(sk->sk_socket)->i_security;
+}
#ifdef CONFIG_SECURITY_NETWORK_XFRM
extern atomic_t selinux_xfrm_refcount;
@@ -34,10 +42,10 @@ static inline int selinux_xfrm_enabled(void)
return (atomic_read(&selinux_xfrm_refcount) > 0);
}
-int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
- struct common_audit_data *ad);
-int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
- struct common_audit_data *ad, u8 proto);
+int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,
+ struct common_audit_data *ad);
+int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
+ struct common_audit_data *ad, u8 proto);
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
static inline void selinux_xfrm_notify_policyload(void)
@@ -56,21 +64,19 @@ static inline int selinux_xfrm_enabled(void)
return 0;
}
-static inline int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
- struct common_audit_data *ad)
+static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
+ struct common_audit_data *ad)
{
return 0;
}
-static inline int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
- struct common_audit_data *ad,
- u8 proto)
+static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
+ struct common_audit_data *ad, u8 proto)
{
return 0;
}
-static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid,
- int ckall)
+static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
{
*sid = SECSID_NULL;
return 0;
@@ -81,9 +87,10 @@ static inline void selinux_xfrm_notify_policyload(void)
}
#endif
-static inline int selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
+static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
{
- return selinux_xfrm_decode_session(skb, sid, 0);
+ int err = selinux_xfrm_decode_session(skb, sid, 0);
+ BUG_ON(err);
}
#endif /* _SELINUX_XFRM_H_ */
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 6235d05..da4b8b2 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -442,7 +442,8 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
sksec->nlbl_state != NLBL_CONNLABELED)
return 0;
- lock_sock(sk);
+ local_bh_disable();
+ bh_lock_sock_nested(sk);
/* connected sockets are allowed to disconnect when the address family
* is set to AF_UNSPEC, if that is what is happening we want to reset
@@ -463,6 +464,7 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
sksec->nlbl_state = NLBL_CONNLABELED;
socket_connect_return:
- release_sock(sk);
+ bh_unlock_sock(sk);
+ local_bh_enable();
return rc;
}
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 03a72c3..c5454c0 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -166,7 +166,6 @@ static void sel_netnode_insert(struct sel_netnode *node)
break;
default:
BUG();
- return;
}
/* we need to impose a limit on the growth of the hash table so check
@@ -226,7 +225,6 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
break;
default:
BUG();
- ret = -EINVAL;
}
if (ret != 0)
goto out;
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 332ac8a..855e464 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -116,8 +116,6 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
{ AUDIT_MAKE_EQUIV, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
{ AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_TTY_AUDIT },
- { AUDIT_GET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_SET_FEATURE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
};
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5122aff..ff42773 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -44,9 +44,7 @@
/* Policy capability filenames */
static char *policycap_names[] = {
"network_peer_controls",
- "open_perms",
- "redhat1",
- "always_check_network"
+ "open_perms"
};
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 820313a..30f119b 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -213,12 +213,7 @@ netlbl_import_failure:
}
#endif /* CONFIG_NETLABEL */
-/*
- * Check to see if all the bits set in e2 are also set in e1. Optionally,
- * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed
- * last_e2bit.
- */
-int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
int i;
@@ -228,25 +223,14 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)
n1 = e1->node;
n2 = e2->node;
-
while (n1 && n2 && (n1->startbit <= n2->startbit)) {
if (n1->startbit < n2->startbit) {
n1 = n1->next;
continue;
}
- for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; )
- i--; /* Skip trailing NULL map entries */
- if (last_e2bit && (i >= 0)) {
- u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE +
- __fls(n2->maps[i]);
- if (lastsetbit > last_e2bit)
- return 0;
- }
-
- while (i >= 0) {
+ for (i = 0; i < EBITMAP_UNIT_NUMS; i++) {
if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
return 0;
- i--;
}
n1 = n1->next;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 712c8a7..922f8af 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -16,13 +16,7 @@
#include <net/netlabel.h>
-#ifdef CONFIG_64BIT
-#define EBITMAP_NODE_SIZE 64
-#else
-#define EBITMAP_NODE_SIZE 32
-#endif
-
-#define EBITMAP_UNIT_NUMS ((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\
+#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \
/ sizeof(unsigned long))
#define EBITMAP_UNIT_SIZE BITS_PER_LONG
#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
@@ -123,7 +117,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
-int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit);
+int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
void ebitmap_destroy(struct ebitmap *e);
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index c85bc1e..40de8d3 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -160,6 +160,8 @@ void mls_sid_to_context(struct context *context,
int mls_level_isvalid(struct policydb *p, struct mls_level *l)
{
struct level_datum *levdatum;
+ struct ebitmap_node *node;
+ int i;
if (!l->sens || l->sens > p->p_levels.nprim)
return 0;
@@ -168,13 +170,19 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
if (!levdatum)
return 0;
- /*
- * Return 1 iff all the bits set in l->cat are also be set in
- * levdatum->level->cat and no bit in l->cat is larger than
- * p->p_cats.nprim.
- */
- return ebitmap_contains(&levdatum->level->cat, &l->cat,
- p->p_cats.nprim);
+ ebitmap_for_each_positive_bit(&l->cat, node, i) {
+ if (i > p->p_cats.nprim)
+ return 0;
+ if (!ebitmap_get_bit(&levdatum->level->cat, i)) {
+ /*
+ * Category may not be associated with
+ * sensitivity.
+ */
+ return 0;
+ }
+ }
+
+ return 1;
}
int mls_range_isvalid(struct policydb *p, struct mls_range *r)
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h
index e936487..03bed52 100644
--- a/security/selinux/ss/mls_types.h
+++ b/security/selinux/ss/mls_types.h
@@ -35,7 +35,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
{
return ((l1->sens >= l2->sens) &&
- ebitmap_contains(&l1->cat, &l2->cat, 0));
+ ebitmap_contains(&l1->cat, &l2->cat));
}
#define mls_level_incomp(l1, l2) \
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f6195eb..c8adde3 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -3203,8 +3203,9 @@ static int range_write_helper(void *key, void *data, void *ptr)
static int range_write(struct policydb *p, void *fp)
{
+ size_t nel;
__le32 buf[1];
- int rc, nel;
+ int rc;
struct policy_data pd;
pd.p = p;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index ee470a0..b4feecc 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -72,7 +72,6 @@
int selinux_policycap_netpeer;
int selinux_policycap_openperm;
-int selinux_policycap_alwaysnetwork;
static DEFINE_RWLOCK(policy_rwlock);
@@ -1813,8 +1812,6 @@ static void security_load_policycaps(void)
POLICYDB_CAPABILITY_NETPEER);
selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_OPENPERM);
- selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
- POLICYDB_CAPABILITY_ALWAYSNETWORK);
}
static int security_preserve_bools(struct policydb *p);
@@ -2326,74 +2323,43 @@ out:
/**
* security_fs_use - Determine how to handle labeling for a filesystem.
- * @sb: superblock in question
+ * @fstype: filesystem type
+ * @behavior: labeling behavior
+ * @sid: SID for filesystem (superblock)
*/
-int security_fs_use(struct super_block *sb)
+int security_fs_use(
+ const char *fstype,
+ unsigned int *behavior,
+ u32 *sid)
{
int rc = 0;
struct ocontext *c;
- struct superblock_security_struct *sbsec = sb->s_security;
- const char *fstype = sb->s_type->name;
- const char *subtype = (sb->s_subtype && sb->s_subtype[0]) ? sb->s_subtype : NULL;
- struct ocontext *base = NULL;
read_lock(&policy_rwlock);
- for (c = policydb.ocontexts[OCON_FSUSE]; c; c = c->next) {
- char *sub;
- int baselen;
-
- baselen = strlen(fstype);
-
- /* if base does not match, this is not the one */
- if (strncmp(fstype, c->u.name, baselen))
- continue;
-
- /* if there is no subtype, this is the one! */
- if (!subtype)
- break;
-
- /* skip past the base in this entry */
- sub = c->u.name + baselen;
-
- /* entry is only a base. save it. keep looking for subtype */
- if (sub[0] == '\0') {
- base = c;
- continue;
- }
-
- /* entry is not followed by a subtype, so it is not a match */
- if (sub[0] != '.')
- continue;
-
- /* whew, we found a subtype of this fstype */
- sub++; /* move past '.' */
-
- /* exact match of fstype AND subtype */
- if (!strcmp(subtype, sub))
+ c = policydb.ocontexts[OCON_FSUSE];
+ while (c) {
+ if (strcmp(fstype, c->u.name) == 0)
break;
+ c = c->next;
}
- /* in case we had found an fstype match but no subtype match */
- if (!c)
- c = base;
-
if (c) {
- sbsec->behavior = c->v.behavior;
+ *behavior = c->v.behavior;
if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, &c->context[0],
&c->sid[0]);
if (rc)
goto out;
}
- sbsec->sid = c->sid[0];
+ *sid = c->sid[0];
} else {
- rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid);
+ rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
if (rc) {
- sbsec->behavior = SECURITY_FS_USE_NONE;
+ *behavior = SECURITY_FS_USE_NONE;
rc = 0;
} else {
- sbsec->behavior = SECURITY_FS_USE_GENFS;
+ *behavior = SECURITY_FS_USE_GENFS;
}
}
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index a91d205..d030818 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -56,7 +56,7 @@
atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
/*
- * Returns true if the context is an LSM/SELinux context.
+ * Returns true if an LSM/SELinux context
*/
static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
{
@@ -66,7 +66,7 @@ static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx)
}
/*
- * Returns true if the xfrm contains a security blob for SELinux.
+ * Returns true if the xfrm contains a security blob for SELinux
*/
static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
{
@@ -74,111 +74,48 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
}
/*
- * Allocates a xfrm_sec_state and populates it using the supplied security
- * xfrm_user_sec_ctx context.
- */
-static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *uctx)
-{
- int rc;
- const struct task_security_struct *tsec = current_security();
- struct xfrm_sec_ctx *ctx = NULL;
- u32 str_len;
-
- if (ctxp == NULL || uctx == NULL ||
- uctx->ctx_doi != XFRM_SC_DOI_LSM ||
- uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
- return -EINVAL;
-
- str_len = uctx->ctx_len;
- if (str_len >= PAGE_SIZE)
- return -ENOMEM;
-
- ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
-
- ctx->ctx_doi = XFRM_SC_DOI_LSM;
- ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
- ctx->ctx_len = str_len;
- memcpy(ctx->ctx_str, &uctx[1], str_len);
- ctx->ctx_str[str_len] = '\0';
- rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid);
- if (rc)
- goto err;
-
- rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
- if (rc)
- goto err;
-
- *ctxp = ctx;
- atomic_inc(&selinux_xfrm_refcount);
- return 0;
-
-err:
- kfree(ctx);
- return rc;
-}
-
-/*
- * Free the xfrm_sec_ctx structure.
- */
-static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
-{
- if (!ctx)
- return;
-
- atomic_dec(&selinux_xfrm_refcount);
- kfree(ctx);
-}
-
-/*
- * Authorize the deletion of a labeled SA or policy rule.
- */
-static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
-{
- const struct task_security_struct *tsec = current_security();
-
- if (!ctx)
- return 0;
-
- return avc_has_perm(tsec->sid, ctx->ctx_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
- NULL);
-}
-
-/*
- * LSM hook implementation that authorizes that a flow can use a xfrm policy
- * rule.
+ * LSM hook implementation that authorizes that a flow can use
+ * a xfrm policy rule.
*/
int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
{
int rc;
+ u32 sel_sid;
- /* All flows should be treated as polmatch'ing an otherwise applicable
- * "non-labeled" policy. This would prevent inadvertent "leaks". */
- if (!ctx)
+ /* Context sid is either set to label or ANY_ASSOC */
+ if (ctx) {
+ if (!selinux_authorizable_ctx(ctx))
+ return -EINVAL;
+
+ sel_sid = ctx->ctx_sid;
+ } else
+ /*
+ * All flows should be treated as polmatch'ing an
+ * otherwise applicable "non-labeled" policy. This
+ * would prevent inadvertent "leaks".
+ */
return 0;
- /* Context sid is either set to label or ANY_ASSOC */
- if (!selinux_authorizable_ctx(ctx))
- return -EINVAL;
+ rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION,
+ ASSOCIATION__POLMATCH,
+ NULL);
+
+ if (rc == -EACCES)
+ return -ESRCH;
- rc = avc_has_perm(fl_secid, ctx->ctx_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
- return (rc == -EACCES ? -ESRCH : rc);
+ return rc;
}
/*
* LSM hook implementation that authorizes that a state matches
* the given policy, flow combo.
*/
-int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
- struct xfrm_policy *xp,
- const struct flowi *fl)
+
+int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp,
+ const struct flowi *fl)
{
u32 state_sid;
+ int rc;
if (!xp->security)
if (x->security)
@@ -201,80 +138,187 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
if (fl->flowi_secid != state_sid)
return 0;
- /* We don't need a separate SA Vs. policy polmatch check since the SA
- * is now of the same label as the flow and a flow Vs. policy polmatch
- * check had already happened in selinux_xfrm_policy_lookup() above. */
- return (avc_has_perm(fl->flowi_secid, state_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
- NULL) ? 0 : 1);
+ rc = avc_has_perm(fl->flowi_secid, state_sid, SECCLASS_ASSOCIATION,
+ ASSOCIATION__SENDTO,
+ NULL)? 0:1;
+
+ /*
+ * We don't need a separate SA Vs. policy polmatch check
+ * since the SA is now of the same label as the flow and
+ * a flow Vs. policy polmatch check had already happened
+ * in selinux_xfrm_policy_lookup() above.
+ */
+
+ return rc;
}
/*
* LSM hook implementation that checks and/or returns the xfrm sid for the
* incoming packet.
*/
+
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
{
- u32 sid_session = SECSID_NULL;
struct sec_path *sp;
+ *sid = SECSID_NULL;
+
if (skb == NULL)
- goto out;
+ return 0;
sp = skb->sp;
if (sp) {
- int i;
+ int i, sid_set = 0;
- for (i = sp->len - 1; i >= 0; i--) {
+ for (i = sp->len-1; i >= 0; i--) {
struct xfrm_state *x = sp->xvec[i];
if (selinux_authorizable_xfrm(x)) {
struct xfrm_sec_ctx *ctx = x->security;
- if (sid_session == SECSID_NULL) {
- sid_session = ctx->ctx_sid;
+ if (!sid_set) {
+ *sid = ctx->ctx_sid;
+ sid_set = 1;
+
if (!ckall)
- goto out;
- } else if (sid_session != ctx->ctx_sid) {
- *sid = SECSID_NULL;
+ break;
+ } else if (*sid != ctx->ctx_sid)
return -EINVAL;
- }
}
}
}
-out:
- *sid = sid_session;
return 0;
}
/*
- * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
+ * Security blob allocation for xfrm_policy and xfrm_state
+ * CTX does not have a meaningful value on input
+ */
+static int selinux_xfrm_sec_ctx_alloc(struct xfrm_sec_ctx **ctxp,
+ struct xfrm_user_sec_ctx *uctx, u32 sid)
+{
+ int rc = 0;
+ const struct task_security_struct *tsec = current_security();
+ struct xfrm_sec_ctx *ctx = NULL;
+ char *ctx_str = NULL;
+ u32 str_len;
+
+ BUG_ON(uctx && sid);
+
+ if (!uctx)
+ goto not_from_user;
+
+ if (uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
+ return -EINVAL;
+
+ str_len = uctx->ctx_len;
+ if (str_len >= PAGE_SIZE)
+ return -ENOMEM;
+
+ *ctxp = ctx = kmalloc(sizeof(*ctx) +
+ str_len + 1,
+ GFP_KERNEL);
+
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->ctx_doi = uctx->ctx_doi;
+ ctx->ctx_len = str_len;
+ ctx->ctx_alg = uctx->ctx_alg;
+
+ memcpy(ctx->ctx_str,
+ uctx+1,
+ str_len);
+ ctx->ctx_str[str_len] = 0;
+ rc = security_context_to_sid(ctx->ctx_str,
+ str_len,
+ &ctx->ctx_sid);
+
+ if (rc)
+ goto out;
+
+ /*
+ * Does the subject have permission to set security context?
+ */
+ rc = avc_has_perm(tsec->sid, ctx->ctx_sid,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__SETCONTEXT, NULL);
+ if (rc)
+ goto out;
+
+ return rc;
+
+not_from_user:
+ rc = security_sid_to_context(sid, &ctx_str, &str_len);
+ if (rc)
+ goto out;
+
+ *ctxp = ctx = kmalloc(sizeof(*ctx) +
+ str_len,
+ GFP_ATOMIC);
+
+ if (!ctx) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ ctx->ctx_doi = XFRM_SC_DOI_LSM;
+ ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
+ ctx->ctx_sid = sid;
+ ctx->ctx_len = str_len;
+ memcpy(ctx->ctx_str,
+ ctx_str,
+ str_len);
+
+ goto out2;
+
+out:
+ *ctxp = NULL;
+ kfree(ctx);
+out2:
+ kfree(ctx_str);
+ return rc;
+}
+
+/*
+ * LSM hook implementation that allocs and transfers uctx spec to
+ * xfrm_policy.
*/
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx)
{
- return selinux_xfrm_alloc_user(ctxp, uctx);
+ int err;
+
+ BUG_ON(!uctx);
+
+ err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0);
+ if (err == 0)
+ atomic_inc(&selinux_xfrm_refcount);
+
+ return err;
}
+
/*
- * LSM hook implementation that copies security data structure from old to new
- * for policy cloning.
+ * LSM hook implementation that copies security data structure from old to
+ * new for policy cloning.
*/
int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp)
{
struct xfrm_sec_ctx *new_ctx;
- if (!old_ctx)
- return 0;
-
- new_ctx = kmemdup(old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len,
- GFP_ATOMIC);
- if (!new_ctx)
- return -ENOMEM;
- atomic_inc(&selinux_xfrm_refcount);
- *new_ctxp = new_ctx;
+ if (old_ctx) {
+ new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len,
+ GFP_ATOMIC);
+ if (!new_ctx)
+ return -ENOMEM;
+ memcpy(new_ctx, old_ctx, sizeof(*new_ctx));
+ memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len);
+ atomic_inc(&selinux_xfrm_refcount);
+ *new_ctxp = new_ctx;
+ }
return 0;
}
@@ -283,7 +327,8 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
*/
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
{
- selinux_xfrm_free(ctx);
+ atomic_dec(&selinux_xfrm_refcount);
+ kfree(ctx);
}
/*
@@ -291,55 +336,31 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
*/
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
{
- return selinux_xfrm_delete(ctx);
-}
+ const struct task_security_struct *tsec = current_security();
-/*
- * LSM hook implementation that allocates a xfrm_sec_state, populates it using
- * the supplied security context, and assigns it to the xfrm_state.
- */
-int selinux_xfrm_state_alloc(struct xfrm_state *x,
- struct xfrm_user_sec_ctx *uctx)
-{
- return selinux_xfrm_alloc_user(&x->security, uctx);
+ if (!ctx)
+ return 0;
+
+ return avc_has_perm(tsec->sid, ctx->ctx_sid,
+ SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
+ NULL);
}
/*
- * LSM hook implementation that allocates a xfrm_sec_state and populates based
- * on a secid.
+ * LSM hook implementation that allocs and transfers sec_ctx spec to
+ * xfrm_state.
*/
-int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
- struct xfrm_sec_ctx *polsec, u32 secid)
+int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uctx,
+ u32 secid)
{
- int rc;
- struct xfrm_sec_ctx *ctx;
- char *ctx_str = NULL;
- int str_len;
-
- if (!polsec)
- return 0;
+ int err;
- if (secid == 0)
- return -EINVAL;
+ BUG_ON(!x);
- rc = security_sid_to_context(secid, &ctx_str, &str_len);
- if (rc)
- return rc;
-
- ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC);
- if (!ctx)
- return -ENOMEM;
-
- ctx->ctx_doi = XFRM_SC_DOI_LSM;
- ctx->ctx_alg = XFRM_SC_ALG_SELINUX;
- ctx->ctx_sid = secid;
- ctx->ctx_len = str_len;
- memcpy(ctx->ctx_str, ctx_str, str_len);
- kfree(ctx_str);
-
- x->security = ctx;
- atomic_inc(&selinux_xfrm_refcount);
- return 0;
+ err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid);
+ if (err == 0)
+ atomic_inc(&selinux_xfrm_refcount);
+ return err;
}
/*
@@ -347,15 +368,24 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
*/
void selinux_xfrm_state_free(struct xfrm_state *x)
{
- selinux_xfrm_free(x->security);
+ atomic_dec(&selinux_xfrm_refcount);
+ kfree(x->security);
}
-/*
- * LSM hook implementation that authorizes deletion of labeled SAs.
- */
+ /*
+ * LSM hook implementation that authorizes deletion of labeled SAs.
+ */
int selinux_xfrm_state_delete(struct xfrm_state *x)
{
- return selinux_xfrm_delete(x->security);
+ const struct task_security_struct *tsec = current_security();
+ struct xfrm_sec_ctx *ctx = x->security;
+
+ if (!ctx)
+ return 0;
+
+ return avc_has_perm(tsec->sid, ctx->ctx_sid,
+ SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
+ NULL);
}
/*
@@ -365,12 +395,14 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
* we need to check for unlabelled access since this may not have
* gone thru the IPSec process.
*/
-int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
- struct common_audit_data *ad)
+int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
+ struct common_audit_data *ad)
{
- int i;
- struct sec_path *sp = skb->sp;
- u32 peer_sid = SECINITSID_UNLABELED;
+ int i, rc = 0;
+ struct sec_path *sp;
+ u32 sel_sid = SECINITSID_UNLABELED;
+
+ sp = skb->sp;
if (sp) {
for (i = 0; i < sp->len; i++) {
@@ -378,17 +410,23 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
if (x && selinux_authorizable_xfrm(x)) {
struct xfrm_sec_ctx *ctx = x->security;
- peer_sid = ctx->ctx_sid;
+ sel_sid = ctx->ctx_sid;
break;
}
}
}
- /* This check even when there's no association involved is intended,
- * according to Trent Jaeger, to make sure a process can't engage in
- * non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(sk_sid, peer_sid,
- SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
+ /*
+ * This check even when there's no association involved is
+ * intended, according to Trent Jaeger, to make sure a
+ * process can't engage in non-ipsec communication unless
+ * explicitly allowed by policy.
+ */
+
+ rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION,
+ ASSOCIATION__RECVFROM, ad);
+
+ return rc;
}
/*
@@ -398,38 +436,49 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
* If we do have a authorizable security association, then it has already been
* checked in the selinux_xfrm_state_pol_flow_match hook above.
*/
-int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
- struct common_audit_data *ad, u8 proto)
+int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb,
+ struct common_audit_data *ad, u8 proto)
{
struct dst_entry *dst;
+ int rc = 0;
+
+ dst = skb_dst(skb);
+
+ if (dst) {
+ struct dst_entry *dst_test;
+
+ for (dst_test = dst; dst_test != NULL;
+ dst_test = dst_test->child) {
+ struct xfrm_state *x = dst_test->xfrm;
+
+ if (x && selinux_authorizable_xfrm(x))
+ goto out;
+ }
+ }
switch (proto) {
case IPPROTO_AH:
case IPPROTO_ESP:
case IPPROTO_COMP:
- /* We should have already seen this packet once before it
- * underwent xfrm(s). No need to subject it to the unlabeled
- * check. */
- return 0;
+ /*
+ * We should have already seen this packet once before
+ * it underwent xfrm(s). No need to subject it to the
+ * unlabeled check.
+ */
+ goto out;
default:
break;
}
- dst = skb_dst(skb);
- if (dst) {
- struct dst_entry *iter;
-
- for (iter = dst; iter != NULL; iter = iter->child) {
- struct xfrm_state *x = iter->xfrm;
-
- if (x && selinux_authorizable_xfrm(x))
- return 0;
- }
- }
+ /*
+ * This check even when there's no association involved is
+ * intended, according to Trent Jaeger, to make sure a
+ * process can't engage in non-ipsec communication unless
+ * explicitly allowed by policy.
+ */
- /* This check even when there's no association involved is intended,
- * according to Trent Jaeger, to make sure a process can't engage in
- * non-IPsec communication unless explicitly allowed by policy. */
- return avc_has_perm(sk_sid, SECINITSID_UNLABELED,
- SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
+ rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
+ ASSOCIATION__SENDTO, ad);
+out:
+ return rc;
}