diff options
author | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2014-04-07 23:49:35 (GMT) |
commit | 62b8c978ee6b8d135d9e7953221de58000dba986 (patch) | |
tree | 683b04b2e627f6710c22c151b23c8cc9a165315e /security/selinux | |
parent | 78fd82238d0e5716578c326404184a27ba67fd6e (diff) | |
download | linux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz |
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 158 | ||||
-rw-r--r-- | security/selinux/include/objsec.h | 4 | ||||
-rw-r--r-- | security/selinux/include/security.h | 13 | ||||
-rw-r--r-- | security/selinux/include/xfrm.h | 45 | ||||
-rw-r--r-- | security/selinux/netlabel.c | 6 | ||||
-rw-r--r-- | security/selinux/netnode.c | 2 | ||||
-rw-r--r-- | security/selinux/nlmsgtab.c | 2 | ||||
-rw-r--r-- | security/selinux/selinuxfs.c | 4 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.c | 20 | ||||
-rw-r--r-- | security/selinux/ss/ebitmap.h | 10 | ||||
-rw-r--r-- | security/selinux/ss/mls.c | 22 | ||||
-rw-r--r-- | security/selinux/ss/mls_types.h | 2 | ||||
-rw-r--r-- | security/selinux/ss/policydb.c | 3 | ||||
-rw-r--r-- | security/selinux/ss/services.c | 66 | ||||
-rw-r--r-- | security/selinux/xfrm.c | 453 |
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; } |