提交 98f700f3 编写于 作者: P Paul Moore

Merge git://git.infradead.org/users/eparis/selinux

Conflicts:
	security/selinux/hooks.c

Pull Eric's existing SELinux tree as there are a number of patches in
there that are not yet upstream.  There was some minor fixup needed to
resolve a conflict in security/selinux/hooks.c:selinux_set_mnt_opts()
between the labeled NFS patches and Eric's security_fs_use()
simplification patch.
...@@ -1052,17 +1052,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) ...@@ -1052,17 +1052,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @xfrm_policy_delete_security: * @xfrm_policy_delete_security:
* @ctx contains the xfrm_sec_ctx. * @ctx contains the xfrm_sec_ctx.
* Authorize deletion of xp->security. * Authorize deletion of xp->security.
* @xfrm_state_alloc_security: * @xfrm_state_alloc:
* @x contains the xfrm_state being added to the Security Association * @x contains the xfrm_state being added to the Security Association
* Database by the XFRM system. * Database by the XFRM system.
* @sec_ctx contains the security context information being provided by * @sec_ctx contains the security context information being provided by
* the user-level SA generation program (e.g., setkey or racoon). * the user-level SA generation program (e.g., setkey or racoon).
* @secid contains the secid from which to take the mls portion of the context.
* Allocate a security structure to the x->security field; the security * Allocate a security structure to the x->security field; the security
* field is initialized to NULL when the xfrm_state is allocated. Set the * field is initialized to NULL when the xfrm_state is allocated. Set the
* context to correspond to either sec_ctx or polsec, with the mls portion * context to correspond to sec_ctx. Return 0 if operation was successful
* taken from secid in the latter case. * (memory to allocate, legal context).
* Return 0 if operation was successful (memory to allocate, legal context). * @xfrm_state_alloc_acquire:
* @x contains the xfrm_state being added to the Security Association
* Database by the XFRM system.
* @polsec contains the policy's security context.
* @secid contains the secid from which to take the mls portion of the
* context.
* Allocate a security structure to the x->security field; the security
* field is initialized to NULL when the xfrm_state is allocated. Set the
* context to correspond to secid. Return 0 if operation was successful
* (memory to allocate, legal context).
* @xfrm_state_free_security: * @xfrm_state_free_security:
* @x contains the xfrm_state. * @x contains the xfrm_state.
* Deallocate x->security. * Deallocate x->security.
...@@ -1679,9 +1687,11 @@ struct security_operations { ...@@ -1679,9 +1687,11 @@ struct security_operations {
int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx);
void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx);
int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx);
int (*xfrm_state_alloc_security) (struct xfrm_state *x, int (*xfrm_state_alloc) (struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_user_sec_ctx *sec_ctx);
u32 secid); int (*xfrm_state_alloc_acquire) (struct xfrm_state *x,
struct xfrm_sec_ctx *polsec,
u32 secid);
void (*xfrm_state_free_security) (struct xfrm_state *x); void (*xfrm_state_free_security) (struct xfrm_state *x);
int (*xfrm_state_delete_security) (struct xfrm_state *x); int (*xfrm_state_delete_security) (struct xfrm_state *x);
int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int (*xfrm_policy_lookup) (struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
......
...@@ -777,9 +777,15 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx) ...@@ -777,9 +777,15 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
return 0; return 0;
} }
static int cap_xfrm_state_alloc_security(struct xfrm_state *x, static int cap_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx, struct xfrm_user_sec_ctx *sec_ctx)
u32 secid) {
return 0;
}
static int cap_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec,
u32 secid)
{ {
return 0; return 0;
} }
...@@ -1101,7 +1107,8 @@ void __init security_fixup_ops(struct security_operations *ops) ...@@ -1101,7 +1107,8 @@ void __init security_fixup_ops(struct security_operations *ops)
set_to_cap_if_null(ops, xfrm_policy_clone_security); set_to_cap_if_null(ops, xfrm_policy_clone_security);
set_to_cap_if_null(ops, xfrm_policy_free_security); set_to_cap_if_null(ops, xfrm_policy_free_security);
set_to_cap_if_null(ops, xfrm_policy_delete_security); set_to_cap_if_null(ops, xfrm_policy_delete_security);
set_to_cap_if_null(ops, xfrm_state_alloc_security); set_to_cap_if_null(ops, xfrm_state_alloc);
set_to_cap_if_null(ops, xfrm_state_alloc_acquire);
set_to_cap_if_null(ops, xfrm_state_free_security); set_to_cap_if_null(ops, xfrm_state_free_security);
set_to_cap_if_null(ops, xfrm_state_delete_security); set_to_cap_if_null(ops, xfrm_state_delete_security);
set_to_cap_if_null(ops, xfrm_policy_lookup); set_to_cap_if_null(ops, xfrm_policy_lookup);
......
...@@ -1342,22 +1342,17 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) ...@@ -1342,22 +1342,17 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
return security_ops->xfrm_policy_delete_security(ctx); return security_ops->xfrm_policy_delete_security(ctx);
} }
int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) int security_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx)
{ {
return security_ops->xfrm_state_alloc_security(x, sec_ctx, 0); return security_ops->xfrm_state_alloc(x, sec_ctx);
} }
EXPORT_SYMBOL(security_xfrm_state_alloc); EXPORT_SYMBOL(security_xfrm_state_alloc);
int security_xfrm_state_alloc_acquire(struct xfrm_state *x, int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec, u32 secid) struct xfrm_sec_ctx *polsec, u32 secid)
{ {
if (!polsec) return security_ops->xfrm_state_alloc_acquire(x, polsec, secid);
return 0;
/*
* We want the context to be taken from secid which is usually
* from the sock.
*/
return security_ops->xfrm_state_alloc_security(x, NULL, secid);
} }
int security_xfrm_state_delete(struct xfrm_state *x) int security_xfrm_state_delete(struct xfrm_state *x)
......
...@@ -95,7 +95,9 @@ ...@@ -95,7 +95,9 @@
#include "audit.h" #include "audit.h"
#include "avc_ss.h" #include "avc_ss.h"
#define NUM_SEL_MNT_OPTS 5 #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 : ""
extern struct security_operations *security_ops; extern struct security_operations *security_ops;
...@@ -139,12 +141,28 @@ static struct kmem_cache *sel_inode_cache; ...@@ -139,12 +141,28 @@ static struct kmem_cache *sel_inode_cache;
* This function checks the SECMARK reference counter to see if any SECMARK * This function checks the SECMARK reference counter to see if any SECMARK
* targets are currently configured, if the reference counter is greater than * targets are currently configured, if the reference counter is greater than
* zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is
* enabled, false (0) if SECMARK is disabled. * enabled, false (0) if SECMARK is disabled. If the always_check_network
* policy capability is enabled, SECMARK is always considered enabled.
* *
*/ */
static int selinux_secmark_enabled(void) static int selinux_secmark_enabled(void)
{ {
return (atomic_read(&selinux_secmark_refcount) > 0); 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());
} }
/* /*
...@@ -309,8 +327,11 @@ enum { ...@@ -309,8 +327,11 @@ enum {
Opt_defcontext = 3, Opt_defcontext = 3,
Opt_rootcontext = 4, Opt_rootcontext = 4,
Opt_labelsupport = 5, Opt_labelsupport = 5,
Opt_nextmntopt = 6,
}; };
#define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1)
static const match_table_t tokens = { static const match_table_t tokens = {
{Opt_context, CONTEXT_STR "%s"}, {Opt_context, CONTEXT_STR "%s"},
{Opt_fscontext, FSCONTEXT_STR "%s"}, {Opt_fscontext, FSCONTEXT_STR "%s"},
...@@ -355,6 +376,29 @@ static int may_context_mount_inode_relabel(u32 sid, ...@@ -355,6 +376,29 @@ static int may_context_mount_inode_relabel(u32 sid,
return rc; 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) static int sb_finish_set_opts(struct super_block *sb)
{ {
struct superblock_security_struct *sbsec = sb->s_security; struct superblock_security_struct *sbsec = sb->s_security;
...@@ -369,8 +413,8 @@ static int sb_finish_set_opts(struct super_block *sb) ...@@ -369,8 +413,8 @@ static int sb_finish_set_opts(struct super_block *sb)
the first boot of the SELinux kernel before we have the first boot of the SELinux kernel before we have
assigned xattr values to the filesystem. */ assigned xattr values to the filesystem. */
if (!root_inode->i_op->getxattr) { if (!root_inode->i_op->getxattr) {
printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " printk(KERN_WARNING "SELinux: (dev %s, type "SB_TYPE_FMT") has no "
"xattr support\n", sb->s_id, sb->s_type->name); "xattr support\n", sb->s_id, SB_TYPE_ARGS(sb));
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
goto out; goto out;
} }
...@@ -378,35 +422,27 @@ static int sb_finish_set_opts(struct super_block *sb) ...@@ -378,35 +422,27 @@ static int sb_finish_set_opts(struct super_block *sb)
if (rc < 0 && rc != -ENODATA) { if (rc < 0 && rc != -ENODATA) {
if (rc == -EOPNOTSUPP) if (rc == -EOPNOTSUPP)
printk(KERN_WARNING "SELinux: (dev %s, type " printk(KERN_WARNING "SELinux: (dev %s, type "
"%s) has no security xattr handler\n", SB_TYPE_FMT") has no security xattr handler\n",
sb->s_id, sb->s_type->name); sb->s_id, SB_TYPE_ARGS(sb));
else else
printk(KERN_WARNING "SELinux: (dev %s, type " printk(KERN_WARNING "SELinux: (dev %s, type "
"%s) getxattr errno %d\n", sb->s_id, SB_TYPE_FMT") getxattr errno %d\n", sb->s_id,
sb->s_type->name, -rc); SB_TYPE_ARGS(sb), -rc);
goto out; goto out;
} }
} }
sbsec->flags |= (SE_SBINITIALIZED | SE_SBLABELSUPP);
if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", printk(KERN_ERR "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), unknown behavior\n",
sb->s_id, sb->s_type->name); sb->s_id, SB_TYPE_ARGS(sb));
else else
printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", printk(KERN_DEBUG "SELinux: initialized (dev %s, type "SB_TYPE_FMT"), %s\n",
sb->s_id, sb->s_type->name, sb->s_id, SB_TYPE_ARGS(sb),
labeling_behaviors[sbsec->behavior-1]); labeling_behaviors[sbsec->behavior-1]);
if (sbsec->behavior == SECURITY_FS_USE_GENFS || sbsec->flags |= SE_SBINITIALIZED;
sbsec->behavior == SECURITY_FS_USE_MNTPOINT || if (selinux_is_sblabel_mnt(sb))
sbsec->behavior == SECURITY_FS_USE_NONE || sbsec->flags |= SBLABEL_MNT;
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. */ /* Initialize the root inode. */
rc = inode_doinit_with_dentry(root_inode, root); rc = inode_doinit_with_dentry(root_inode, root);
...@@ -460,15 +496,18 @@ static int selinux_get_mnt_opts(const struct super_block *sb, ...@@ -460,15 +496,18 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
if (!ss_initialized) if (!ss_initialized)
return -EINVAL; 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; tmp = sbsec->flags & SE_MNTMASK;
/* count the number of mount options for this sb */ /* count the number of mount options for this sb */
for (i = 0; i < 8; i++) { for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
if (tmp & 0x01) if (tmp & 0x01)
opts->num_mnt_opts++; opts->num_mnt_opts++;
tmp >>= 1; tmp >>= 1;
} }
/* Check if the Label support flag is set */ /* Check if the Label support flag is set */
if (sbsec->flags & SE_SBLABELSUPP) if (sbsec->flags & SBLABEL_MNT)
opts->num_mnt_opts++; opts->num_mnt_opts++;
opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
...@@ -515,9 +554,9 @@ static int selinux_get_mnt_opts(const struct super_block *sb, ...@@ -515,9 +554,9 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
opts->mnt_opts[i] = context; opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
} }
if (sbsec->flags & SE_SBLABELSUPP) { if (sbsec->flags & SBLABEL_MNT) {
opts->mnt_opts[i] = NULL; opts->mnt_opts[i] = NULL;
opts->mnt_opts_flags[i++] = SE_SBLABELSUPP; opts->mnt_opts_flags[i++] = SBLABEL_MNT;
} }
BUG_ON(i != opts->num_mnt_opts); BUG_ON(i != opts->num_mnt_opts);
...@@ -561,7 +600,6 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -561,7 +600,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
int rc = 0, i; int rc = 0, i;
struct superblock_security_struct *sbsec = sb->s_security; 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 *inode = sbsec->sb->s_root->d_inode;
struct inode_security_struct *root_isec = inode->i_security; struct inode_security_struct *root_isec = inode->i_security;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
...@@ -614,14 +652,14 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -614,14 +652,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
for (i = 0; i < num_opts; i++) { for (i = 0; i < num_opts; i++) {
u32 sid; u32 sid;
if (flags[i] == SE_SBLABELSUPP) if (flags[i] == SBLABEL_MNT)
continue; continue;
rc = security_context_to_sid(mount_options[i], rc = security_context_to_sid(mount_options[i],
strlen(mount_options[i]), &sid); strlen(mount_options[i]), &sid);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid" printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n",
mount_options[i], sb->s_id, name, rc); mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc);
goto out; goto out;
} }
switch (flags[i]) { switch (flags[i]) {
...@@ -685,9 +723,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -685,9 +723,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this * Determine the labeling behavior to use for this
* filesystem type. * filesystem type.
*/ */
rc = security_fs_use((sbsec->flags & SE_SBPROC) ? rc = security_fs_use(sb);
"proc" : sb->s_type->name,
&sbsec->behavior, &sbsec->sid);
if (rc) { if (rc) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: security_fs_use(%s) returned %d\n", "%s: security_fs_use(%s) returned %d\n",
...@@ -770,7 +806,8 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -770,7 +806,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
out_double_mount: out_double_mount:
rc = -EINVAL; rc = -EINVAL;
printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different " printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different "
"security settings for (dev %s, type %s)\n", sb->s_id, name); "security settings for (dev %s, type "SB_TYPE_FMT")\n", sb->s_id,
SB_TYPE_ARGS(sb));
goto out; goto out;
} }
...@@ -1037,7 +1074,7 @@ static void selinux_write_opts(struct seq_file *m, ...@@ -1037,7 +1074,7 @@ static void selinux_write_opts(struct seq_file *m,
case DEFCONTEXT_MNT: case DEFCONTEXT_MNT:
prefix = DEFCONTEXT_STR; prefix = DEFCONTEXT_STR;
break; break;
case SE_SBLABELSUPP: case SBLABEL_MNT:
seq_putc(m, ','); seq_putc(m, ',');
seq_puts(m, LABELSUPP_STR); seq_puts(m, LABELSUPP_STR);
continue; continue;
...@@ -1650,7 +1687,7 @@ static int may_create(struct inode *dir, ...@@ -1650,7 +1687,7 @@ static int may_create(struct inode *dir,
if (rc) if (rc)
return rc; return rc;
if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { if (!newsid || !(sbsec->flags & SBLABEL_MNT)) {
rc = security_transition_sid(sid, dsec->sid, tclass, rc = security_transition_sid(sid, dsec->sid, tclass,
&dentry->d_name, &newsid); &dentry->d_name, &newsid);
if (rc) if (rc)
...@@ -2438,14 +2475,14 @@ static int selinux_sb_remount(struct super_block *sb, void *data) ...@@ -2438,14 +2475,14 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
u32 sid; u32 sid;
size_t len; size_t len;
if (flags[i] == SE_SBLABELSUPP) if (flags[i] == SBLABEL_MNT)
continue; continue;
len = strlen(mount_options[i]); len = strlen(mount_options[i]);
rc = security_context_to_sid(mount_options[i], len, &sid); rc = security_context_to_sid(mount_options[i], len, &sid);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_to_sid" printk(KERN_WARNING "SELinux: security_context_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type "SB_TYPE_FMT") errno=%d\n",
mount_options[i], sb->s_id, sb->s_type->name, rc); mount_options[i], sb->s_id, SB_TYPE_ARGS(sb), rc);
goto out_free_opts; goto out_free_opts;
} }
rc = -EINVAL; rc = -EINVAL;
...@@ -2483,8 +2520,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data) ...@@ -2483,8 +2520,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
return rc; return rc;
out_bad_option: out_bad_option:
printk(KERN_WARNING "SELinux: unable to change security options " printk(KERN_WARNING "SELinux: unable to change security options "
"during remount (dev %s, type=%s)\n", sb->s_id, "during remount (dev %s, type "SB_TYPE_FMT")\n", sb->s_id,
sb->s_type->name); SB_TYPE_ARGS(sb));
goto out_free_opts; goto out_free_opts;
} }
...@@ -2606,7 +2643,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -2606,7 +2643,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
if ((sbsec->flags & SE_SBINITIALIZED) && if ((sbsec->flags & SE_SBINITIALIZED) &&
(sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) (sbsec->behavior == SECURITY_FS_USE_MNTPOINT))
newsid = sbsec->mntpoint_sid; newsid = sbsec->mntpoint_sid;
else if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) { else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) {
rc = security_transition_sid(sid, dsec->sid, rc = security_transition_sid(sid, dsec->sid,
inode_mode_to_security_class(inode->i_mode), inode_mode_to_security_class(inode->i_mode),
qstr, &newsid); qstr, &newsid);
...@@ -2628,7 +2665,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -2628,7 +2665,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec->initialized = 1; isec->initialized = 1;
} }
if (!ss_initialized || !(sbsec->flags & SE_SBLABELSUPP)) if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (name) { if (name) {
...@@ -2836,7 +2873,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -2836,7 +2873,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return selinux_inode_setotherxattr(dentry, name); return selinux_inode_setotherxattr(dentry, name);
sbsec = inode->i_sb->s_security; sbsec = inode->i_sb->s_security;
if (!(sbsec->flags & SE_SBLABELSUPP)) if (!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!inode_owner_or_capable(inode)) if (!inode_owner_or_capable(inode))
...@@ -3797,8 +3834,12 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) ...@@ -3797,8 +3834,12 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
u32 nlbl_sid; u32 nlbl_sid;
u32 nlbl_type; u32 nlbl_type;
selinux_skb_xfrm_sid(skb, &xfrm_sid); err = selinux_skb_xfrm_sid(skb, &xfrm_sid);
selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); if (unlikely(err))
return -EACCES;
err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
if (unlikely(err))
return -EACCES;
err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
if (unlikely(err)) { if (unlikely(err)) {
...@@ -4252,7 +4293,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -4252,7 +4293,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return selinux_sock_rcv_skb_compat(sk, skb, family); return selinux_sock_rcv_skb_compat(sk, skb, family);
secmark_active = selinux_secmark_enabled(); secmark_active = selinux_secmark_enabled();
peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); peerlbl_active = selinux_peerlbl_enabled();
if (!secmark_active && !peerlbl_active) if (!secmark_active && !peerlbl_active)
return 0; return 0;
...@@ -4634,7 +4675,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, ...@@ -4634,7 +4675,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
secmark_active = selinux_secmark_enabled(); secmark_active = selinux_secmark_enabled();
netlbl_active = netlbl_enabled(); netlbl_active = netlbl_enabled();
peerlbl_active = netlbl_active || selinux_xfrm_enabled(); peerlbl_active = selinux_peerlbl_enabled();
if (!secmark_active && !peerlbl_active) if (!secmark_active && !peerlbl_active)
return NF_ACCEPT; return NF_ACCEPT;
...@@ -4786,7 +4827,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, ...@@ -4786,7 +4827,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
return NF_ACCEPT; return NF_ACCEPT;
#endif #endif
secmark_active = selinux_secmark_enabled(); secmark_active = selinux_secmark_enabled();
peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); peerlbl_active = selinux_peerlbl_enabled();
if (!secmark_active && !peerlbl_active) if (!secmark_active && !peerlbl_active)
return NF_ACCEPT; return NF_ACCEPT;
...@@ -5790,7 +5831,8 @@ static struct security_operations selinux_ops = { ...@@ -5790,7 +5831,8 @@ static struct security_operations selinux_ops = {
.xfrm_policy_clone_security = selinux_xfrm_policy_clone, .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
.xfrm_policy_free_security = selinux_xfrm_policy_free, .xfrm_policy_free_security = selinux_xfrm_policy_free,
.xfrm_policy_delete_security = selinux_xfrm_policy_delete, .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
.xfrm_state_alloc_security = selinux_xfrm_state_alloc, .xfrm_state_alloc = selinux_xfrm_state_alloc,
.xfrm_state_alloc_acquire = selinux_xfrm_state_alloc_acquire,
.xfrm_state_free_security = selinux_xfrm_state_free, .xfrm_state_free_security = selinux_xfrm_state_free,
.xfrm_state_delete_security = selinux_xfrm_state_delete, .xfrm_state_delete_security = selinux_xfrm_state_delete,
.xfrm_policy_lookup = selinux_xfrm_policy_lookup, .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
......
...@@ -58,8 +58,8 @@ struct superblock_security_struct { ...@@ -58,8 +58,8 @@ struct superblock_security_struct {
u32 sid; /* SID of file system superblock */ u32 sid; /* SID of file system superblock */
u32 def_sid; /* default SID for labeling */ u32 def_sid; /* default SID for labeling */
u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */ u32 mntpoint_sid; /* SECURITY_FS_USE_MNTPOINT context for files */
unsigned int behavior; /* labeling behavior */ unsigned short behavior; /* labeling behavior */
unsigned char flags; /* which mount options were specified */ unsigned short flags; /* which mount options were specified */
struct mutex lock; struct mutex lock;
struct list_head isec_head; struct list_head isec_head;
spinlock_t isec_lock; spinlock_t isec_lock;
......
...@@ -45,14 +45,15 @@ ...@@ -45,14 +45,15 @@
/* Mask for just the mount related flags */ /* Mask for just the mount related flags */
#define SE_MNTMASK 0x0f #define SE_MNTMASK 0x0f
/* Super block security struct flags for mount options */ /* 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 CONTEXT_MNT 0x01
#define FSCONTEXT_MNT 0x02 #define FSCONTEXT_MNT 0x02
#define ROOTCONTEXT_MNT 0x04 #define ROOTCONTEXT_MNT 0x04
#define DEFCONTEXT_MNT 0x08 #define DEFCONTEXT_MNT 0x08
#define SBLABEL_MNT 0x10
/* Non-mount related flags */ /* Non-mount related flags */
#define SE_SBINITIALIZED 0x10 #define SE_SBINITIALIZED 0x0100
#define SE_SBPROC 0x20 #define SE_SBPROC 0x0200
#define SE_SBLABELSUPP 0x40
#define CONTEXT_STR "context=" #define CONTEXT_STR "context="
#define FSCONTEXT_STR "fscontext=" #define FSCONTEXT_STR "fscontext="
...@@ -68,12 +69,15 @@ extern int selinux_enabled; ...@@ -68,12 +69,15 @@ extern int selinux_enabled;
enum { enum {
POLICYDB_CAPABILITY_NETPEER, POLICYDB_CAPABILITY_NETPEER,
POLICYDB_CAPABILITY_OPENPERM, POLICYDB_CAPABILITY_OPENPERM,
POLICYDB_CAPABILITY_REDHAT1,
POLICYDB_CAPABILITY_ALWAYSNETWORK,
__POLICYDB_CAPABILITY_MAX __POLICYDB_CAPABILITY_MAX
}; };
#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1) #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
extern int selinux_policycap_netpeer; extern int selinux_policycap_netpeer;
extern int selinux_policycap_openperm; extern int selinux_policycap_openperm;
extern int selinux_policycap_alwaysnetwork;
/* /*
* type_datum properties * type_datum properties
...@@ -172,8 +176,7 @@ int security_get_allow_unknown(void); ...@@ -172,8 +176,7 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */ #define SECURITY_FS_USE_NATIVE 7 /* use native label support */
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */ #define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
int security_fs_use(const char *fstype, unsigned int *behavior, int security_fs_use(struct super_block *sb);
u32 *sid);
int security_genfs_sid(const char *fstype, char *name, u16 sclass, int security_genfs_sid(const char *fstype, char *name, u16 sclass,
u32 *sid); u32 *sid);
......
...@@ -10,29 +10,21 @@ ...@@ -10,29 +10,21 @@
#include <net/flow.h> #include <net/flow.h>
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx); struct xfrm_user_sec_ctx *uctx);
int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp); struct xfrm_sec_ctx **new_ctxp);
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx);
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx);
int selinux_xfrm_state_alloc(struct xfrm_state *x, int selinux_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx, u32 secid); struct xfrm_user_sec_ctx *uctx);
int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec, u32 secid);
void selinux_xfrm_state_free(struct xfrm_state *x); void selinux_xfrm_state_free(struct xfrm_state *x);
int selinux_xfrm_state_delete(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_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir);
int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, 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 #ifdef CONFIG_SECURITY_NETWORK_XFRM
extern atomic_t selinux_xfrm_refcount; extern atomic_t selinux_xfrm_refcount;
...@@ -42,10 +34,10 @@ static inline int selinux_xfrm_enabled(void) ...@@ -42,10 +34,10 @@ static inline int selinux_xfrm_enabled(void)
return (atomic_read(&selinux_xfrm_refcount) > 0); return (atomic_read(&selinux_xfrm_refcount) > 0);
} }
int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb, int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
struct common_audit_data *ad); struct common_audit_data *ad);
int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
struct common_audit_data *ad, u8 proto); struct common_audit_data *ad, u8 proto);
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall); int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall);
static inline void selinux_xfrm_notify_policyload(void) static inline void selinux_xfrm_notify_policyload(void)
...@@ -59,19 +51,21 @@ static inline int selinux_xfrm_enabled(void) ...@@ -59,19 +51,21 @@ static inline int selinux_xfrm_enabled(void)
return 0; return 0;
} }
static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, static inline int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
struct common_audit_data *ad) struct common_audit_data *ad)
{ {
return 0; return 0;
} }
static inline int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, static inline int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
struct common_audit_data *ad, u8 proto) struct common_audit_data *ad,
u8 proto)
{ {
return 0; 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; *sid = SECSID_NULL;
return 0; return 0;
...@@ -82,10 +76,9 @@ static inline void selinux_xfrm_notify_policyload(void) ...@@ -82,10 +76,9 @@ static inline void selinux_xfrm_notify_policyload(void)
} }
#endif #endif
static inline void selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid) static inline int selinux_skb_xfrm_sid(struct sk_buff *skb, u32 *sid)
{ {
int err = selinux_xfrm_decode_session(skb, sid, 0); return selinux_xfrm_decode_session(skb, sid, 0);
BUG_ON(err);
} }
#endif /* _SELINUX_XFRM_H_ */ #endif /* _SELINUX_XFRM_H_ */
...@@ -166,6 +166,7 @@ static void sel_netnode_insert(struct sel_netnode *node) ...@@ -166,6 +166,7 @@ static void sel_netnode_insert(struct sel_netnode *node)
break; break;
default: default:
BUG(); BUG();
return;
} }
/* we need to impose a limit on the growth of the hash table so check /* we need to impose a limit on the growth of the hash table so check
...@@ -225,6 +226,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) ...@@ -225,6 +226,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
break; break;
default: default:
BUG(); BUG();
ret = -EINVAL;
} }
if (ret != 0) if (ret != 0)
goto out; goto out;
......
...@@ -44,7 +44,9 @@ ...@@ -44,7 +44,9 @@
/* Policy capability filenames */ /* Policy capability filenames */
static char *policycap_names[] = { static char *policycap_names[] = {
"network_peer_controls", "network_peer_controls",
"open_perms" "open_perms",
"redhat1",
"always_check_network"
}; };
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
......
...@@ -213,7 +213,12 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap, ...@@ -213,7 +213,12 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
} }
#endif /* CONFIG_NETLABEL */ #endif /* CONFIG_NETLABEL */
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) /*
* 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)
{ {
struct ebitmap_node *n1, *n2; struct ebitmap_node *n1, *n2;
int i; int i;
...@@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) ...@@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1 = e1->node; n1 = e1->node;
n2 = e2->node; n2 = e2->node;
while (n1 && n2 && (n1->startbit <= n2->startbit)) { while (n1 && n2 && (n1->startbit <= n2->startbit)) {
if (n1->startbit < n2->startbit) { if (n1->startbit < n2->startbit) {
n1 = n1->next; n1 = n1->next;
continue; continue;
} }
for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { 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) {
if ((n1->maps[i] & n2->maps[i]) != n2->maps[i]) if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])
return 0; return 0;
i--;
} }
n1 = n1->next; n1 = n1->next;
......
...@@ -16,7 +16,13 @@ ...@@ -16,7 +16,13 @@
#include <net/netlabel.h> #include <net/netlabel.h>
#define EBITMAP_UNIT_NUMS ((32 - sizeof(void *) - sizeof(u32)) \ #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))\
/ sizeof(unsigned long)) / sizeof(unsigned long))
#define EBITMAP_UNIT_SIZE BITS_PER_LONG #define EBITMAP_UNIT_SIZE BITS_PER_LONG
#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) #define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
...@@ -117,7 +123,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, ...@@ -117,7 +123,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit);
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit); int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
void ebitmap_destroy(struct ebitmap *e); void ebitmap_destroy(struct ebitmap *e);
......
...@@ -160,8 +160,6 @@ void mls_sid_to_context(struct context *context, ...@@ -160,8 +160,6 @@ void mls_sid_to_context(struct context *context,
int mls_level_isvalid(struct policydb *p, struct mls_level *l) int mls_level_isvalid(struct policydb *p, struct mls_level *l)
{ {
struct level_datum *levdatum; struct level_datum *levdatum;
struct ebitmap_node *node;
int i;
if (!l->sens || l->sens > p->p_levels.nprim) if (!l->sens || l->sens > p->p_levels.nprim)
return 0; return 0;
...@@ -170,19 +168,13 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l) ...@@ -170,19 +168,13 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
if (!levdatum) if (!levdatum)
return 0; return 0;
ebitmap_for_each_positive_bit(&l->cat, node, i) { /*
if (i > p->p_cats.nprim) * Return 1 iff all the bits set in l->cat are also be set in
return 0; * levdatum->level->cat and no bit in l->cat is larger than
if (!ebitmap_get_bit(&levdatum->level->cat, i)) { * p->p_cats.nprim.
/* */
* Category may not be associated with return ebitmap_contains(&levdatum->level->cat, &l->cat,
* sensitivity. p->p_cats.nprim);
*/
return 0;
}
}
return 1;
} }
int mls_range_isvalid(struct policydb *p, struct mls_range *r) int mls_range_isvalid(struct policydb *p, struct mls_range *r)
......
...@@ -35,7 +35,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) ...@@ -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) static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
{ {
return ((l1->sens >= l2->sens) && return ((l1->sens >= l2->sens) &&
ebitmap_contains(&l1->cat, &l2->cat)); ebitmap_contains(&l1->cat, &l2->cat, 0));
} }
#define mls_level_incomp(l1, l2) \ #define mls_level_incomp(l1, l2) \
......
...@@ -3203,9 +3203,8 @@ static int range_write_helper(void *key, void *data, void *ptr) ...@@ -3203,9 +3203,8 @@ static int range_write_helper(void *key, void *data, void *ptr)
static int range_write(struct policydb *p, void *fp) static int range_write(struct policydb *p, void *fp)
{ {
size_t nel;
__le32 buf[1]; __le32 buf[1];
int rc; int rc, nel;
struct policy_data pd; struct policy_data pd;
pd.p = p; pd.p = p;
......
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
int selinux_policycap_netpeer; int selinux_policycap_netpeer;
int selinux_policycap_openperm; int selinux_policycap_openperm;
int selinux_policycap_alwaysnetwork;
static DEFINE_RWLOCK(policy_rwlock); static DEFINE_RWLOCK(policy_rwlock);
...@@ -1812,6 +1813,8 @@ static void security_load_policycaps(void) ...@@ -1812,6 +1813,8 @@ static void security_load_policycaps(void)
POLICYDB_CAPABILITY_NETPEER); POLICYDB_CAPABILITY_NETPEER);
selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_OPENPERM); POLICYDB_CAPABILITY_OPENPERM);
selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_ALWAYSNETWORK);
} }
static int security_preserve_bools(struct policydb *p); static int security_preserve_bools(struct policydb *p);
...@@ -2323,43 +2326,74 @@ int security_genfs_sid(const char *fstype, ...@@ -2323,43 +2326,74 @@ int security_genfs_sid(const char *fstype,
/** /**
* security_fs_use - Determine how to handle labeling for a filesystem. * security_fs_use - Determine how to handle labeling for a filesystem.
* @fstype: filesystem type * @sb: superblock in question
* @behavior: labeling behavior
* @sid: SID for filesystem (superblock)
*/ */
int security_fs_use( int security_fs_use(struct super_block *sb)
const char *fstype,
unsigned int *behavior,
u32 *sid)
{ {
int rc = 0; int rc = 0;
struct ocontext *c; 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); read_lock(&policy_rwlock);
c = policydb.ocontexts[OCON_FSUSE]; for (c = policydb.ocontexts[OCON_FSUSE]; c; c = c->next) {
while (c) { char *sub;
if (strcmp(fstype, c->u.name) == 0) 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))
break; break;
c = c->next;
} }
/* in case we had found an fstype match but no subtype match */
if (!c)
c = base;
if (c) { if (c) {
*behavior = c->v.behavior; sbsec->behavior = c->v.behavior;
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, &c->context[0], rc = sidtab_context_to_sid(&sidtab, &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
goto out; goto out;
} }
*sid = c->sid[0]; sbsec->sid = c->sid[0];
} else { } else {
rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid);
if (rc) { if (rc) {
*behavior = SECURITY_FS_USE_NONE; sbsec->behavior = SECURITY_FS_USE_NONE;
rc = 0; rc = 0;
} else { } else {
*behavior = SECURITY_FS_USE_GENFS; sbsec->behavior = SECURITY_FS_USE_GENFS;
} }
} }
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0); atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);
/* /*
* Returns true if an LSM/SELinux context * Returns true if the context is an LSM/SELinux context.
*/ */
static inline int selinux_authorizable_ctx(struct xfrm_sec_ctx *ctx) 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) ...@@ -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) static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
{ {
...@@ -74,48 +74,111 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) ...@@ -74,48 +74,111 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
} }
/* /*
* LSM hook implementation that authorizes that a flow can use * Allocates a xfrm_sec_state and populates it using the supplied security
* a xfrm policy rule. * xfrm_user_sec_ctx context.
*/ */
int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx)
{ {
int rc; int rc;
u32 sel_sid; const struct task_security_struct *tsec = current_security();
struct xfrm_sec_ctx *ctx = NULL;
u32 str_len;
/* Context sid is either set to label or ANY_ASSOC */ if (ctxp == NULL || uctx == NULL ||
if (ctx) { uctx->ctx_doi != XFRM_SC_DOI_LSM ||
if (!selinux_authorizable_ctx(ctx)) uctx->ctx_alg != XFRM_SC_ALG_SELINUX)
return -EINVAL; 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;
rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION, str_len = uctx->ctx_len;
ASSOCIATION__POLMATCH, if (str_len >= PAGE_SIZE)
NULL); return -ENOMEM;
if (rc == -EACCES) ctx = kmalloc(sizeof(*ctx) + str_len + 1, GFP_KERNEL);
return -ESRCH; 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; 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.
*/
int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
{
int rc;
/* All flows should be treated as polmatch'ing an otherwise applicable
* "non-labeled" policy. This would prevent inadvertent "leaks". */
if (!ctx)
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, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
return (rc == -EACCES ? -ESRCH : rc);
}
/* /*
* LSM hook implementation that authorizes that a state matches * LSM hook implementation that authorizes that a state matches
* the given policy, flow combo. * the given policy, flow combo.
*/ */
int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct xfrm_policy *xp,
const struct flowi *fl) const struct flowi *fl)
{ {
u32 state_sid; u32 state_sid;
int rc;
if (!xp->security) if (!xp->security)
if (x->security) if (x->security)
...@@ -138,187 +201,80 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy * ...@@ -138,187 +201,80 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
if (fl->flowi_secid != state_sid) if (fl->flowi_secid != state_sid)
return 0; return 0;
rc = avc_has_perm(fl->flowi_secid, state_sid, SECCLASS_ASSOCIATION, /* We don't need a separate SA Vs. policy polmatch check since the SA
ASSOCIATION__SENDTO, * is now of the same label as the flow and a flow Vs. policy polmatch
NULL)? 0:1; * check had already happened in selinux_xfrm_policy_lookup() above. */
return (avc_has_perm(fl->flowi_secid, state_sid,
/* SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
* We don't need a separate SA Vs. policy polmatch check NULL) ? 0 : 1);
* 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 * LSM hook implementation that checks and/or returns the xfrm sid for the
* incoming packet. * incoming packet.
*/ */
int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall) int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
{ {
u32 sid_session = SECSID_NULL;
struct sec_path *sp; struct sec_path *sp;
*sid = SECSID_NULL;
if (skb == NULL) if (skb == NULL)
return 0; goto out;
sp = skb->sp; sp = skb->sp;
if (sp) { if (sp) {
int i, sid_set = 0; int i;
for (i = sp->len-1; i >= 0; i--) { for (i = sp->len - 1; i >= 0; i--) {
struct xfrm_state *x = sp->xvec[i]; struct xfrm_state *x = sp->xvec[i];
if (selinux_authorizable_xfrm(x)) { if (selinux_authorizable_xfrm(x)) {
struct xfrm_sec_ctx *ctx = x->security; struct xfrm_sec_ctx *ctx = x->security;
if (!sid_set) { if (sid_session == SECSID_NULL) {
*sid = ctx->ctx_sid; sid_session = ctx->ctx_sid;
sid_set = 1;
if (!ckall) if (!ckall)
break; goto out;
} else if (*sid != ctx->ctx_sid) } else if (sid_session != ctx->ctx_sid) {
*sid = SECSID_NULL;
return -EINVAL; return -EINVAL;
}
} }
} }
} }
return 0;
}
/*
* 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: out:
*ctxp = NULL; *sid = sid_session;
kfree(ctx); return 0;
out2:
kfree(ctx_str);
return rc;
} }
/* /*
* LSM hook implementation that allocs and transfers uctx spec to * LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
* xfrm_policy.
*/ */
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx) struct xfrm_user_sec_ctx *uctx)
{ {
int err; return selinux_xfrm_alloc_user(ctxp, uctx);
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 * LSM hook implementation that copies security data structure from old to new
* new for policy cloning. * for policy cloning.
*/ */
int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp) struct xfrm_sec_ctx **new_ctxp)
{ {
struct xfrm_sec_ctx *new_ctx; struct xfrm_sec_ctx *new_ctx;
if (old_ctx) { if (!old_ctx)
new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, return 0;
GFP_ATOMIC);
if (!new_ctx) new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, GFP_ATOMIC);
return -ENOMEM; if (!new_ctx)
return -ENOMEM;
memcpy(new_ctx, old_ctx, sizeof(*old_ctx) + old_ctx->ctx_len);
atomic_inc(&selinux_xfrm_refcount);
*new_ctxp = new_ctx;
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; return 0;
} }
...@@ -327,8 +283,7 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, ...@@ -327,8 +283,7 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
*/ */
void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
{ {
atomic_dec(&selinux_xfrm_refcount); selinux_xfrm_free(ctx);
kfree(ctx);
} }
/* /*
...@@ -336,31 +291,55 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) ...@@ -336,31 +291,55 @@ void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
*/ */
int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
{ {
const struct task_security_struct *tsec = current_security(); return selinux_xfrm_delete(ctx);
}
if (!ctx)
return 0;
return avc_has_perm(tsec->sid, ctx->ctx_sid, /*
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, * LSM hook implementation that allocates a xfrm_sec_state, populates it using
NULL); * 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);
} }
/* /*
* LSM hook implementation that allocs and transfers sec_ctx spec to * LSM hook implementation that allocates a xfrm_sec_state and populates based
* xfrm_state. * on a secid.
*/ */
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,
u32 secid) struct xfrm_sec_ctx *polsec, u32 secid)
{ {
int err; int rc;
struct xfrm_sec_ctx *ctx;
char *ctx_str = NULL;
int str_len;
if (!polsec)
return 0;
BUG_ON(!x); if (secid == 0)
return -EINVAL;
err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); rc = security_sid_to_context(secid, &ctx_str, &str_len);
if (err == 0) if (rc)
atomic_inc(&selinux_xfrm_refcount); return rc;
return err;
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;
} }
/* /*
...@@ -368,24 +347,15 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct ...@@ -368,24 +347,15 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct
*/ */
void selinux_xfrm_state_free(struct xfrm_state *x) void selinux_xfrm_state_free(struct xfrm_state *x)
{ {
atomic_dec(&selinux_xfrm_refcount); selinux_xfrm_free(x->security);
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) int selinux_xfrm_state_delete(struct xfrm_state *x)
{ {
const struct task_security_struct *tsec = current_security(); return selinux_xfrm_delete(x->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);
} }
/* /*
...@@ -395,14 +365,12 @@ int selinux_xfrm_state_delete(struct xfrm_state *x) ...@@ -395,14 +365,12 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)
* we need to check for unlabelled access since this may not have * we need to check for unlabelled access since this may not have
* gone thru the IPSec process. * gone thru the IPSec process.
*/ */
int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
struct common_audit_data *ad) struct common_audit_data *ad)
{ {
int i, rc = 0; int i;
struct sec_path *sp; struct sec_path *sp = skb->sp;
u32 sel_sid = SECINITSID_UNLABELED; u32 peer_sid = SECINITSID_UNLABELED;
sp = skb->sp;
if (sp) { if (sp) {
for (i = 0; i < sp->len; i++) { for (i = 0; i < sp->len; i++) {
...@@ -410,23 +378,17 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, ...@@ -410,23 +378,17 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
if (x && selinux_authorizable_xfrm(x)) { if (x && selinux_authorizable_xfrm(x)) {
struct xfrm_sec_ctx *ctx = x->security; struct xfrm_sec_ctx *ctx = x->security;
sel_sid = ctx->ctx_sid; peer_sid = ctx->ctx_sid;
break; break;
} }
} }
} }
/* /* This check even when there's no association involved is intended,
* This check even when there's no association involved is * according to Trent Jaeger, to make sure a process can't engage in
* intended, according to Trent Jaeger, to make sure a * non-IPsec communication unless explicitly allowed by policy. */
* process can't engage in non-ipsec communication unless return avc_has_perm(sk_sid, peer_sid,
* explicitly allowed by policy. SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
*/
rc = avc_has_perm(isec_sid, sel_sid, SECCLASS_ASSOCIATION,
ASSOCIATION__RECVFROM, ad);
return rc;
} }
/* /*
...@@ -436,49 +398,38 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb, ...@@ -436,49 +398,38 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
* If we do have a authorizable security association, then it has already been * If we do have a authorizable security association, then it has already been
* checked in the selinux_xfrm_state_pol_flow_match hook above. * checked in the selinux_xfrm_state_pol_flow_match hook above.
*/ */
int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
struct common_audit_data *ad, u8 proto) struct common_audit_data *ad, u8 proto)
{ {
struct dst_entry *dst; 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) { switch (proto) {
case IPPROTO_AH: case IPPROTO_AH:
case IPPROTO_ESP: case IPPROTO_ESP:
case IPPROTO_COMP: case IPPROTO_COMP:
/* /* We should have already seen this packet once before it
* We should have already seen this packet once before * underwent xfrm(s). No need to subject it to the unlabeled
* it underwent xfrm(s). No need to subject it to the * check. */
* unlabeled check. return 0;
*/
goto out;
default: default:
break; break;
} }
/* dst = skb_dst(skb);
* This check even when there's no association involved is if (dst) {
* intended, according to Trent Jaeger, to make sure a struct dst_entry *iter;
* process can't engage in non-ipsec communication unless
* explicitly allowed by policy.
*/
rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION, for (iter = dst; iter != NULL; iter = iter->child) {
ASSOCIATION__SENDTO, ad); struct xfrm_state *x = iter->xfrm;
out:
return rc; 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. */
return avc_has_perm(sk_sid, SECINITSID_UNLABELED,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册