summaryrefslogtreecommitdiffstats
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c938
1 files changed, 704 insertions, 234 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 925e546b5a87..4cafe6a19167 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -67,6 +67,8 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/dccp.h>
+#include <linux/sctp.h>
+#include <net/sctp/structs.h>
#include <linux/quota.h>
#include <linux/un.h> /* for Unix socket types */
#include <net/af_unix.h> /* for Unix socket types */
@@ -98,20 +100,24 @@
#include "audit.h"
#include "avc_ss.h"
+struct selinux_state selinux_state;
+
/* SECMARK reference count */
static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
-int selinux_enforcing;
+static int selinux_enforcing_boot;
static int __init enforcing_setup(char *str)
{
unsigned long enforcing;
if (!kstrtoul(str, 0, &enforcing))
- selinux_enforcing = enforcing ? 1 : 0;
+ selinux_enforcing_boot = enforcing ? 1 : 0;
return 1;
}
__setup("enforcing=", enforcing_setup);
+#else
+#define selinux_enforcing_boot 1
#endif
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
@@ -129,6 +135,19 @@ __setup("selinux=", selinux_enabled_setup);
int selinux_enabled = 1;
#endif
+static unsigned int selinux_checkreqprot_boot =
+ CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
+
+static int __init checkreqprot_setup(char *str)
+{
+ unsigned long checkreqprot;
+
+ if (!kstrtoul(str, 0, &checkreqprot))
+ selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
+ return 1;
+}
+__setup("checkreqprot=", checkreqprot_setup);
+
static struct kmem_cache *sel_inode_cache;
static struct kmem_cache *file_security_cache;
@@ -145,7 +164,8 @@ static struct kmem_cache *file_security_cache;
*/
static int selinux_secmark_enabled(void)
{
- return (selinux_policycap_alwaysnetwork || atomic_read(&selinux_secmark_refcount));
+ return (selinux_policycap_alwaysnetwork() ||
+ atomic_read(&selinux_secmark_refcount));
}
/**
@@ -160,7 +180,8 @@ static int selinux_secmark_enabled(void)
*/
static int selinux_peerlbl_enabled(void)
{
- return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
+ return (selinux_policycap_alwaysnetwork() ||
+ netlbl_enabled() || selinux_xfrm_enabled());
}
static int selinux_netcache_avc_callback(u32 event)
@@ -264,7 +285,8 @@ static int __inode_security_revalidate(struct inode *inode,
might_sleep_if(may_sleep);
- if (ss_initialized && isec->initialized != LABEL_INITIALIZED) {
+ if (selinux_state.initialized &&
+ isec->initialized != LABEL_INITIALIZED) {
if (!may_sleep)
return -ECHILD;
@@ -446,12 +468,14 @@ static int may_context_mount_sb_relabel(u32 sid,
const struct task_security_struct *tsec = cred->security;
int rc;
- rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ tsec->sid, sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELTO, NULL);
return rc;
}
@@ -462,12 +486,14 @@ static int may_context_mount_inode_relabel(u32 sid,
{
const struct task_security_struct *tsec = cred->security;
int rc;
- rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL);
if (rc)
return rc;
- rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
+ rc = avc_has_perm(&selinux_state,
+ sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL);
return rc;
}
@@ -486,7 +512,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
!strcmp(sb->s_type->name, "debugfs") ||
!strcmp(sb->s_type->name, "tracefs") ||
!strcmp(sb->s_type->name, "rootfs") ||
- (selinux_policycap_cgroupseclabel &&
+ (selinux_policycap_cgroupseclabel() &&
(!strcmp(sb->s_type->name, "cgroup") ||
!strcmp(sb->s_type->name, "cgroup2")));
}
@@ -586,7 +612,7 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
if (!(sbsec->flags & SE_SBINITIALIZED))
return -EINVAL;
- if (!ss_initialized)
+ if (!selinux_state.initialized)
return -EINVAL;
/* make sure we always check enough bits to cover the mask */
@@ -617,21 +643,25 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
i = 0;
if (sbsec->flags & FSCONTEXT_MNT) {
- rc = security_sid_to_context(sbsec->sid, &context, &len);
+ rc = security_sid_to_context(&selinux_state, sbsec->sid,
+ &context, &len);
if (rc)
goto out_free;
opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
}
if (sbsec->flags & CONTEXT_MNT) {
- rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
+ rc = security_sid_to_context(&selinux_state,
+ sbsec->mntpoint_sid,
+ &context, &len);
if (rc)
goto out_free;
opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = CONTEXT_MNT;
}
if (sbsec->flags & DEFCONTEXT_MNT) {
- rc = security_sid_to_context(sbsec->def_sid, &context, &len);
+ rc = security_sid_to_context(&selinux_state, sbsec->def_sid,
+ &context, &len);
if (rc)
goto out_free;
opts->mnt_opts[i] = context;
@@ -641,7 +671,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
struct dentry *root = sbsec->sb->s_root;
struct inode_security_struct *isec = backing_inode_security(root);
- rc = security_sid_to_context(isec->sid, &context, &len);
+ rc = security_sid_to_context(&selinux_state, isec->sid,
+ &context, &len);
if (rc)
goto out_free;
opts->mnt_opts[i] = context;
@@ -704,7 +735,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock);
- if (!ss_initialized) {
+ if (!selinux_state.initialized) {
if (!num_opts) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
@@ -750,7 +781,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (flags[i] == SBLABEL_MNT)
continue;
- rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
+ rc = security_context_str_to_sid(&selinux_state,
+ mount_options[i], &sid,
+ GFP_KERNEL);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -826,7 +859,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(sb);
+ rc = security_fs_use(&selinux_state, sb);
if (rc) {
printk(KERN_WARNING
"%s: security_fs_use(%s) returned %d\n",
@@ -851,7 +884,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
- rc = security_transition_sid(current_sid(), current_sid(),
+ rc = security_transition_sid(&selinux_state,
+ current_sid(),
+ current_sid(),
SECCLASS_FILE, NULL,
&sbsec->mntpoint_sid);
if (rc)
@@ -987,7 +1022,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
* if the parent was able to be mounted it clearly had no special lsm
* mount options. thus we can safely deal with this superblock later
*/
- if (!ss_initialized)
+ if (!selinux_state.initialized)
return 0;
/*
@@ -1014,7 +1049,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
- rc = security_fs_use(newsb);
+ rc = security_fs_use(&selinux_state, newsb);
if (rc)
goto out;
}
@@ -1297,7 +1332,7 @@ static inline int default_protocol_dgram(int protocol)
static inline u16 socket_type_to_security_class(int family, int type, int protocol)
{
- int extsockclass = selinux_policycap_extsockclass;
+ int extsockclass = selinux_policycap_extsockclass();
switch (family) {
case PF_UNIX:
@@ -1471,7 +1506,8 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
path++;
}
}
- rc = security_genfs_sid(sb->s_type->name, path, tclass, sid);
+ rc = security_genfs_sid(&selinux_state, sb->s_type->name,
+ path, tclass, sid);
}
free_page((unsigned long)buffer);
return rc;
@@ -1589,7 +1625,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->def_sid;
rc = 0;
} else {
- rc = security_context_to_sid_default(context, rc, &sid,
+ rc = security_context_to_sid_default(&selinux_state,
+ context, rc, &sid,
sbsec->def_sid,
GFP_NOFS);
if (rc) {
@@ -1622,7 +1659,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->sid;
/* Try to obtain a transition SID. */
- rc = security_transition_sid(task_sid, sid, sclass, NULL, &sid);
+ rc = security_transition_sid(&selinux_state, task_sid, sid,
+ sclass, NULL, &sid);
if (rc)
goto out;
break;
@@ -1740,9 +1778,11 @@ static int cred_has_capability(const struct cred *cred,
return -EINVAL;
}
- rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
+ rc = avc_has_perm_noaudit(&selinux_state,
+ sid, sid, sclass, av, 0, &avd);
if (audit == SECURITY_CAP_AUDIT) {
- int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
+ int rc2 = avc_audit(&selinux_state,
+ sid, sid, sclass, av, &avd, rc, &ad, 0);
if (rc2)
return rc2;
}
@@ -1768,7 +1808,8 @@ static int inode_has_perm(const struct cred *cred,
sid = cred_sid(cred);
isec = inode->i_security;
- return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, perms, adp);
}
/* Same as inode_has_perm, but pass explicit audit data containing
@@ -1841,7 +1882,8 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file;
if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -1883,7 +1925,8 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
*_new_isid = tsec->create_sid;
} else {
const struct inode_security_struct *dsec = inode_security(dir);
- return security_transition_sid(tsec->sid, dsec->sid, tclass,
+ return security_transition_sid(&selinux_state, tsec->sid,
+ dsec->sid, tclass,
name, _new_isid);
}
@@ -1910,7 +1953,8 @@ static int may_create(struct inode *dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
- rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
+ rc = avc_has_perm(&selinux_state,
+ sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
&ad);
if (rc)
@@ -1921,11 +1965,13 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;
- return avc_has_perm(newsid, sbsec->sid,
+ return avc_has_perm(&selinux_state,
+ newsid, sbsec->sid,
SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, &ad);
}
@@ -1954,7 +2000,8 @@ static int may_link(struct inode *dir,
av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
- rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
@@ -1974,7 +2021,8 @@ static int may_link(struct inode *dir,
return 0;
}
- rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, av, &ad);
return rc;
}
@@ -1998,16 +2046,19 @@ static inline int may_rename(struct inode *old_dir,
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = old_dentry;
- rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
+ rc = avc_has_perm(&selinux_state,
+ sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
return rc;
- rc = avc_has_perm(sid, old_isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, old_isec->sid,
old_isec->sclass, FILE__RENAME, &ad);
if (rc)
return rc;
if (old_is_dir && new_dir != old_dir) {
- rc = avc_has_perm(sid, old_isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, old_isec->sid,
old_isec->sclass, DIR__REPARENT, &ad);
if (rc)
return rc;
@@ -2017,13 +2068,15 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH;
if (d_is_positive(new_dentry))
av |= DIR__REMOVE_NAME;
- rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry);
- rc = avc_has_perm(sid, new_isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, new_isec->sid,
new_isec->sclass,
(new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
if (rc)
@@ -2043,7 +2096,8 @@ static int superblock_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred);
sbsec = sb->s_security;
- return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
+ return avc_has_perm(&selinux_state,
+ sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
}
/* Convert a Linux mode and permission mask to an access vector. */
@@ -2106,7 +2160,8 @@ static inline u32 open_file_to_av(struct file *file)
u32 av = file_to_av(file);
struct inode *inode = file_inode(file);
- if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC)
+ if (selinux_policycap_openperm() &&
+ inode->i_sb->s_magic != SOCKFS_MAGIC)
av |= FILE__OPEN;
return av;
@@ -2119,7 +2174,8 @@ static int selinux_binder_set_context_mgr(struct task_struct *mgr)
u32 mysid = current_sid();
u32 mgrsid = task_sid(mgr);
- return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER,
+ return avc_has_perm(&selinux_state,
+ mysid, mgrsid, SECCLASS_BINDER,
BINDER__SET_CONTEXT_MGR, NULL);
}
@@ -2132,13 +2188,15 @@ static int selinux_binder_transaction(struct task_struct *from,
int rc;
if (mysid != fromsid) {
- rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER,
+ rc = avc_has_perm(&selinux_state,
+ mysid, fromsid, SECCLASS_BINDER,
BINDER__IMPERSONATE, NULL);
if (rc)
return rc;
}
- return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
+ return avc_has_perm(&selinux_state,
+ fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
NULL);
}
@@ -2148,7 +2206,8 @@ static int selinux_binder_transfer_binder(struct task_struct *from,
u32 fromsid = task_sid(from);
u32 tosid = task_sid(to);
- return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
+ return avc_has_perm(&selinux_state,
+ fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
NULL);
}
@@ -2167,7 +2226,8 @@ static int selinux_binder_transfer_file(struct task_struct *from,
ad.u.path = file->f_path;
if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -2185,7 +2245,8 @@ static int selinux_binder_transfer_file(struct task_struct *from,
return 0;
isec = backing_inode_security(dentry);
- return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, file_to_av(file),
&ad);
}
@@ -2196,21 +2257,25 @@ static int selinux_ptrace_access_check(struct task_struct *child,
u32 csid = task_sid(child);
if (mode & PTRACE_MODE_READ)
- return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, csid, SECCLASS_FILE, FILE__READ, NULL);
- return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
static int selinux_ptrace_traceme(struct task_struct *parent)
{
- return avc_has_perm(task_sid(parent), current_sid(), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ task_sid(parent), current_sid(), SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
}
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- return avc_has_perm(current_sid(), task_sid(target), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(target), SECCLASS_PROCESS,
PROCESS__GETCAP, NULL);
}
@@ -2219,7 +2284,8 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
PROCESS__SETCAP, NULL);
}
@@ -2279,18 +2345,21 @@ static int selinux_syslog(int type)
switch (type) {
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL:
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
NULL);
}
/* All other syslog types */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
}
@@ -2351,13 +2420,14 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
* policy allows the corresponding permission between
* the old and new contexts.
*/
- if (selinux_policycap_nnp_nosuid_transition) {
+ if (selinux_policycap_nnp_nosuid_transition()) {
av = 0;
if (nnp)
av |= PROCESS2__NNP_TRANSITION;
if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION;
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL);
if (!rc)
return 0;
@@ -2368,7 +2438,8 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
* i.e. SIDs that are guaranteed to only be allowed a subset
* of the permissions of the current SID.
*/
- rc = security_bounded_transition(old_tsec->sid, new_tsec->sid);
+ rc = security_bounded_transition(&selinux_state, old_tsec->sid,
+ new_tsec->sid);
if (!rc)
return 0;
@@ -2420,8 +2491,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
return rc;
} else {
/* Check for a default transition on this program. */
- rc = security_transition_sid(old_tsec->sid, isec->sid,
- SECCLASS_PROCESS, NULL,
+ rc = security_transition_sid(&selinux_state, old_tsec->sid,
+ isec->sid, SECCLASS_PROCESS, NULL,
&new_tsec->sid);
if (rc)
return rc;
@@ -2439,25 +2510,29 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
- rc = avc_has_perm(old_tsec->sid, isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc)
return rc;
} else {
/* Check permissions for the transition. */
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
if (rc)
return rc;
- rc = avc_has_perm(new_tsec->sid, isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ new_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
if (rc)
return rc;
/* Check for shared state */
if (bprm->unsafe & LSM_UNSAFE_SHARE) {
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__SHARE,
NULL);
if (rc)
@@ -2469,7 +2544,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
u32 ptsid = ptrace_parent_sid();
if (ptsid != 0) {
- rc = avc_has_perm(ptsid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ ptsid, new_tsec->sid,
SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
if (rc)
@@ -2483,7 +2559,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
/* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */
- rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__NOATSECURE,
NULL);
bprm->secureexec |= !!rc;
@@ -2575,7 +2652,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/
- rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL);
if (rc) {
/* protect against do_prlimit() */
@@ -2615,7 +2693,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID.
*/
- rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
+ rc = avc_has_perm(&selinux_state,
+ osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) {
if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
memset(&itimer, 0, sizeof itimer);
@@ -2779,7 +2858,9 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
if (flags[i] == SBLABEL_MNT)
continue;
- rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
+ rc = security_context_str_to_sid(&selinux_state,
+ mount_options[i], &sid,
+ GFP_KERNEL);
if (rc) {
printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n",
@@ -2904,7 +2985,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
if (rc)
return rc;
- return security_sid_to_context(newsid, (char **)ctx, ctxlen);
+ return security_sid_to_context(&selinux_state, newsid, (char **)ctx,
+ ctxlen);
}
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
@@ -2958,14 +3040,15 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec->initialized = LABEL_INITIALIZED;
}
- if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT))
+ if (!selinux_state.initialized || !(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
if (name)
*name = XATTR_SELINUX_SUFFIX;
if (value && len) {
- rc = security_sid_to_context_force(newsid, &context, &clen);
+ rc = security_sid_to_context_force(&selinux_state, newsid,
+ &context, &clen);
if (rc)
return rc;
*value = context;
@@ -3040,7 +3123,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec))
return PTR_ERR(isec);
- return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
+ return avc_has_perm_flags(&selinux_state,
+ sid, isec->sid, isec->sclass, FILE__READ, &ad,
rcu ? MAY_NOT_BLOCK : 0);
}
@@ -3056,7 +3140,8 @@ static noinline int audit_inode_permission(struct inode *inode,
ad.type = LSM_AUDIT_DATA_INODE;
ad.u.inode = inode;
- rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
+ rc = slow_avc_audit(&selinux_state,
+ current_sid(), isec->sid, isec->sclass, perms,
audited, denied, result, &ad, flags);
if (rc)
return rc;
@@ -3094,7 +3179,8 @@ static int selinux_inode_permission(struct inode *inode, int mask)
if (IS_ERR(isec))
return PTR_ERR(isec);
- rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
+ rc = avc_has_perm_noaudit(&selinux_state,
+ sid, isec->sid, isec->sclass, perms, 0, &avd);
audited = avc_audit_required(perms, &avd, rc,
from_access ? FILE__AUDIT_ACCESS : 0,
&denied);
@@ -3126,7 +3212,7 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR);
- if (selinux_policycap_openperm &&
+ if (selinux_policycap_openperm() &&
inode->i_sb->s_magic != SOCKFS_MAGIC &&
(ia_valid & ATTR_SIZE) &&
!(ia_valid & ATTR_FILE))
@@ -3183,12 +3269,14 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
ad.u.dentry = dentry;
isec = backing_inode_security(dentry);
- rc = avc_has_perm(sid, isec->sid, isec->sclass,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad);
if (rc)
return rc;
- rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
+ rc = security_context_to_sid(&selinux_state, value, size, &newsid,
+ GFP_KERNEL);
if (rc == -EINVAL) {
if (!has_cap_mac_admin(true)) {
struct audit_buffer *ab;
@@ -3213,22 +3301,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return rc;
}
- rc = security_context_to_sid_force(value, size, &newsid);
+ rc = security_context_to_sid_force(&selinux_state, value,
+ size, &newsid);
}
if (rc)
return rc;
- rc = avc_has_perm(sid, newsid, isec->sclass,
+ rc = avc_has_perm(&selinux_state,
+ sid, newsid, isec->sclass,
FILE__RELABELTO, &ad);
if (rc)
return rc;
- rc = security_validate_transition(isec->sid, newsid, sid,
- isec->sclass);
+ rc = security_validate_transition(&selinux_state, isec->sid, newsid,
+ sid, isec->sclass);
if (rc)
return rc;
- return avc_has_perm(newsid,
+ return avc_has_perm(&selinux_state,
+ newsid,
sbsec->sid,
SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE,
@@ -3249,7 +3340,8 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return;
}
- rc = security_context_to_sid_force(value, size, &newsid);
+ rc = security_context_to_sid_force(&selinux_state, value, size,
+ &newsid);
if (rc) {
printk(KERN_ERR "SELinux: unable to map context to SID"
"for (%s, %lu), rc=%d\n",
@@ -3324,10 +3416,12 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
*/
isec = inode_security(inode);
if (has_cap_mac_admin(false))
- error = security_sid_to_context_force(isec->sid, &context,
+ error = security_sid_to_context_force(&selinux_state,
+ isec->sid, &context,
&size);
else
- error = security_sid_to_context(isec->sid, &context, &size);
+ error = security_sid_to_context(&selinux_state, isec->sid,
+ &context, &size);
if (error)
return error;
error = size;
@@ -3353,7 +3447,8 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size)
return -EACCES;
- rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL);
+ rc = security_context_to_sid(&selinux_state, value, size, &newsid,
+ GFP_KERNEL);
if (rc)
return rc;
@@ -3442,7 +3537,7 @@ static int selinux_file_permission(struct file *file, int mask)
isec = inode_security(inode);
if (sid == fsec->sid && fsec->isid == isec->sid &&
- fsec->pseqno == avc_policy_seqno())
+ fsec->pseqno == avc_policy_seqno(&selinux_state))
/* No change since file_open check. */
return 0;
@@ -3482,7 +3577,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path;
if (ssid != fsec->sid) {
- rc = avc_has_perm(ssid, fsec->sid,
+ rc = avc_has_perm(&selinux_state,
+ ssid, fsec->sid,
SECCLASS_FD,
FD__USE,
&ad);
@@ -3494,8 +3590,9 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0;
isec = inode_security(inode);
- rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
- requested, driver, xperm, &ad);
+ rc = avc_has_extended_perms(&selinux_state,
+ ssid, isec->sid, isec->sclass,
+ requested, driver, xperm, &ad);
out:
return rc;
}
@@ -3563,7 +3660,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable.
* This has an additional check.
*/
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL);
if (rc)
goto error;
@@ -3593,7 +3691,8 @@ static int selinux_mmap_addr(unsigned long addr)
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid();
- rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_MEMPROTECT,
MEMPROTECT__MMAP_ZERO, NULL);
}
@@ -3615,7 +3714,7 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot,
return rc;
}
- if (selinux_checkreqprot)
+ if (selinux_state.checkreqprot)
prot = reqprot;
return file_map_prot_check(file, prot,
@@ -3629,7 +3728,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
const struct cred *cred = current_cred();
u32 sid = cred_sid(cred);
- if (selinux_checkreqprot)
+ if (selinux_state.checkreqprot)
prot = reqprot;
if (default_noexec &&
@@ -3637,13 +3736,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
int rc = 0;
if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) {
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file &&
((vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack) ||
vma_is_stack_for_current(vma))) {
- rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
+ rc = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL);
} else if (vma->vm_file && vma->anon_vma) {
/*
@@ -3735,7 +3836,8 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else
perm = signal_to_av(signum);
- return avc_has_perm(fsec->fown_sid, sid,
+ return avc_has_perm(&selinux_state,
+ fsec->fown_sid, sid,
SECCLASS_PROCESS, perm, NULL);
}
@@ -3761,7 +3863,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
* struct as its SID.
*/
fsec->isid = isec->sid;
- fsec->pseqno = avc_policy_seqno();
+ fsec->pseqno = avc_policy_seqno(&selinux_state);
/*
* Since the inode label or policy seqno may have changed
* between the selinux_inode_permission check and the saving
@@ -3780,7 +3882,8 @@ static int selinux_task_alloc(struct task_struct *task,
{
u32 sid = current_sid();
- return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
}
/*
@@ -3844,6 +3947,11 @@ static void selinux_cred_transfer(struct cred *new, const struct cred *old)
*tsec = *old_tsec;
}
+static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
+{
+ *secid = cred_sid(c);
+}
+
/*
* set the security data for a kernel service
* - all the creation contexts are set to unlabelled
@@ -3854,7 +3962,8 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(sid, secid,
+ ret = avc_has_perm(&selinux_state,
+ sid, secid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__USE_AS_OVERRIDE,
NULL);
@@ -3878,7 +3987,8 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
u32 sid = current_sid();
int ret;
- ret = avc_has_perm(sid, isec->sid,
+ ret = avc_has_perm(&selinux_state,
+ sid, isec->sid,
SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__CREATE_FILES_AS,
NULL);
@@ -3895,7 +4005,8 @@ static int selinux_kernel_module_request(char *kmod_name)
ad.type = LSM_AUDIT_DATA_KMOD;
ad.u.kmod_name = kmod_name;
- return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
SYSTEM__MODULE_REQUEST, &ad);
}
@@ -3909,7 +4020,8 @@ static int selinux_kernel_module_from_file(struct file *file)
/* init_module */
if (file == NULL)
- return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
+ return avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_SYSTEM,
SYSTEM__MODULE_LOAD, NULL);
/* finit_module */
@@ -3919,13 +4031,15 @@ static int selinux_kernel_module_from_file(struct file *file)
fsec = file->f_security;
if (sid != fsec->sid) {
- rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
+ rc = avc_has_perm(&selinux_state,
+ sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
if (rc)
return rc;
}
isec = inode_security(file_inode(file));
- return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SYSTEM,
SYSTEM__MODULE_LOAD, &ad);
}
@@ -3947,19 +4061,22 @@ static int selinux_kernel_read_file(struct file *file,
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETPGID, NULL);
}
static int selinux_task_getpgid(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETPGID, NULL);
}
static int selinux_task_getsid(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETSESSION, NULL);
}
@@ -3970,19 +4087,22 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
static int selinux_task_setnice(struct task_struct *p, int nice)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getioprio(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
@@ -3997,7 +4117,8 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
av |= PROCESS__SETRLIMIT;
if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT;
- return avc_has_perm(cred_sid(cred), cred_sid(tcred),
+ return avc_has_perm(&selinux_state,
+ cred_sid(cred), cred_sid(tcred),
SECCLASS_PROCESS, av, NULL);
}
@@ -4011,7 +4132,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
- return avc_has_perm(current_sid(), task_sid(p),
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
return 0;
@@ -4019,34 +4141,41 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
static int selinux_task_movememory(struct task_struct *p)
{
- return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS,
+ return avc_has_perm(&selinux_state,
+ current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
- int sig, u32 secid)
+ int sig, const struct cred *cred)
{
+ u32 secid;
u32 perm;
if (!sig)
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
perm = signal_to_av(sig);
- if (!secid)
+ if (!cred)
secid = current_sid();
- return avc_has_perm(secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
+ else
+ secid = cred_sid(cred);
+ return avc_has_perm(&selinux_state,
+ secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
}
static void selinux_task_to_inode(struct task_struct *p,
@@ -4134,6 +4263,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
break;
}
+#if IS_ENABLED(CONFIG_IP_SCTP)
+ case IPPROTO_SCTP: {
+ struct sctphdr _sctph, *sh;
+
+ if (ntohs(ih->frag_off) & IP_OFFSET)
+ break;
+
+ offset += ihlen;
+ sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
+ if (sh == NULL)
+ break;
+
+ ad->u.net->sport = sh->source;
+ ad->u.net->dport = sh->dest;
+ break;
+ }
+#endif
default:
break;
}
@@ -4207,6 +4353,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
break;
}
+#if IS_ENABLED(CONFIG_IP_SCTP)
+ case IPPROTO_SCTP: {
+ struct sctphdr _sctph, *sh;
+
+ sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
+ if (sh == NULL)
+ break;
+
+ ad->u.net->sport = sh->source;
+ ad->u.net->dport = sh->dest;
+ break;
+ }
+#endif
/* includes fragments */
default:
break;
@@ -4287,7 +4446,8 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
if (unlikely(err))
return -EACCES;
- err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid);
+ err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
+ nlbl_type, xfrm_sid, sid);
if (unlikely(err)) {
printk(KERN_WARNING
"SELinux: failure in selinux_skb_peerlbl_sid(),"
@@ -4315,7 +4475,8 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
int err = 0;
if (skb_sid != SECSID_NULL)
- err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid);
+ err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
+ conn_sid);
else
*conn_sid = sk_sid;
@@ -4332,8 +4493,8 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
return 0;
}
- return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL,
- socksid);
+ return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
+ secclass, NULL, socksid);
}
static int sock_has_perm(struct sock *sk, u32 perms)
@@ -4349,7 +4510,8 @@ static int sock_has_perm(struct sock *sk, u32 perms)
ad.u.net = &net;
ad.u.net->sk = sk;
- return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
+ return avc_has_perm(&selinux_state,
+ current_sid(), sksec->sid, sksec->sclass, perms,
&ad);
}
@@ -4369,7 +4531,8 @@ static int selinux_socket_create(int family, int type,
if (rc)
return rc;
- return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
+ return avc_has_perm(&selinux_state,
+ tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
}
static int selinux_socket_post_create(struct socket *sock, int family,
@@ -4396,6 +4559,10 @@ static int selinux_socket_post_create(struct socket *sock, int family,
sksec = sock->sk->sk_security;
sksec->sclass = sclass;
sksec->sid = sid;
+ /* Allows detection of the first association on this socket */
+ if (sksec->sclass == SECCLASS_SCTP_SOCKET)
+ sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
+
err = selinux_netlbl_socket_post_create(sock->sk, family);
}
@@ -4416,11 +4583,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (err)
goto out;
- /*
- * If PF_INET or PF_INET6, check name_bind permission for the port.
- * Multiple address binding for SCTP is not supported yet: we just
- * check the first address now.
- */
+ /* If PF_INET or PF_INET6, check name_bind permission for the port. */
family = sk->sk_family;
if (family == PF_INET || family == PF_INET6) {
char *addrp;
@@ -4432,22 +4595,35 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
unsigned short snum;
u32 sid, node_perm;
- if (family == PF_INET) {
- if (addrlen < sizeof(struct sockaddr_in)) {
- err = -EINVAL;
- goto out;
- }
+ /*
+ * sctp_bindx(3) calls via selinux_sctp_bind_connect()
+ * that validates multiple binding addresses. Because of this
+ * need to check address->sa_family as it is possible to have
+ * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
+ */
+ switch (address->sa_family) {
+ case AF_INET:
+ if (addrlen < sizeof(struct sockaddr_in))
+ return -EINVAL;
addr4 = (struct sockaddr_in *)address;
snum = ntohs(addr4->sin_port);
addrp = (char *)&addr4->sin_addr.s_addr;
- } else {
- if (addrlen < SIN6_LEN_RFC2133) {
- err = -EINVAL;
- goto out;
- }
+ break;
+ case AF_INET6:
+ if (addrlen < SIN6_LEN_RFC2133)
+ return -EINVAL;
addr6 = (struct sockaddr_in6 *)address;
snum = ntohs(addr6->sin6_port);
addrp = (char *)&addr6->sin6_addr.s6_addr;
+ break;
+ default:
+ /* Note that SCTP services expect -EINVAL, whereas
+ * others expect -EAFNOSUPPORT.
+ */
+ if (sksec->sclass == SECCLASS_SCTP_SOCKET)
+ return -EINVAL;
+ else
+ return -EAFNOSUPPORT;
}
if (snum) {
@@ -4465,7 +4641,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
ad.u.net = &net;
ad.u.net->sport = htons(snum);
ad.u.net->family = family;
- err = avc_has_perm(sksec->sid, sid,
+ err = avc_has_perm(&selinux_state,
+ sksec->sid, sid,
sksec->sclass,
SOCKET__NAME_BIND, &ad);
if (err)
@@ -4486,6 +4663,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
node_perm = DCCP_SOCKET__NODE_BIND;
break;
+ case SECCLASS_SCTP_SOCKET:
+ node_perm = SCTP_SOCKET__NODE_BIND;
+ break;
+
default:
node_perm = RAWIP_SOCKET__NODE_BIND;
break;
@@ -4500,12 +4681,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
ad.u.net->sport = htons(snum);
ad.u.net->family = family;
- if (family == PF_INET)
+ if (address->sa_family == AF_INET)
ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
else
ad.u.net->v6info.saddr = addr6->sin6_addr;
- err = avc_has_perm(sksec->sid, sid,
+ err = avc_has_perm(&selinux_state,
+ sksec->sid, sid,
sksec->sclass, node_perm, &ad);
if (err)
goto out;
@@ -4514,7 +4696,11 @@ out:
return err;
}
-static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
+/* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
+ * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.txt
+ */
+static int selinux_socket_connect_helper(struct socket *sock,
+ struct sockaddr *address, int addrlen)
{
struct sock *sk = sock->sk;
struct sk_security_struct *sksec = sk->sk_security;
@@ -4525,10 +4711,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
return err;
/*
- * If a TCP or DCCP socket, check name_connect permission for the port.
+ * If a TCP, DCCP or SCTP socket, check name_connect permission
+ * for the port.
*/
if (sksec->sclass == SECCLASS_TCP_SOCKET ||
- sksec->sclass == SECCLASS_DCCP_SOCKET) {
+ sksec->sclass == SECCLASS_DCCP_SOCKET ||
+ sksec->sclass == SECCLASS_SCTP_SOCKET) {
struct common_audit_data ad;
struct lsm_network_audit net = {0,};
struct sockaddr_in *addr4 = NULL;
@@ -4536,38 +4724,75 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
unsigned short snum;
u32 sid, perm;
- if (sk->sk_family == PF_INET) {
+ /* sctp_connectx(3) calls via selinux_sctp_bind_connect()
+ * that validates multiple connect addresses. Because of this
+ * need to check address->sa_family as it is possible to have
+ * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
+ */
+ switch (address->sa_family) {
+ case AF_INET:
addr4 = (struct sockaddr_in *)address;
if (addrlen < sizeof(struct sockaddr_in))
return -EINVAL;
snum = ntohs(addr4->sin_port);
- } else {
+ break;
+ case AF_INET6:
addr6 = (struct sockaddr_in6 *)address;
if (addrlen < SIN6_LEN_RFC2133)
return -EINVAL;
snum = ntohs(addr6->sin6_port);
+ break;
+ default:
+ /* Note that SCTP services expect -EINVAL, whereas
+ * others expect -EAFNOSUPPORT.
+ */
+ if (sksec->sclass == SECCLASS_SCTP_SOCKET)
+ return -EINVAL;
+ else
+ return -EAFNOSUPPORT;
}
err = sel_netport_sid(sk->sk_protocol, snum, &sid);
if (err)
- goto out;
+ return err;
- perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
- TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
+ switch (sksec->sclass) {
+ case SECCLASS_TCP_SOCKET:
+ perm = TCP_SOCKET__NAME_CONNECT;
+ break;
+ case SECCLASS_DCCP_SOCKET:
+ perm = DCCP_SOCKET__NAME_CONNECT;
+ break;
+ case SECCLASS_SCTP_SOCKET:
+ perm = SCTP_SOCKET__NAME_CONNECT;
+ break;
+ }
ad.type = LSM_AUDIT_DATA_NET;
ad.u.net = &net;
ad.u.net->dport = htons(snum);
ad.u.net->family = sk->sk_family;
- err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
+ err = avc_has_perm(&selinux_state,
+ sksec->sid, sid, sksec->sclass, perm, &ad);
if (err)
- goto out;
+ return err;
}
- err = selinux_netlbl_socket_connect(sk, address);
+ return 0;
+}
-out:
- return err;
+/* Supports connect(2), see comments in selinux_socket_connect_helper() */
+static int selinux_socket_connect(struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ int err;
+ struct sock *sk = sock->sk;
+
+ err = selinux_socket_connect_helper(sock, address, addrlen);
+ if (err)
+ return err;
+
+ return selinux_netlbl_socket_connect(sk, address);
}
static int selinux_socket_listen(struct socket *sock, int backlog)
@@ -4660,7 +4885,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
ad.u.net = &net;
ad.u.net->sk = other;
- err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
+ err = avc_has_perm(&selinux_state,
+ sksec_sock->sid, sksec_other->sid,
sksec_other->sclass,
UNIX_STREAM_SOCKET__CONNECTTO, &ad);
if (err)
@@ -4668,8 +4894,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
/* server child socket */
sksec_new->peer_sid = sksec_sock->sid;
- err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid,
- &sksec_new->sid);
+ err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
+ sksec_sock->sid, &sksec_new->sid);
if (err)
return err;
@@ -4691,7 +4917,8 @@ static int selinux_socket_unix_may_send(struct socket *sock,
ad.u.net = &net;
ad.u.net->sk = other->sk;
- return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+ return avc_has_perm(&selinux_state,
+ ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
&ad);
}
@@ -4706,7 +4933,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netif_sid(ns, ifindex, &if_sid);
if (err)
return err;
- err = avc_has_perm(peer_sid, if_sid,
+ err = avc_has_perm(&selinux_state,
+ peer_sid, if_sid,
SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err)
return err;
@@ -4714,7 +4942,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netnode_sid(addrp, family, &node_sid);
if (err)
return err;
- return avc_has_perm(peer_sid, node_sid,
+ return avc_has_perm(&selinux_state,
+ peer_sid, node_sid,
SECCLASS_NODE, NODE__RECVFROM, ad);
}
@@ -4737,7 +4966,8 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err;
if (selinux_secmark_enabled()) {
- err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+ err = avc_has_perm(&selinux_state,
+ sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
return err;
@@ -4774,7 +5004,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* to the selinux_sock_rcv_skb_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
- if (!selinux_policycap_netpeer)
+ if (!selinux_policycap_netpeer())
return selinux_sock_rcv_skb_compat(sk, skb, family);
secmark_active = selinux_secmark_enabled();
@@ -4802,7 +5032,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
selinux_netlbl_err(skb, family, err, 0);
return err;
}
- err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
+ err = avc_has_perm(&selinux_state,
+ sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad);
if (err) {
selinux_netlbl_err(skb, family, err, 0);
@@ -4811,7 +5042,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
if (secmark_active) {
- err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
+ err = avc_has_perm(&selinux_state,
+ sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad);
if (err)
return err;
@@ -4830,12 +5062,14 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
u32 peer_sid = SECSID_NULL;
if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
- sksec->sclass == SECCLASS_TCP_SOCKET)
+ sksec->sclass == SECCLASS_TCP_SOCKET ||
+ sksec->sclass == SECCLASS_SCTP_SOCKET)
peer_sid = sksec->peer_sid;
if (peer_sid == SECSID_NULL)
return -ENOPROTOOPT;
- err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
+ err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
+ &scontext_len);
if (err)
return err;
@@ -4943,6 +5177,172 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
sksec->sclass = isec->sclass;
}
+/* Called whenever SCTP receives an INIT chunk. This happens when an incoming
+ * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
+ * already present).
+ */
+static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
+ struct sk_buff *skb)
+{
+ struct sk_security_struct *sksec = ep->base.sk->sk_security;
+ struct common_audit_data ad;
+ struct lsm_network_audit net = {0,};
+ u8 peerlbl_active;
+ u32 peer_sid = SECINITSID_UNLABELED;
+ u32 conn_sid;
+ int err = 0;
+
+ if (!selinux_policycap_extsockclass())
+ return 0;
+
+ peerlbl_active = selinux_peerlbl_enabled();
+
+ if (peerlbl_active) {
+ /* This will return peer_sid = SECSID_NULL if there are
+ * no peer labels, see security_net_peersid_resolve().
+ */
+ err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family,
+ &peer_sid);
+ if (err)
+ return err;
+
+ if (peer_sid == SECSID_NULL)
+ peer_sid = SECINITSID_UNLABELED;
+ }
+
+ if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
+ sksec->sctp_assoc_state = SCTP_ASSOC_SET;
+
+ /* Here as first association on socket. As the peer SID
+ * was allowed by peer recv (and the netif/node checks),
+ * then it is approved by policy and used as the primary
+ * peer SID for getpeercon(3).
+ */
+ sksec->peer_sid = peer_sid;
+ } else if (sksec->peer_sid != peer_sid) {
+ /* Other association peer SIDs are checked to enforce
+ * consistency among the peer SIDs.
+ */
+ ad.type = LSM_AUDIT_DATA_NET;
+ ad.u.net = &net;
+ ad.u.net->sk = ep->base.sk;
+ err = avc_has_perm(&selinux_state,
+ sksec->peer_sid, peer_sid, sksec->sclass,
+ SCTP_SOCKET__ASSOCIATION, &ad);
+ if (err)
+ return err;
+ }
+
+ /* Compute the MLS component for the connection and store
+ * the information in ep. This will be used by SCTP TCP type
+ * sockets and peeled off connections as they cause a new
+ * socket to be generated. selinux_sctp_sk_clone() will then
+ * plug this into the new socket.
+ */
+ err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
+ if (err)
+ return err;
+
+ ep->secid = conn_sid;
+ ep->peer_secid = peer_sid;
+
+ /* Set any NetLabel labels including CIPSO/CALIPSO options. */
+ return selinux_netlbl_sctp_assoc_request(ep, skb);
+}
+
+/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
+ * based on their @optname.
+ */
+static int selinux_sctp_bind_connect(struct sock *sk, int optname,
+ struct sockaddr *address,
+ int addrlen)
+{
+ int len, err = 0, walk_size = 0;
+ void *addr_buf;
+ struct sockaddr *addr;
+ struct socket *sock;
+
+ if (!selinux_policycap_extsockclass())
+ return 0;
+
+ /* Process one or more addresses that may be IPv4 or IPv6 */
+ sock = sk->sk_socket;
+ addr_buf = address;
+
+ while (walk_size < addrlen) {
+ addr = addr_buf;
+ switch (addr->sa_family) {
+ case AF_INET:
+ len = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ len = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ return -EAFNOSUPPORT;
+ }
+
+ err = -EINVAL;
+ switch (optname) {
+ /* Bind checks */
+ case SCTP_PRIMARY_ADDR:
+ case SCTP_SET_PEER_PRIMARY_ADDR:
+ case SCTP_SOCKOPT_BINDX_ADD:
+ err = selinux_socket_bind(sock, addr, len);
+ break;
+ /* Connect checks */
+ case SCTP_SOCKOPT_CONNECTX:
+ case SCTP_PARAM_SET_PRIMARY:
+ case SCTP_PARAM_ADD_IP:
+ case SCTP_SENDMSG_CONNECT:
+ err = selinux_socket_connect_helper(sock, addr, len);
+ if (err)
+ return err;
+
+ /* As selinux_sctp_bind_connect() is called by the
+ * SCTP protocol layer, the socket is already locked,
+ * therefore selinux_netlbl_socket_connect_locked() is
+ * is called here. The situations handled are:
+ * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
+ * whenever a new IP address is added or when a new
+ * primary address is selected.
+ * Note that an SCTP connect(2) call happens before
+ * the SCTP protocol layer and is handled via
+ * selinux_socket_connect().
+ */
+ err = selinux_netlbl_socket_connect_locked(sk, addr);
+ break;
+ }
+
+ if (err)
+ return err;
+
+ addr_buf += len;
+ walk_size += len;
+ }
+
+ return 0;
+}
+
+/* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */
+static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
+ struct sock *newsk)
+{
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct sk_security_struct *newsksec = newsk->sk_security;
+
+ /* If policy does not support SECCLASS_SCTP_SOCKET then call
+ * the non-sctp clone version.
+ */
+ if (!selinux_policycap_extsockclass())
+ return selinux_sk_clone_security(sk, newsk);
+
+ newsksec->sid = ep->secid;
+ newsksec->peer_sid = ep->peer_secid;
+ newsksec->sclass = sksec->sclass;
+ selinux_netlbl_sctp_sk_clone(sk, newsk);
+}
+
static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct request_sock *req)
{
@@ -5001,7 +5401,9 @@ static int selinux_secmark_relabel_packet(u32 sid)
__tsec = current_security();
tsid = __tsec->sid;
- return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
+ return avc_has_perm(&selinux_state,
+ tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
+ NULL);
}
static void selinux_secmark_refcount_inc(void)
@@ -5049,7 +5451,8 @@ static int selinux_tun_dev_create(void)
* connections unlike traditional sockets - check the TUN driver to
* get a better understanding of why this socket is special */
- return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
+ return avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
NULL);
}
@@ -5057,7 +5460,8 @@ static int selinux_tun_dev_attach_queue(void *security)
{
struct tun_security_struct *tunsec = security;
- return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
+ return avc_has_perm(&selinux_state,
+ current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__ATTACH_QUEUE, NULL);
}
@@ -5085,11 +5489,13 @@ static int selinux_tun_dev_open(void *security)
u32 sid = current_sid();
int err;
- err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET,
+ err = avc_has_perm(&selinux_state,
+ sid, tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELFROM, NULL);
if (err)
return err;
- err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
+ err = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELTO, NULL);
if (err)
return err;
@@ -5120,7 +5526,8 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
sk->sk_protocol, nlh->nlmsg_type,
secclass_map[sksec->sclass - 1].name,
task_pid_nr(current), current->comm);
- if (!selinux_enforcing || security_get_allow_unknown())
+ if (!enforcing_enabled(&selinux_state) ||
+ security_get_allow_unknown(&selinux_state))
err = 0;
}
@@ -5150,7 +5557,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
u8 netlbl_active;
u8 peerlbl_active;
- if (!selinux_policycap_netpeer)
+ if (!selinux_policycap_netpeer())
return NF_ACCEPT;
secmark_active = selinux_secmark_enabled();
@@ -5179,7 +5586,8 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
}
if (secmark_active)
- if (avc_has_perm(peer_sid, skb->secmark,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP;
@@ -5291,7 +5699,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP;
if (selinux_secmark_enabled())
- if (avc_has_perm(sksec->sid, skb->secmark,
+ if (avc_has_perm(&selinux_state,
+ sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -5319,7 +5728,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
* to the selinux_ip_postroute_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
- if (!selinux_policycap_netpeer)
+ if (!selinux_policycap_netpeer())
return selinux_ip_postroute_compat(skb, ifindex, family);
secmark_active = selinux_secmark_enabled();
@@ -5414,7 +5823,8 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
return NF_DROP;
if (secmark_active)
- if (avc_has_perm(peer_sid, skb->secmark,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
@@ -5424,13 +5834,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
return NF_DROP;
- if (avc_has_perm(peer_sid, if_sid,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
if (sel_netnode_sid(addrp, family, &node_sid))
return NF_DROP;
- if (avc_has_perm(peer_sid, node_sid,
+ if (avc_has_perm(&selinux_state,
+ peer_sid, node_sid,
SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP_ERR(-ECONNREFUSED);
}
@@ -5518,7 +5930,8 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key;
- return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, isec->sclass, perms, &ad);
}
static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
@@ -5548,7 +5961,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad);
if (rc) {
ipc_free_security(msq);
@@ -5573,7 +5987,8 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad);
}
@@ -5586,10 +6001,12 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
case IPC_INFO:
case MSG_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
case MSG_STAT:
+ case MSG_STAT_ANY:
perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
break;
case IPC_SET:
@@ -5625,8 +6042,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
* Compute new sid based on current process and
* message queue this message will be stored in
*/
- rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG,
- NULL, &msec->sid);
+ rc = security_transition_sid(&selinux_state, sid, isec->sid,
+ SECCLASS_MSG, NULL, &msec->sid);
if (rc)
return rc;
}
@@ -5635,15 +6052,18 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */
- rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
MSGQ__WRITE, &ad);
if (!rc)
/* Can this process send the message */
- rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
+ rc = avc_has_perm(&selinux_state,
+ sid, msec->sid, SECCLASS_MSG,
MSG__SEND, &ad);
if (!rc)
/* Can the message be put in the queue? */
- rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
+ rc = avc_has_perm(&selinux_state,
+ msec->sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ENQUEUE, &ad);
return rc;
@@ -5665,10 +6085,12 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
- rc = avc_has_perm(sid, isec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid,
SECCLASS_MSGQ, MSGQ__READ, &ad);
if (!rc)
- rc = avc_has_perm(sid, msec->sid,
+ rc = avc_has_perm(&selinux_state,
+ sid, msec->sid,
SECCLASS_MSG, MSG__RECEIVE, &ad);
return rc;
}
@@ -5690,7 +6112,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad);
if (rc) {
ipc_free_security(shp);
@@ -5715,7 +6138,8 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SHM,
SHM__ASSOCIATE, &ad);
}
@@ -5729,10 +6153,12 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
case IPC_INFO:
case SHM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT:
case SHM_STAT:
+ case SHM_STAT_ANY:
perms = SHM__GETATTR | SHM__ASSOCIATE;
break;
case IPC_SET:
@@ -5783,7 +6209,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM,
+ rc = avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad);
if (rc) {
ipc_free_security(sma);
@@ -5808,7 +6235,8 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
- return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SEM,
SEM__ASSOCIATE, &ad);
}
@@ -5822,7 +6250,8 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
case IPC_INFO:
case SEM_INFO:
/* No specific object, just general system-wide information. */
- return avc_has_perm(current_sid(), SECINITSID_KERNEL,
+ return avc_has_perm(&selinux_state,
+ current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case GETPID:
case GETNCNT:
@@ -5845,6 +6274,7 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
break;
case IPC_STAT:
case SEM_STAT:
+ case SEM_STAT_ANY:
perms = SEM__GETATTR | SEM__ASSOCIATE;
break;
default:
@@ -5908,7 +6338,8 @@ static int selinux_getprocattr(struct task_struct *p,
__tsec = __task_cred(p)->security;
if (current != p) {
- error = avc_has_perm(current_sid(), __tsec->sid,
+ error = avc_has_perm(&selinux_state,
+ current_sid(), __tsec->sid,
SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
if (error)
goto bad;
@@ -5935,7 +6366,7 @@ static int selinux_getprocattr(struct task_struct *p,
if (!sid)
return 0;
- error = security_sid_to_context(sid, value, &len);
+ error = security_sid_to_context(&selinux_state, sid, value, &len);
if (error)
return error;
return len;
@@ -5957,19 +6388,24 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
* Basic control over ability to set these attributes at all.
*/
if (!strcmp(name, "exec"))
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL);
else if (!strcmp(name, "fscreate"))
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL);
else if (!strcmp(name, "keycreate"))
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL);
else if (!strcmp(name, "sockcreate"))
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL);
else if (!strcmp(name, "current"))
- error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL);
else
error = -EINVAL;
@@ -5982,7 +6418,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
str[size-1] = 0;
size--;
}
- error = security_context_to_sid(value, size, &sid, GFP_KERNEL);
+ error = security_context_to_sid(&selinux_state, value, size,
+ &sid, GFP_KERNEL);
if (error == -EINVAL && !strcmp(name, "fscreate")) {
if (!has_cap_mac_admin(true)) {
struct audit_buffer *ab;
@@ -6001,8 +6438,9 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
return error;
}
- error = security_context_to_sid_force(value, size,
- &sid);
+ error = security_context_to_sid_force(
+ &selinux_state,
+ value, size, &sid);
}
if (error)
return error;
@@ -6024,7 +6462,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
} else if (!strcmp(name, "fscreate")) {
tsec->create_sid = sid;
} else if (!strcmp(name, "keycreate")) {
- error = avc_has_perm(mysid, sid, SECCLASS_KEY, KEY__CREATE,
+ error = avc_has_perm(&selinux_state,
+ mysid, sid, SECCLASS_KEY, KEY__CREATE,
NULL);
if (error)
goto abort_change;
@@ -6039,13 +6478,15 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
/* Only allow single threaded processes to change context */
error = -EPERM;
if (!current_is_single_threaded()) {
- error = security_bounded_transition(tsec->sid, sid);
+ error = security_bounded_transition(&selinux_state,
+ tsec->sid, sid);
if (error)
goto abort_change;
}
/* Check permissions for the transition. */
- error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL);
if (error)
goto abort_change;
@@ -6054,7 +6495,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
Otherwise, leave SID unchanged and fail. */
ptsid = ptrace_parent_sid();
if (ptsid != 0) {
- error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
+ error = avc_has_perm(&selinux_state,
+ ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL);
if (error)
goto abort_change;
@@ -6081,12 +6523,14 @@ static int selinux_ismaclabel(const char *name)
static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
- return security_sid_to_context(secid, secdata, seclen);
+ return security_sid_to_context(&selinux_state, secid,
+ secdata, seclen);
}
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL);
+ return security_context_to_sid(&selinux_state, secdata, seclen,
+ secid, GFP_KERNEL);
}
static void selinux_release_secctx(char *secdata, u32 seclen)
@@ -6178,7 +6622,8 @@ static int selinux_key_permission(key_ref_t key_ref,
key = key_ref_to_ptr(key_ref);
ksec = key->security;
- return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
+ return avc_has_perm(&selinux_state,
+ sid, ksec->sid, SECCLASS_KEY, perm, NULL);
}
static int selinux_key_getsecurity(struct key *key, char **_buffer)
@@ -6188,7 +6633,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
unsigned len;
int rc;
- rc = security_sid_to_context(ksec->sid, &context, &len);
+ rc = security_sid_to_context(&selinux_state, ksec->sid,
+ &context, &len);
if (!rc)
rc = len;
*_buffer = context;
@@ -6213,7 +6659,8 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
ibpkey.subnet_prefix = subnet_prefix;
ibpkey.pkey = pkey_val;
ad.u.ibpkey = &ibpkey;
- return avc_has_perm(sec->sid, sid,
+ return avc_has_perm(&selinux_state,
+ sec->sid, sid,
SECCLASS_INFINIBAND_PKEY,
INFINIBAND_PKEY__ACCESS, &ad);
}
@@ -6227,7 +6674,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
struct ib_security_struct *sec = ib_sec;
struct lsm_ibendport_audit ibendport;
- err = security_ib_endport_sid(dev_name, port_num, &sid);
+ err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
+ &sid);
if (err)
return err;
@@ -6236,7 +6684,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name));
ibendport.port = port_num;
ad.u.ibendport = &ibendport;
- return avc_has_perm(sec->sid, sid,
+ return avc_has_perm(&selinux_state,
+ sec->sid, sid,
SECCLASS_INFINIBAND_ENDPORT,
INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
}
@@ -6269,11 +6718,13 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
switch (cmd) {
case BPF_MAP_CREATE:
- ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
+ ret = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
NULL);
break;
case BPF_PROG_LOAD:
- ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
+ ret = avc_has_perm(&selinux_state,
+ sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
NULL);
break;
default:
@@ -6313,14 +6764,16 @@ static int bpf_fd_pass(struct file *file, u32 sid)
if (file->f_op == &bpf_map_fops) {
map = file->private_data;
bpfsec = map->security;
- ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ ret = avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret)
return ret;
} else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data;
bpfsec = prog->aux->security;
- ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ ret = avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
if (ret)
return ret;
@@ -6334,7 +6787,8 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
struct bpf_security_struct *bpfsec;
bpfsec = map->security;
- return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ return avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(fmode), NULL);
}
@@ -6344,7 +6798,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
struct bpf_security_struct *bpfsec;
bpfsec = prog->aux->security;
- return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
+ return avc_has_perm(&selinux_state,
+ sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL);
}
@@ -6479,6 +6934,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(cred_free, selinux_cred_free),
LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
+ LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
@@ -6563,6 +7019,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
+ LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
+ LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
+ LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
@@ -6638,6 +7097,12 @@ static __init int selinux_init(void)
printk(KERN_INFO "SELinux: Initializing.\n");
+ memset(&selinux_state, 0, sizeof(selinux_state));
+ enforcing_set(&selinux_state, selinux_enforcing_boot);
+ selinux_state.checkreqprot = selinux_checkreqprot_boot;
+ selinux_ss_init(&selinux_state.ss);
+ selinux_avc_init(&selinux_state.avc);
+
/* Set the security state for the initial task. */
cred_init_security();
@@ -6651,6 +7116,12 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL);
avc_init();
+ avtab_cache_init();
+
+ ebitmap_cache_init();
+
+ hashtab_cache_init();
+
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
@@ -6659,7 +7130,7 @@ static __init int selinux_init(void)
if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC LSM notifier callback\n");
- if (selinux_enforcing)
+ if (selinux_enforcing_boot)
printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
else
printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
@@ -6780,23 +7251,22 @@ static void selinux_nf_ip_exit(void)
#endif /* CONFIG_NETFILTER */
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
-static int selinux_disabled;
-
-int selinux_disable(void)
+int selinux_disable(struct selinux_state *state)
{
- if (ss_initialized) {
+ if (state->initialized) {
/* Not permitted after initial policy load. */
return -EINVAL;
}
- if (selinux_disabled) {
+ if (state->disabled) {
/* Only do this once. */
return -EINVAL;
}
+ state->disabled = 1;
+
printk(KERN_INFO "SELinux: Disabled at runtime.\n");
- selinux_disabled = 1;
selinux_enabled = 0;
security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));