Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
6f799c97
Commit
6f799c97
authored
Oct 22, 2013
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.infradead.org/users/pcmoore/selinux
into ra-next
parents
eb8948a0
42d64e1a
Changes
17
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
450 additions
and
400 deletions
+450
-400
include/linux/security.h
include/linux/security.h
+18
-8
security/capability.c
security/capability.c
+11
-4
security/security.c
security/security.c
+4
-9
security/selinux/hooks.c
security/selinux/hooks.c
+94
-52
security/selinux/include/objsec.h
security/selinux/include/objsec.h
+2
-2
security/selinux/include/security.h
security/selinux/include/security.h
+8
-5
security/selinux/include/xfrm.h
security/selinux/include/xfrm.h
+19
-26
security/selinux/netlabel.c
security/selinux/netlabel.c
+2
-4
security/selinux/netnode.c
security/selinux/netnode.c
+2
-0
security/selinux/selinuxfs.c
security/selinux/selinuxfs.c
+3
-1
security/selinux/ss/ebitmap.c
security/selinux/ss/ebitmap.c
+18
-2
security/selinux/ss/ebitmap.h
security/selinux/ss/ebitmap.h
+8
-2
security/selinux/ss/mls.c
security/selinux/ss/mls.c
+7
-15
security/selinux/ss/mls_types.h
security/selinux/ss/mls_types.h
+1
-1
security/selinux/ss/policydb.c
security/selinux/ss/policydb.c
+1
-2
security/selinux/ss/services.c
security/selinux/ss/services.c
+50
-16
security/selinux/xfrm.c
security/selinux/xfrm.c
+202
-251
No files found.
include/linux/security.h
View file @
6f799c97
...
...
@@ -1052,17 +1052,25 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @xfrm_policy_delete_security:
* @ctx contains the xfrm_sec_ctx.
* Authorize deletion of xp->security.
* @xfrm_state_alloc
_security
:
* @xfrm_state_alloc:
* @x contains the xfrm_state being added to the Security Association
* Database by the XFRM system.
* @sec_ctx contains the security context information being provided by
* 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
* 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
* taken from secid in the latter case.
* Return 0 if operation was successful (memory to allocate, legal context).
* context to correspond to sec_ctx. 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:
* @x contains the xfrm_state.
* Deallocate x->security.
...
...
@@ -1679,9 +1687,11 @@ struct security_operations {
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
);
int
(
*
xfrm_policy_delete_security
)
(
struct
xfrm_sec_ctx
*
ctx
);
int
(
*
xfrm_state_alloc_security
)
(
struct
xfrm_state
*
x
,
struct
xfrm_user_sec_ctx
*
sec_ctx
,
u32
secid
);
int
(
*
xfrm_state_alloc
)
(
struct
xfrm_state
*
x
,
struct
xfrm_user_sec_ctx
*
sec_ctx
);
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
);
int
(
*
xfrm_state_delete_security
)
(
struct
xfrm_state
*
x
);
int
(
*
xfrm_policy_lookup
)
(
struct
xfrm_sec_ctx
*
ctx
,
u32
fl_secid
,
u8
dir
);
...
...
security/capability.c
View file @
6f799c97
...
...
@@ -777,9 +777,15 @@ static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
return
0
;
}
static
int
cap_xfrm_state_alloc_security
(
struct
xfrm_state
*
x
,
struct
xfrm_user_sec_ctx
*
sec_ctx
,
u32
secid
)
static
int
cap_xfrm_state_alloc
(
struct
xfrm_state
*
x
,
struct
xfrm_user_sec_ctx
*
sec_ctx
)
{
return
0
;
}
static
int
cap_xfrm_state_alloc_acquire
(
struct
xfrm_state
*
x
,
struct
xfrm_sec_ctx
*
polsec
,
u32
secid
)
{
return
0
;
}
...
...
@@ -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_free_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_delete_security
);
set_to_cap_if_null
(
ops
,
xfrm_policy_lookup
);
...
...
security/security.c
View file @
6f799c97
...
...
@@ -1340,22 +1340,17 @@ int security_xfrm_policy_delete(struct xfrm_sec_ctx *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
);
int
security_xfrm_state_alloc_acquire
(
struct
xfrm_state
*
x
,
struct
xfrm_sec_ctx
*
polsec
,
u32
secid
)
{
if
(
!
polsec
)
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
);
return
security_ops
->
xfrm_state_alloc_acquire
(
x
,
polsec
,
secid
);
}
int
security_xfrm_state_delete
(
struct
xfrm_state
*
x
)
...
...
security/selinux/hooks.c
View file @
6f799c97
...
...
@@ -95,7 +95,9 @@
#include "audit.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
;
...
...
@@ -139,12 +141,28 @@ 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.
* 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
)
{
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 {
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"
},
...
...
@@ -355,6 +376,29 @@ 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
;
...
...
@@ -369,8 +413,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
%s
) has no "
"xattr support
\n
"
,
sb
->
s_id
,
sb
->
s_type
->
name
);
printk
(
KERN_WARNING
"SELinux: (dev %s, type
"
SB_TYPE_FMT
"
) has no "
"xattr support
\n
"
,
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
);
rc
=
-
EOPNOTSUPP
;
goto
out
;
}
...
...
@@ -378,35 +422,27 @@ 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 "
"%s
) has no security xattr handler
\n
"
,
sb
->
s_id
,
sb
->
s_type
->
name
);
SB_TYPE_FMT
"
) has no security xattr handler
\n
"
,
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
);
else
printk
(
KERN_WARNING
"SELinux: (dev %s, type "
"%s
) getxattr errno %d
\n
"
,
sb
->
s_id
,
sb
->
s_type
->
name
,
-
rc
);
SB_TYPE_FMT
"
) getxattr errno %d
\n
"
,
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
,
-
rc
);
goto
out
;
}
}
sbsec
->
flags
|=
(
SE_SBINITIALIZED
|
SE_SBLABELSUPP
);
if
(
sbsec
->
behavior
>
ARRAY_SIZE
(
labeling_behaviors
))
printk
(
KERN_ERR
"SELinux: initialized (dev %s, type
%s
), unknown behavior
\n
"
,
sb
->
s_id
,
sb
->
s_type
->
name
);
printk
(
KERN_ERR
"SELinux: initialized (dev %s, type
"
SB_TYPE_FMT
"
), unknown behavior
\n
"
,
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
);
else
printk
(
KERN_DEBUG
"SELinux: initialized (dev %s, type
%s
), %s
\n
"
,
sb
->
s_id
,
sb
->
s_type
->
name
,
printk
(
KERN_DEBUG
"SELinux: initialized (dev %s, type
"
SB_TYPE_FMT
"
), %s
\n
"
,
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
,
labeling_behaviors
[
sbsec
->
behavior
-
1
]);
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
;
sbsec
->
flags
|=
SE_SBINITIALIZED
;
if
(
selinux_is_sblabel_mnt
(
sb
))
sbsec
->
flags
|=
SBLABEL_MNT
;
/* Initialize the root inode. */
rc
=
inode_doinit_with_dentry
(
root_inode
,
root
);
...
...
@@ -460,15 +496,18 @@ 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
<
8
;
i
++
)
{
for
(
i
=
0
;
i
<
NUM_SEL_MNT_OPTS
;
i
++
)
{
if
(
tmp
&
0x01
)
opts
->
num_mnt_opts
++
;
tmp
>>=
1
;
}
/* Check if the Label support flag is set */
if
(
sbsec
->
flags
&
S
E_SBLABELSUPP
)
if
(
sbsec
->
flags
&
S
BLABEL_MNT
)
opts
->
num_mnt_opts
++
;
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,
opts
->
mnt_opts
[
i
]
=
context
;
opts
->
mnt_opts_flags
[
i
++
]
=
ROOTCONTEXT_MNT
;
}
if
(
sbsec
->
flags
&
S
E_SBLABELSUPP
)
{
if
(
sbsec
->
flags
&
S
BLABEL_MNT
)
{
opts
->
mnt_opts
[
i
]
=
NULL
;
opts
->
mnt_opts_flags
[
i
++
]
=
S
E_SBLABELSUPP
;
opts
->
mnt_opts_flags
[
i
++
]
=
S
BLABEL_MNT
;
}
BUG_ON
(
i
!=
opts
->
num_mnt_opts
);
...
...
@@ -561,7 +600,6 @@ 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
;
...
...
@@ -614,14 +652,14 @@ static int selinux_set_mnt_opts(struct super_block *sb,
for
(
i
=
0
;
i
<
num_opts
;
i
++
)
{
u32
sid
;
if
(
flags
[
i
]
==
S
E_SBLABELSUPP
)
if
(
flags
[
i
]
==
S
BLABEL_MNT
)
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
%s
) errno=%d
\n
"
,
mount_options
[
i
],
sb
->
s_id
,
name
,
rc
);
"(%s) failed for (dev %s, type
"
SB_TYPE_FMT
"
) errno=%d
\n
"
,
mount_options
[
i
],
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
,
rc
);
goto
out
;
}
switch
(
flags
[
i
])
{
...
...
@@ -685,9 +723,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this
* filesystem type.
*/
rc
=
security_fs_use
((
sbsec
->
flags
&
SE_SBPROC
)
?
"proc"
:
sb
->
s_type
->
name
,
&
sbsec
->
behavior
,
&
sbsec
->
sid
);
rc
=
security_fs_use
(
sb
);
if
(
rc
)
{
printk
(
KERN_WARNING
"%s: security_fs_use(%s) returned %d
\n
"
,
...
...
@@ -770,7 +806,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
out_double_mount:
rc
=
-
EINVAL
;
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
;
}
...
...
@@ -1037,7 +1074,7 @@ static void selinux_write_opts(struct seq_file *m,
case
DEFCONTEXT_MNT
:
prefix
=
DEFCONTEXT_STR
;
break
;
case
S
E_SBLABELSUPP
:
case
S
BLABEL_MNT
:
seq_putc
(
m
,
','
);
seq_puts
(
m
,
LABELSUPP_STR
);
continue
;
...
...
@@ -1650,7 +1687,7 @@ static int may_create(struct inode *dir,
if
(
rc
)
return
rc
;
if
(
!
newsid
||
!
(
sbsec
->
flags
&
S
E_SBLABELSUPP
))
{
if
(
!
newsid
||
!
(
sbsec
->
flags
&
S
BLABEL_MNT
))
{
rc
=
security_transition_sid
(
sid
,
dsec
->
sid
,
tclass
,
&
dentry
->
d_name
,
&
newsid
);
if
(
rc
)
...
...
@@ -2438,14 +2475,14 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
u32
sid
;
size_t
len
;
if
(
flags
[
i
]
==
S
E_SBLABELSUPP
)
if
(
flags
[
i
]
==
S
BLABEL_MNT
)
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
%s
) errno=%d
\n
"
,
mount_options
[
i
],
sb
->
s_id
,
sb
->
s_type
->
name
,
rc
);
"(%s) failed for (dev %s, type
"
SB_TYPE_FMT
"
) errno=%d
\n
"
,
mount_options
[
i
],
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
,
rc
);
goto
out_free_opts
;
}
rc
=
-
EINVAL
;
...
...
@@ -2483,8 +2520,8 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
return
rc
;
out_bad_option:
printk
(
KERN_WARNING
"SELinux: unable to change security options "
"during remount (dev %s, type
=%s
)
\n
"
,
sb
->
s_id
,
sb
->
s_type
->
name
);
"during remount (dev %s, type
"
SB_TYPE_FMT
"
)
\n
"
,
sb
->
s_id
,
SB_TYPE_ARGS
(
sb
)
);
goto
out_free_opts
;
}
...
...
@@ -2607,7 +2644,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
&
S
E_SBLABELSUPP
))
{
else
if
(
!
newsid
||
!
(
sbsec
->
flags
&
S
BLABEL_MNT
))
{
rc
=
security_transition_sid
(
sid
,
dsec
->
sid
,
inode_mode_to_security_class
(
inode
->
i_mode
),
qstr
,
&
newsid
);
...
...
@@ -2629,7 +2666,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec
->
initialized
=
1
;
}
if
(
!
ss_initialized
||
!
(
sbsec
->
flags
&
S
E_SBLABELSUPP
))
if
(
!
ss_initialized
||
!
(
sbsec
->
flags
&
S
BLABEL_MNT
))
return
-
EOPNOTSUPP
;
if
(
name
)
...
...
@@ -2831,7 +2868,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
&
S
E_SBLABELSUPP
))
if
(
!
(
sbsec
->
flags
&
S
BLABEL_MNT
))
return
-
EOPNOTSUPP
;
if
(
!
inode_owner_or_capable
(
inode
))
...
...
@@ -3792,8 +3829,12 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
u32
nlbl_sid
;
u32
nlbl_type
;
selinux_skb_xfrm_sid
(
skb
,
&
xfrm_sid
);
selinux_netlbl_skbuff_getsid
(
skb
,
family
,
&
nlbl_type
,
&
nlbl_sid
);
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
;
err
=
security_net_peersid_resolve
(
nlbl_sid
,
nlbl_type
,
xfrm_sid
,
sid
);
if
(
unlikely
(
err
))
{
...
...
@@ -4247,7 +4288,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
=
netlbl_enabled
()
||
selinux_xfrm
_enabled
();
peerlbl_active
=
selinux_peerlbl
_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
0
;
...
...
@@ -4629,7 +4670,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex,
secmark_active
=
selinux_secmark_enabled
();
netlbl_active
=
netlbl_enabled
();
peerlbl_active
=
netlbl_active
||
selinux_xfrm
_enabled
();
peerlbl_active
=
selinux_peerlbl
_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
NF_ACCEPT
;
...
...
@@ -4781,7 +4822,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
return
NF_ACCEPT
;
#endif
secmark_active
=
selinux_secmark_enabled
();
peerlbl_active
=
netlbl_enabled
()
||
selinux_xfrm
_enabled
();
peerlbl_active
=
selinux_peerlbl
_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
NF_ACCEPT
;
...
...
@@ -5785,7 +5826,8 @@ 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_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_delete_security
=
selinux_xfrm_state_delete
,
.
xfrm_policy_lookup
=
selinux_xfrm_policy_lookup
,
...
...
security/selinux/include/objsec.h
View file @
6f799c97
...
...
@@ -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
int
behavior
;
/* labeling behavior */
unsigned
char
flags
;
/* which mount options were specified */
unsigned
short
behavior
;
/* labeling behavior */
unsigned
short
flags
;
/* which mount options were specified */
struct
mutex
lock
;
struct
list_head
isec_head
;
spinlock_t
isec_lock
;
...
...
security/selinux/include/security.h
View file @
6f799c97
...
...
@@ -45,14 +45,15 @@
/* 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 0x10
#define SE_SBPROC 0x20
#define SE_SBLABELSUPP 0x40
#define SE_SBINITIALIZED 0x0100
#define SE_SBPROC 0x0200
#define CONTEXT_STR "context="
#define FSCONTEXT_STR "fscontext="
...
...
@@ -68,12 +69,15 @@ 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
...
...
@@ -172,8 +176,7 @@ 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
(
const
char
*
fstype
,
unsigned
int
*
behavior
,
u32
*
sid
);
int
security_fs_use
(
struct
super_block
*
sb
);
int
security_genfs_sid
(
const
char
*
fstype
,
char
*
name
,
u16
sclass
,
u32
*
sid
);
...
...
security/selinux/include/xfrm.h
View file @
6f799c97
...
...
@@ -10,29 +10,21 @@
#include <net/flow.h>
int
selinux_xfrm_policy_alloc
(
struct
xfrm_sec_ctx
**
ctxp
,
struct
xfrm_user_sec_ctx
*
sec_
ctx
);
struct
xfrm_user_sec_ctx
*
u
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
*
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
);
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
);
/*
* 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
;
}
struct
xfrm_policy
*
xp
,
const
struct
flowi
*
fl
);
#ifdef CONFIG_SECURITY_NETWORK_XFRM
extern
atomic_t
selinux_xfrm_refcount
;
...
...
@@ -42,10 +34,10 @@ static inline int selinux_xfrm_enabled(void)
return
(
atomic_read
(
&
selinux_xfrm_refcount
)
>
0
);
}
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_sock_rcv_skb
(
u32
s
k_s
id
,
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_decode_session
(
struct
sk_buff
*
skb
,
u32
*
sid
,
int
ckall
);
static
inline
void
selinux_xfrm_notify_policyload
(
void
)
...
...
@@ -64,19 +56,21 @@ static inline int selinux_xfrm_enabled(void)
return
0
;
}
static
inline
int
selinux_xfrm_sock_rcv_skb
(
u32
isec
_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
)
static
inline
int
selinux_xfrm_sock_rcv_skb
(
u32
sk
_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
)
{
return
0
;
}
static
inline
int
selinux_xfrm_postroute_last
(
u32
isec_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
,
u8
proto
)
static
inline
int
selinux_xfrm_postroute_last
(
u32
sk_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
;
...
...
@@ -87,10 +81,9 @@ static inline void selinux_xfrm_notify_policyload(void)
}
#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
);
BUG_ON
(
err
);
return
selinux_xfrm_decode_session
(
skb
,
sid
,
0
);
}
#endif
/* _SELINUX_XFRM_H_ */
security/selinux/netlabel.c
View file @
6f799c97
...
...
@@ -442,8 +442,7 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
sksec
->
nlbl_state
!=
NLBL_CONNLABELED
)
return
0
;
local_bh_disable
();
bh_lock_sock_nested
(
sk
);
lock_sock
(
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
...
...
@@ -464,7 +463,6 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
sksec
->
nlbl_state
=
NLBL_CONNLABELED
;
socket_connect_return:
bh_unlock_sock
(
sk
);
local_bh_enable
();
release_sock
(
sk
);
return
rc
;
}
security/selinux/netnode.c
View file @
6f799c97
...
...
@@ -166,6 +166,7 @@ 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
...
...
@@ -225,6 +226,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
break
;
default:
BUG
();
ret
=
-
EINVAL
;
}
if
(
ret
!=
0
)
goto
out
;
...
...
security/selinux/selinuxfs.c
View file @
6f799c97
...
...
@@ -44,7 +44,9 @@
/* Policy capability filenames */
static
char
*
policycap_names
[]
=
{
"network_peer_controls"
,
"open_perms"
"open_perms"
,
"redhat1"
,
"always_check_network"
};
unsigned
int
selinux_checkreqprot
=
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE
;
...
...
security/selinux/ss/ebitmap.c
View file @
6f799c97
...
...
@@ -213,7 +213,12 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
}
#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
;
int
i
;
...
...
@@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
n1
=
e1
->
node
;
n2
=
e2
->
node
;
while
(
n1
&&
n2
&&
(
n1
->
startbit
<=
n2
->
startbit
))
{
if
(
n1
->
startbit
<
n2
->
startbit
)
{
n1
=
n1
->
next
;
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
])
return
0
;
i
--
;
}
n1
=
n1
->
next
;
...
...
security/selinux/ss/ebitmap.h
View file @
6f799c97
...
...
@@ -16,7 +16,13 @@
#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))
#define EBITMAP_UNIT_SIZE BITS_PER_LONG
#define EBITMAP_SIZE (EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE)
...
...
@@ -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_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_set_bit
(
struct
ebitmap
*
e
,
unsigned
long
bit
,
int
value
);
void
ebitmap_destroy
(
struct
ebitmap
*
e
);
...
...
security/selinux/ss/mls.c
View file @
6f799c97
...
...
@@ -160,8 +160,6 @@ 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
;
...
...
@@ -170,19 +168,13 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)
if
(
!
levdatum
)
return
0
;
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
;
/*
* 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
);
}
int
mls_range_isvalid
(
struct
policydb
*
p
,
struct
mls_range
*
r
)
...
...
security/selinux/ss/mls_types.h
View file @
6f799c97
...
...
@@ -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
));
ebitmap_contains
(
&
l1
->
cat
,
&
l2
->
cat
,
0
));
}
#define mls_level_incomp(l1, l2) \
...
...
security/selinux/ss/policydb.c
View file @
6f799c97
...
...
@@ -3203,9 +3203,8 @@ 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
;
int
rc
,
nel
;
struct
policy_data
pd
;
pd
.
p
=
p
;
...
...
security/selinux/ss/services.c
View file @
6f799c97
...
...
@@ -72,6 +72,7 @@
int
selinux_policycap_netpeer
;
int
selinux_policycap_openperm
;
int
selinux_policycap_alwaysnetwork
;
static
DEFINE_RWLOCK
(
policy_rwlock
);
...
...
@@ -1812,6 +1813,8 @@ 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
);
...
...
@@ -2323,43 +2326,74 @@ int security_genfs_sid(const char *fstype,
/**
* security_fs_use - Determine how to handle labeling for a filesystem.
* @fstype: filesystem type
* @behavior: labeling behavior
* @sid: SID for filesystem (superblock)
* @sb: superblock in question
*/
int
security_fs_use
(
const
char
*
fstype
,
unsigned
int
*
behavior
,
u32
*
sid
)
int
security_fs_use
(
struct
super_block
*
sb
)
{
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
);
c
=
policydb
.
ocontexts
[
OCON_FSUSE
];
while
(
c
)
{
if
(
strcmp
(
fstype
,
c
->
u
.
name
)
==
0
)
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
))
break
;
c
=
c
->
next
;
}
/* in case we had found an fstype match but no subtype match */
if
(
!
c
)
c
=
base
;
if
(
c
)
{
*
behavior
=
c
->
v
.
behavior
;
sbsec
->
behavior
=
c
->
v
.
behavior
;
if
(
!
c
->
sid
[
0
])
{
rc
=
sidtab_context_to_sid
(
&
sidtab
,
&
c
->
context
[
0
],
&
c
->
sid
[
0
]);
if
(
rc
)
goto
out
;
}
*
sid
=
c
->
sid
[
0
];
sbsec
->
sid
=
c
->
sid
[
0
];
}
else
{
rc
=
security_genfs_sid
(
fstype
,
"/"
,
SECCLASS_DIR
,
sid
);
rc
=
security_genfs_sid
(
fstype
,
"/"
,
SECCLASS_DIR
,
&
sbsec
->
sid
);
if
(
rc
)
{
*
behavior
=
SECURITY_FS_USE_NONE
;
sbsec
->
behavior
=
SECURITY_FS_USE_NONE
;
rc
=
0
;
}
else
{
*
behavior
=
SECURITY_FS_USE_GENFS
;
sbsec
->
behavior
=
SECURITY_FS_USE_GENFS
;
}
}
...
...
security/selinux/xfrm.c
View file @
6f799c97
...
...
@@ -56,7 +56,7 @@
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
)
{
...
...
@@ -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,48 +74,111 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
}
/*
*
LSM hook implementation that authorizes that a flow can use
*
a xfrm policy rule
.
*
Allocates a xfrm_sec_state and populates it using the supplied security
*
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
;
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
(
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
;
if
(
ctxp
==
NULL
||
uctx
==
NULL
||
uctx
->
ctx_doi
!=
XFRM_SC_DOI_LSM
||
uctx
->
ctx_alg
!=
XFRM_SC_ALG_SELINUX
)
return
-
EINVAL
;
rc
=
avc_has_perm
(
fl_secid
,
sel_sid
,
SECCLASS_ASSOCIATION
,
ASSOCIATION__POLMATCH
,
NULL
)
;
str_len
=
uctx
->
ctx_len
;
if
(
str_len
>=
PAGE_SIZE
)
return
-
ENOMEM
;
if
(
rc
==
-
EACCES
)
return
-
ESRCH
;
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.
*/
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
* 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
)
...
...
@@ -138,187 +201,80 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
if
(
fl
->
flowi_secid
!=
state_sid
)
return
0
;
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
;
/* 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
);
}
/*
* 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
)
return
0
;
goto
out
;
sp
=
skb
->
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
];
if
(
selinux_authorizable_xfrm
(
x
))
{
struct
xfrm_sec_ctx
*
ctx
=
x
->
security
;
if
(
!
sid_set
)
{
*
sid
=
ctx
->
ctx_sid
;
sid_set
=
1
;
if
(
sid_session
==
SECSID_NULL
)
{
sid_session
=
ctx
->
ctx_sid
;
if
(
!
ckall
)
break
;
}
else
if
(
*
sid
!=
ctx
->
ctx_sid
)
goto
out
;
}
else
if
(
sid_session
!=
ctx
->
ctx_sid
)
{
*
sid
=
SECSID_NULL
;
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:
*
ctxp
=
NULL
;
kfree
(
ctx
);
out2:
kfree
(
ctx_str
);
return
rc
;
*
sid
=
sid_session
;
return
0
;
}
/*
* LSM hook implementation that allocs and transfers uctx spec to
* xfrm_policy.
* 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
)
{
int
err
;
BUG_ON
(
!
uctx
);
err
=
selinux_xfrm_sec_ctx_alloc
(
ctxp
,
uctx
,
0
);
if
(
err
==
0
)
atomic_inc
(
&
selinux_xfrm_refcount
);
return
err
;
return
selinux_xfrm_alloc_user
(
ctxp
,
uctx
);
}
/*
* 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
)
{
new_ctx
=
kmalloc
(
sizeof
(
*
old_ctx
)
+
old_ctx
->
ctx_len
,
GFP_ATOMIC
);
if
(
!
new_ctx
)
return
-
ENOMEM
;
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
;
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
;
}
...
...
@@ -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
)
{
atomic_dec
(
&
selinux_xfrm_refcount
);
kfree
(
ctx
);
selinux_xfrm_free
(
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
)
{
const
struct
task_security_struct
*
tsec
=
current_security
();
if
(
!
ctx
)
return
0
;
return
selinux_xfrm_delete
(
ctx
);
}
return
avc_has_perm
(
tsec
->
sid
,
ctx
->
ctx_sid
,
SECCLASS_ASSOCIATION
,
ASSOCIATION__SETCONTEXT
,
NULL
);
/*
* 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
);
}
/*
* LSM hook implementation that alloc
s and transfers sec_ctx spec to
*
xfrm_state
.
* LSM hook implementation that alloc
ates a xfrm_sec_state and populates based
*
on a secid
.
*/
int
selinux_xfrm_state_alloc
(
struct
xfrm_state
*
x
,
struct
xfrm_user_sec_ctx
*
uct
x
,
u32
secid
)
int
selinux_xfrm_state_alloc
_acquire
(
struct
xfrm_state
*
x
,
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
);
if
(
err
==
0
)
atomic_inc
(
&
selinux_xfrm_refcount
);
return
err
;
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
;
}
/*
...
...
@@ -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
)
{
atomic_dec
(
&
selinux_xfrm_refcount
);
kfree
(
x
->
security
);
selinux_xfrm_free
(
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
)
{
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
);
return
selinux_xfrm_delete
(
x
->
security
);
}
/*
...
...
@@ -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
* gone thru the IPSec process.
*/
int
selinux_xfrm_sock_rcv_skb
(
u32
isec
_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
)
int
selinux_xfrm_sock_rcv_skb
(
u32
sk
_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
)
{
int
i
,
rc
=
0
;
struct
sec_path
*
sp
;
u32
sel_sid
=
SECINITSID_UNLABELED
;
sp
=
skb
->
sp
;
int
i
;
struct
sec_path
*
sp
=
skb
->
sp
;
u32
peer_sid
=
SECINITSID_UNLABELED
;
if
(
sp
)
{
for
(
i
=
0
;
i
<
sp
->
len
;
i
++
)
{
...
...
@@ -410,23 +378,17 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,
if
(
x
&&
selinux_authorizable_xfrm
(
x
))
{
struct
xfrm_sec_ctx
*
ctx
=
x
->
security
;
sel
_sid
=
ctx
->
ctx_sid
;
peer
_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.
*/
rc
=
avc_has_perm
(
isec_sid
,
sel_sid
,
SECCLASS_ASSOCIATION
,
ASSOCIATION__RECVFROM
,
ad
);
return
rc
;
/* 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
);
}
/*
...
...
@@ -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
* checked in the selinux_xfrm_state_pol_flow_match hook above.
*/
int
selinux_xfrm_postroute_last
(
u32
isec
_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
,
u8
proto
)
int
selinux_xfrm_postroute_last
(
u32
sk
_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.
*/
goto
out
;
/* We should have already seen this packet once before it
* underwent xfrm(s). No need to subject it to the unlabeled
* check. */
return
0
;
default:
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.
*/
dst
=
skb_dst
(
skb
);
if
(
dst
)
{
struct
dst_entry
*
iter
;
rc
=
avc_has_perm
(
isec_sid
,
SECINITSID_UNLABELED
,
SECCLASS_ASSOCIATION
,
ASSOCIATION__SENDTO
,
ad
);
out:
return
rc
;
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. */
return
avc_has_perm
(
sk_sid
,
SECINITSID_UNLABELED
,
SECCLASS_ASSOCIATION
,
ASSOCIATION__SENDTO
,
ad
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment