aboutsummaryrefslogtreecommitdiffstats
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/avc.c6
-rw-r--r--security/selinux/hooks.c457
-rw-r--r--security/selinux/ibpkey.c2
-rw-r--r--security/selinux/ima.c8
-rw-r--r--security/selinux/include/audit.h7
-rw-r--r--security/selinux/include/avc.h3
-rw-r--r--security/selinux/include/avc_ss.h4
-rw-r--r--security/selinux/include/classmap.h6
-rw-r--r--security/selinux/include/ibpkey.h2
-rw-r--r--security/selinux/include/initial_sid_to_string.h3
-rw-r--r--security/selinux/include/netnode.h2
-rw-r--r--security/selinux/include/netport.h2
-rw-r--r--security/selinux/include/policycap.h21
-rw-r--r--security/selinux/include/policycap_names.h5
-rw-r--r--security/selinux/include/security.h35
-rw-r--r--security/selinux/include/xfrm.h2
-rw-r--r--security/selinux/netnode.c9
-rw-r--r--security/selinux/netport.c2
-rw-r--r--security/selinux/nlmsgtab.c18
-rw-r--r--security/selinux/selinuxfs.c27
-rw-r--r--security/selinux/ss/avtab.c26
-rw-r--r--security/selinux/ss/conditional.c5
-rw-r--r--security/selinux/ss/context.h17
-rw-r--r--security/selinux/ss/ebitmap.c22
-rw-r--r--security/selinux/ss/ebitmap.h26
-rw-r--r--security/selinux/ss/hashtab.c3
-rw-r--r--security/selinux/ss/mls.c1
-rw-r--r--security/selinux/ss/mls_types.h4
-rw-r--r--security/selinux/ss/policydb.c40
-rw-r--r--security/selinux/ss/policydb.h2
-rw-r--r--security/selinux/ss/services.c71
-rw-r--r--security/selinux/ss/sidtab.c10
-rw-r--r--security/selinux/ss/sidtab.h2
-rw-r--r--security/selinux/xfrm.c6
34 files changed, 427 insertions, 429 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index abcd9740d10f..9a43af0ebd7d 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -668,7 +668,7 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
struct common_audit_data *ad = a;
struct selinux_audit_data *sad = ad->selinux_audit_data;
u32 av = sad->audited;
- const char **perms;
+ const char *const *perms;
int i, perm;
audit_log_format(ab, "avc: %s ", sad->denied ? "denied" : "granted");
@@ -1059,7 +1059,7 @@ int avc_has_extended_perms(struct selinux_state *state,
node = avc_lookup(state->avc, ssid, tsid, tclass);
if (unlikely(!node)) {
- node = avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node);
+ avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node);
} else {
memcpy(&avd, &node->ae.avd, sizeof(avd));
xp_node = node->ae.xp_node;
@@ -1151,7 +1151,7 @@ inline int avc_has_perm_noaudit(struct selinux_state *state,
node = avc_lookup(state->avc, ssid, tsid, tclass);
if (unlikely(!node))
- node = avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node);
+ avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node);
else
memcpy(avd, &node->ae.avd, sizeof(*avd));
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 62d30c0a30c2..f553c370397e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -25,7 +25,6 @@
#include <linux/kd.h>
#include <linux/kernel.h>
#include <linux/kernel_read_file.h>
-#include <linux/tracehook.h>
#include <linux/errno.h>
#include <linux/sched/signal.h>
#include <linux/sched/task.h>
@@ -92,6 +91,7 @@
#include <uapi/linux/mount.h>
#include <linux/fsnotify.h>
#include <linux/fanotify.h>
+#include <linux/io_uring.h>
#include "avc.h"
#include "objsec.h"
@@ -146,7 +146,7 @@ static int __init checkreqprot_setup(char *str)
if (!kstrtoul(str, 0, &checkreqprot)) {
selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
if (checkreqprot)
- pr_warn("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n");
+ pr_err("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n");
}
return 1;
}
@@ -211,10 +211,9 @@ static int selinux_lsm_notifier_avc_callback(u32 event)
*/
static void cred_init_security(void)
{
- struct cred *cred = (struct cred *) current->real_cred;
struct task_security_struct *tsec;
- tsec = selinux_cred(cred);
+ tsec = selinux_cred(unrcu_pointer(current->real_cred));
tsec->osid = tsec->sid = SECINITSID_KERNEL;
}
@@ -230,19 +229,6 @@ static inline u32 cred_sid(const struct cred *cred)
}
/*
- * get the subjective security ID of a task
- */
-static inline u32 task_sid_subj(const struct task_struct *task)
-{
- u32 sid;
-
- rcu_read_lock();
- sid = cred_sid(rcu_dereference(task->cred));
- rcu_read_unlock();
- return sid;
-}
-
-/*
* get the objective security ID of a task
*/
static inline u32 task_sid_obj(const struct task_struct *task)
@@ -354,17 +340,15 @@ static void inode_free_security(struct inode *inode)
}
struct selinux_mnt_opts {
- const char *fscontext, *context, *rootcontext, *defcontext;
+ u32 fscontext_sid;
+ u32 context_sid;
+ u32 rootcontext_sid;
+ u32 defcontext_sid;
};
static void selinux_free_mnt_opts(void *mnt_opts)
{
- struct selinux_mnt_opts *opts = mnt_opts;
- kfree(opts->fscontext);
- kfree(opts->context);
- kfree(opts->rootcontext);
- kfree(opts->defcontext);
- kfree(opts);
+ kfree(mnt_opts);
}
enum {
@@ -492,7 +476,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
static int sb_check_xattr_support(struct super_block *sb)
{
- struct superblock_security_struct *sbsec = sb->s_security;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
struct dentry *root = sb->s_root;
struct inode *root_inode = d_backing_inode(root);
u32 sid;
@@ -611,17 +595,6 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,
return 0;
}
-static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
-{
- int rc = security_context_str_to_sid(&selinux_state, s,
- sid, GFP_KERNEL);
- if (rc)
- pr_warn("SELinux: security_context_str_to_sid"
- "(%s) failed for (dev %s, type %s) errno=%d\n",
- s, sb->s_id, sb->s_type->name, rc);
- return rc;
-}
-
/*
* Allow filesystems with binary mount data to explicitly set mount point
* labeling information.
@@ -668,7 +641,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* we need to skip the double mount verification.
*
* This does open a hole in which we will not notice if the first
- * mount using this sb set explict options and a second mount using
+ * mount using this sb set explicit options and a second mount using
* this sb does not set any security options. (The first options
* will be used for both mounts)
*/
@@ -684,37 +657,29 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* than once with different security options.
*/
if (opts) {
- if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
- if (rc)
- goto out;
+ if (opts->fscontext_sid) {
+ fscontext_sid = opts->fscontext_sid;
if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
fscontext_sid))
goto out_double_mount;
sbsec->flags |= FSCONTEXT_MNT;
}
- if (opts->context) {
- rc = parse_sid(sb, opts->context, &context_sid);
- if (rc)
- goto out;
+ if (opts->context_sid) {
+ context_sid = opts->context_sid;
if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
context_sid))
goto out_double_mount;
sbsec->flags |= CONTEXT_MNT;
}
- if (opts->rootcontext) {
- rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
- if (rc)
- goto out;
+ if (opts->rootcontext_sid) {
+ rootcontext_sid = opts->rootcontext_sid;
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
rootcontext_sid))
goto out_double_mount;
sbsec->flags |= ROOTCONTEXT_MNT;
}
- if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
- if (rc)
- goto out;
+ if (opts->defcontext_sid) {
+ defcontext_sid = opts->defcontext_sid;
if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
defcontext_sid))
goto out_double_mount;
@@ -980,85 +945,67 @@ out:
return rc;
}
+/*
+ * NOTE: the caller is resposible for freeing the memory even if on error.
+ */
static int selinux_add_opt(int token, const char *s, void **mnt_opts)
{
struct selinux_mnt_opts *opts = *mnt_opts;
+ u32 *dst_sid;
+ int rc;
- if (token == Opt_seclabel) /* eaten and completely ignored */
+ if (token == Opt_seclabel)
+ /* eaten and completely ignored */
return 0;
+ if (!s)
+ return -EINVAL;
+
+ if (!selinux_initialized(&selinux_state)) {
+ pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
+ return -EINVAL;
+ }
if (!opts) {
- opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
+ opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return -ENOMEM;
*mnt_opts = opts;
}
- if (!s)
- return -ENOMEM;
+
switch (token) {
case Opt_context:
- if (opts->context || opts->defcontext)
- goto Einval;
- opts->context = s;
+ if (opts->context_sid || opts->defcontext_sid)
+ goto err;
+ dst_sid = &opts->context_sid;
break;
case Opt_fscontext:
- if (opts->fscontext)
- goto Einval;
- opts->fscontext = s;
+ if (opts->fscontext_sid)
+ goto err;
+ dst_sid = &opts->fscontext_sid;
break;
case Opt_rootcontext:
- if (opts->rootcontext)
- goto Einval;
- opts->rootcontext = s;
+ if (opts->rootcontext_sid)
+ goto err;
+ dst_sid = &opts->rootcontext_sid;
break;
case Opt_defcontext:
- if (opts->context || opts->defcontext)
- goto Einval;
- opts->defcontext = s;
+ if (opts->context_sid || opts->defcontext_sid)
+ goto err;
+ dst_sid = &opts->defcontext_sid;
break;
- }
- return 0;
-Einval:
- pr_warn(SEL_MOUNT_FAIL_MSG);
- return -EINVAL;
-}
-
-static int selinux_add_mnt_opt(const char *option, const char *val, int len,
- void **mnt_opts)
-{
- int token = Opt_error;
- int rc, i;
-
- for (i = 0; i < ARRAY_SIZE(tokens); i++) {
- if (strcmp(option, tokens[i].name) == 0) {
- token = tokens[i].opt;
- break;
- }
- }
-
- if (token == Opt_error)
+ default:
+ WARN_ON(1);
return -EINVAL;
-
- if (token != Opt_seclabel) {
- val = kmemdup_nul(val, len, GFP_KERNEL);
- if (!val) {
- rc = -ENOMEM;
- goto free_opt;
- }
- }
- rc = selinux_add_opt(token, val, mnt_opts);
- if (unlikely(rc)) {
- kfree(val);
- goto free_opt;
}
+ rc = security_context_str_to_sid(&selinux_state, s, dst_sid, GFP_KERNEL);
+ if (rc)
+ pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
+ s, rc);
return rc;
-free_opt:
- if (*mnt_opts) {
- selinux_free_mnt_opts(*mnt_opts);
- *mnt_opts = NULL;
- }
- return rc;
+err:
+ pr_warn(SEL_MOUNT_FAIL_MSG);
+ return -EINVAL;
}
static int show_sid(struct seq_file *m, u32 sid)
@@ -1070,7 +1017,7 @@ static int show_sid(struct seq_file *m, u32 sid)
rc = security_sid_to_context(&selinux_state, sid,
&context, &len);
if (!rc) {
- bool has_comma = context && strchr(context, ',');
+ bool has_comma = strchr(context, ',');
seq_putc(m, '=');
if (has_comma)
@@ -2571,7 +2518,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
if (rc) {
clear_itimer();
- spin_lock_irq(&current->sighand->siglock);
+ spin_lock_irq(&unrcu_pointer(current->sighand)->siglock);
if (!fatal_signal_pending(current)) {
flush_sigqueue(&current->pending);
flush_sigqueue(&current->signal->shared_pending);
@@ -2579,13 +2526,13 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
sigemptyset(&current->blocked);
recalc_sigpending();
}
- spin_unlock_irq(&current->sighand->siglock);
+ spin_unlock_irq(&unrcu_pointer(current->sighand)->siglock);
}
/* Wake up the parent if it is waiting so that it can recheck
* wait permission to the new task SID. */
read_lock(&tasklist_lock);
- __wake_up_parent(current, current->real_parent);
+ __wake_up_parent(current, unrcu_pointer(current->real_parent));
read_unlock(&tasklist_lock);
}
@@ -2651,8 +2598,9 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
}
}
rc = selinux_add_opt(token, arg, mnt_opts);
+ kfree(arg);
+ arg = NULL;
if (unlikely(rc)) {
- kfree(arg);
goto free_opt;
}
} else {
@@ -2683,9 +2631,7 @@ free_opt:
static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
- struct superblock_security_struct *sbsec = sb->s_security;
- u32 sid;
- int rc;
+ struct superblock_security_struct *sbsec = selinux_superblock(sb);
/*
* Superblock not initialized (i.e. no options) - reject if any
@@ -2701,35 +2647,27 @@ static int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
if (!opts)
return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
- if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &sid);
- if (rc)
- return 1;
- if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ if (opts->fscontext_sid) {
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+ opts->fscontext_sid))
return 1;
}
- if (opts->context) {
- rc = parse_sid(sb, opts->context, &sid);
- if (rc)
- return 1;
- if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+ if (opts->context_sid) {
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+ opts->context_sid))
return 1;
}
- if (opts->rootcontext) {
+ if (opts->rootcontext_sid) {
struct inode_security_struct *root_isec;
root_isec = backing_inode_security(sb->s_root);
- rc = parse_sid(sb, opts->rootcontext, &sid);
- if (rc)
- return 1;
- if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+ opts->rootcontext_sid))
return 1;
}
- if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &sid);
- if (rc)
- return 1;
- if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+ if (opts->defcontext_sid) {
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+ opts->defcontext_sid))
return 1;
}
return 0;
@@ -2739,8 +2677,6 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
struct superblock_security_struct *sbsec = selinux_superblock(sb);
- u32 sid;
- int rc;
if (!(sbsec->flags & SE_SBINITIALIZED))
return 0;
@@ -2748,34 +2684,26 @@ static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
if (!opts)
return 0;
- if (opts->fscontext) {
- rc = parse_sid(sb, opts->fscontext, &sid);
- if (rc)
- return rc;
- if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
+ if (opts->fscontext_sid) {
+ if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
+ opts->fscontext_sid))
goto out_bad_option;
}
- if (opts->context) {
- rc = parse_sid(sb, opts->context, &sid);
- if (rc)
- return rc;
- if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
+ if (opts->context_sid) {
+ if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
+ opts->context_sid))
goto out_bad_option;
}
- if (opts->rootcontext) {
+ if (opts->rootcontext_sid) {
struct inode_security_struct *root_isec;
root_isec = backing_inode_security(sb->s_root);
- rc = parse_sid(sb, opts->rootcontext, &sid);
- if (rc)
- return rc;
- if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
+ if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
+ opts->rootcontext_sid))
goto out_bad_option;
}
- if (opts->defcontext) {
- rc = parse_sid(sb, opts->defcontext, &sid);
- if (rc)
- return rc;
- if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
+ if (opts->defcontext_sid) {
+ if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
+ opts->defcontext_sid))
goto out_bad_option;
}
return 0;
@@ -2842,38 +2770,12 @@ static int selinux_fs_context_dup(struct fs_context *fc,
struct fs_context *src_fc)
{
const struct selinux_mnt_opts *src = src_fc->security;
- struct selinux_mnt_opts *opts;
if (!src)
return 0;
- fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
- if (!fc->security)
- return -ENOMEM;
-
- opts = fc->security;
-
- if (src->fscontext) {
- opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
- if (!opts->fscontext)
- return -ENOMEM;
- }
- if (src->context) {
- opts->context = kstrdup(src->context, GFP_KERNEL);
- if (!opts->context)
- return -ENOMEM;
- }
- if (src->rootcontext) {
- opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
- if (!opts->rootcontext)
- return -ENOMEM;
- }
- if (src->defcontext) {
- opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
- if (!opts->defcontext)
- return -ENOMEM;
- }
- return 0;
+ fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
+ return fc->security ? 0 : -ENOMEM;
}
static const struct fs_parameter_spec selinux_fs_parameters[] = {
@@ -2889,18 +2791,13 @@ static int selinux_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
struct fs_parse_result result;
- int opt, rc;
+ int opt;
opt = fs_parse(fc, selinux_fs_parameters, param, &result);
if (opt < 0)
return opt;
- rc = selinux_add_opt(opt, param->string, &fc->security);
- if (!rc) {
- param->string = NULL;
- rc = 1;
- }
- return rc;
+ return selinux_add_opt(opt, param->string, &fc->security);
}
/* inode security operations */
@@ -3062,8 +2959,8 @@ static int selinux_inode_init_security_anon(struct inode *inode,
* allowed to actually create this type of anonymous inode.
*/
- ad.type = LSM_AUDIT_DATA_INODE;
- ad.u.inode = inode;
+ ad.type = LSM_AUDIT_DATA_ANONINODE;
+ ad.u.anonclass = name ? (const char *)name->name : "?";
return avc_has_perm(&selinux_state,
tsec->sid,
@@ -3381,8 +3278,6 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
isec->sid = newsid;
isec->initialized = LABEL_INITIALIZED;
spin_unlock(&isec->lock);
-
- return;
}
static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
@@ -3781,6 +3676,12 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
CAP_OPT_NONE, true);
break;
+ case FIOCLEX:
+ case FIONCLEX:
+ if (!selinux_policycap_ioctl_skip_cloexec())
+ error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
+ break;
+
/* default case assumes that the command will go
* to the file's ioctl() function.
*/
@@ -4205,9 +4106,9 @@ static int selinux_task_getsid(struct task_struct *p)
PROCESS__GETSESSION, NULL);
}
-static void selinux_task_getsecid_subj(struct task_struct *p, u32 *secid)
+static void selinux_current_getsecid_subj(u32 *secid)
{
- *secid = task_sid_subj(p);
+ *secid = current_sid();
}
static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
@@ -4321,6 +4222,14 @@ static void selinux_task_to_inode(struct task_struct *p,
spin_unlock(&isec->lock);
}
+static int selinux_userns_create(const struct cred *cred)
+{
+ u32 sid = current_sid();
+
+ return avc_has_perm(&selinux_state, sid, sid, SECCLASS_USER_NAMESPACE,
+ USER_NAMESPACE__CREATE, NULL);
+}
+
/* Returns error only if unable to parse addresses */
static int selinux_parse_skb_ipv4(struct sk_buff *skb,
struct common_audit_data *ad, u8 *proto)
@@ -5335,37 +5244,38 @@ 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).
+/*
+ * Determines peer_secid for the asoc and updates socket's peer label
+ * if it's the first association on the socket.
*/
-static int selinux_sctp_assoc_request(struct sctp_association *asoc,
- struct sk_buff *skb)
+static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+ struct sk_buff *skb)
{
- struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ struct sock *sk = asoc->base.sk;
+ u16 family = sk->sk_family;
+ struct sk_security_struct *sksec = 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;
+ int err;
- if (!selinux_policycap_extsockclass())
- return 0;
+ /* handle mapped IPv4 packets arriving via IPv6 sockets */
+ if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+ family = PF_INET;
- peerlbl_active = selinux_peerlbl_enabled();
+ if (selinux_peerlbl_enabled()) {
+ asoc->peer_secid = SECSID_NULL;
- 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, asoc->base.sk->sk_family,
- &peer_sid);
+ err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid);
if (err)
return err;
- if (peer_sid == SECSID_NULL)
- peer_sid = SECINITSID_UNLABELED;
+ if (asoc->peer_secid == SECSID_NULL)
+ asoc->peer_secid = SECINITSID_UNLABELED;
+ } else {
+ asoc->peer_secid = SECINITSID_UNLABELED;
}
if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
@@ -5376,8 +5286,8 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
* 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) {
+ sksec->peer_sid = asoc->peer_secid;
+ } else if (sksec->peer_sid != asoc->peer_secid) {
/* Other association peer SIDs are checked to enforce
* consistency among the peer SIDs.
*/
@@ -5385,11 +5295,32 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
ad.u.net = &net;
ad.u.net->sk = asoc->base.sk;
err = avc_has_perm(&selinux_state,
- sksec->peer_sid, peer_sid, sksec->sclass,
- SCTP_SOCKET__ASSOCIATION, &ad);
+ sksec->peer_sid, asoc->peer_secid,
+ sksec->sclass, SCTP_SOCKET__ASSOCIATION,
+ &ad);
if (err)
return err;
}
+ return 0;
+}
+
+/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This
+ * happens on an incoming connect(2), sctp_connectx(3) or
+ * sctp_sendmsg(3) (with no association already present).
+ */
+static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+ struct sk_buff *skb)
+{
+ struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+ u32 conn_sid;
+ int err;
+
+ if (!selinux_policycap_extsockclass())
+ return 0;
+
+ err = selinux_sctp_process_new_assoc(asoc, skb);
+ if (err)
+ return err;
/* Compute the MLS component for the connection and store
* the information in asoc. This will be used by SCTP TCP type
@@ -5397,17 +5328,36 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
* 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);
+ err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid);
if (err)
return err;
asoc->secid = conn_sid;
- asoc->peer_secid = peer_sid;
/* Set any NetLabel labels including CIPSO/CALIPSO options. */
return selinux_netlbl_sctp_assoc_request(asoc, skb);
}
+/* Called when SCTP receives a COOKIE ACK chunk as the final
+ * response to an association request (initited by us).
+ */
+static int selinux_sctp_assoc_established(struct sctp_association *asoc,
+ struct sk_buff *skb)
+{
+ struct sk_security_struct *sksec = asoc->base.sk->sk_security;
+
+ if (!selinux_policycap_extsockclass())
+ return 0;
+
+ /* Inherit secid from the parent socket - this will be picked up
+ * by selinux_sctp_sk_clone() if the association gets peeled off
+ * into a new socket.
+ */
+ asoc->secid = sksec->sid;
+
+ return selinux_sctp_process_new_assoc(asoc, skb);
+}
+
/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
* based on their @optname.
*/
@@ -5780,7 +5730,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
struct sk_security_struct *sksec;
struct common_audit_data ad;
struct lsm_network_audit net = {0,};
- u8 proto;
+ u8 proto = 0;
sk = skb_to_full_sk(skb);
if (sk == NULL)
@@ -6045,7 +5995,6 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
- int rc;
isec = selinux_ipc(msq);
ipc_init_security(isec, SECCLASS_MSGQ);
@@ -6053,10 +6002,9 @@ 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(&selinux_state,
- sid, isec->sid, SECCLASS_MSGQ,
- MSGQ__CREATE, &ad);
- return rc;
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_MSGQ,
+ MSGQ__CREATE, &ad);
}
static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -6184,7 +6132,6 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
- int rc;
isec = selinux_ipc(shp);
ipc_init_security(isec, SECCLASS_SHM);
@@ -6192,10 +6139,9 @@ 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(&selinux_state,
- sid, isec->sid, SECCLASS_SHM,
- SHM__CREATE, &ad);
- return rc;
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SHM,
+ SHM__CREATE, &ad);
}
static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -6269,7 +6215,6 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
struct ipc_security_struct *isec;
struct common_audit_data ad;
u32 sid = current_sid();
- int rc;
isec = selinux_ipc(sma);
ipc_init_security(isec, SECCLASS_SEM);
@@ -6277,10 +6222,9 @@ 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(&selinux_state,
- sid, isec->sid, SECCLASS_SEM,
- SEM__CREATE, &ad);
- return rc;
+ return avc_has_perm(&selinux_state,
+ sid, isec->sid, SECCLASS_SEM,
+ SEM__CREATE, &ad);
}
static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -6386,7 +6330,7 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
}
static int selinux_getprocattr(struct task_struct *p,
- char *name, char **value)
+ const char *name, char **value)
{
const struct task_security_struct *__tsec;
u32 sid;
@@ -6540,7 +6484,6 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
goto abort_change;
/* Only allow single threaded processes to change context */
- error = -EPERM;
if (!current_is_single_threaded()) {
error = security_bounded_transition(&selinux_state,
tsec->sid, sid);
@@ -6849,7 +6792,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
}
/* This function will check the file pass through unix socket or binder to see
- * if it is a bpf related object. And apply correspinding checks on the bpf
+ * if it is a bpf related object. And apply corresponding checks on the bpf
* object based on the type. The bpf maps and programs, not like other files and
* socket, are using a shared anonymous inode inside the kernel as their inode.
* So checking that inode cannot identify if the process have privilege to
@@ -7047,6 +6990,28 @@ static int selinux_uring_sqpoll(void)
return avc_has_perm(&selinux_state, sid, sid,
SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
}
+
+/**
+ * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed
+ * @ioucmd: the io_uring command structure
+ *
+ * Check to see if the current domain is allowed to execute an
+ * IORING_OP_URING_CMD against the device/file specified in @ioucmd.
+ *
+ */
+static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
+{
+ struct file *file = ioucmd->file;
+ struct inode *inode = file_inode(file);
+ struct inode_security_struct *isec = selinux_inode(inode);
+ struct common_audit_data ad;
+
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = file;
+
+ return avc_has_perm(&selinux_state, current_sid(), isec->sid,
+ SECCLASS_IO_URING, IO_URING__CMD, &ad);
+}
#endif /* CONFIG_IO_URING */
/*
@@ -7159,7 +7124,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
- LSM_HOOK_INIT(task_getsecid_subj, selinux_task_getsecid_subj),
+ LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj),
LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj),
LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
@@ -7171,6 +7136,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
LSM_HOOK_INIT(task_kill, selinux_task_kill),
LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
+ LSM_HOOK_INIT(userns_create, selinux_userns_create),
LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
@@ -7228,6 +7194,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
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(sctp_assoc_established, selinux_sctp_assoc_established),
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),
@@ -7290,6 +7257,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
#ifdef CONFIG_IO_URING
LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
+ LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd),
#endif
/*
@@ -7298,7 +7266,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
- LSM_HOOK_INIT(sb_add_mnt_opt, selinux_add_mnt_opt),
#ifdef CONFIG_SECURITY_NETWORK_XFRM
LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
#endif
@@ -7347,6 +7314,8 @@ static __init int selinux_init(void)
memset(&selinux_state, 0, sizeof(selinux_state));
enforcing_set(&selinux_state, selinux_enforcing_boot);
+ if (CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE)
+ pr_err("SELinux: CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE is non-zero. This is deprecated and will be rejected in a future kernel release.\n");
checkreqprot_set(&selinux_state, selinux_checkreqprot_boot);
selinux_avc_init(&selinux_state.avc);
mutex_init(&selinux_state.status_lock);
diff --git a/security/selinux/ibpkey.c b/security/selinux/ibpkey.c
index 20b3b2243820..5839ca7bb9c7 100644
--- a/security/selinux/ibpkey.c
+++ b/security/selinux/ibpkey.c
@@ -104,7 +104,7 @@ static void sel_ib_pkey_insert(struct sel_ib_pkey *pkey)
tail = list_entry(
rcu_dereference_protected(
- sel_ib_pkey_hash[idx].list.prev,
+ list_tail_rcu(&sel_ib_pkey_hash[idx].list),
lockdep_is_held(&sel_ib_pkey_lock)),
struct sel_ib_pkey, list);
list_del_rcu(&tail->list);
diff --git a/security/selinux/ima.c b/security/selinux/ima.c
index 727c4e43219d..a915b89d55b0 100644
--- a/security/selinux/ima.c
+++ b/security/selinux/ima.c
@@ -29,7 +29,7 @@ static char *selinux_ima_collect_state(struct selinux_state *state)
buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
len = strlen(on);
- for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++)
+ for (i = 0; i < __POLICYDB_CAP_MAX; i++)
buf_len += strlen(selinux_policycap_names[i]) + len;
buf = kzalloc(buf_len, GFP_KERNEL);
@@ -54,7 +54,7 @@ static char *selinux_ima_collect_state(struct selinux_state *state)
rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len);
WARN_ON(rc >= buf_len);
- for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) {
+ for (i = 0; i < __POLICYDB_CAP_MAX; i++) {
rc = strlcat(buf, selinux_policycap_names[i], buf_len);
WARN_ON(rc >= buf_len);
@@ -77,7 +77,7 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
size_t policy_len;
int rc = 0;
- WARN_ON(!mutex_is_locked(&state->policy_mutex));
+ lockdep_assert_held(&state->policy_mutex);
state_str = selinux_ima_collect_state(state);
if (!state_str) {
@@ -117,7 +117,7 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
*/
void selinux_ima_measure_state(struct selinux_state *state)
{
- WARN_ON(mutex_is_locked(&state->policy_mutex));
+ lockdep_assert_not_held(&state->policy_mutex);
mutex_lock(&state->policy_mutex);
selinux_ima_measure_state_locked(state);
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 073a3d34a0d2..406bceb90c6c 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -12,10 +12,13 @@
#ifndef _SELINUX_AUDIT_H
#define _SELINUX_AUDIT_H
+#include <linux/audit.h>
+#include <linux/types.h>
+
/**
* selinux_audit_rule_init - alloc/init an selinux audit rule structure.
* @field: the field this rule refers to
- * @op: the operater the rule uses
+ * @op: the operator the rule uses
* @rulestr: the text "target" of the rule
* @rule: pointer to the new rule structure returned via this
*
@@ -51,7 +54,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
* @rule: rule to be checked
* Returns 1 if there are selinux fields specified in the rule, 0 otherwise.
*/
-int selinux_audit_rule_known(struct audit_krule *krule);
+int selinux_audit_rule_known(struct audit_krule *rule);
#endif /* _SELINUX_AUDIT_H */
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 00f78be48283..5525b94fd266 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -53,7 +53,7 @@ struct selinux_audit_data {
u32 denied;
int result;
struct selinux_state *state;
-};
+} __randomize_layout;
/*
* AVC operations
@@ -104,6 +104,7 @@ int slow_avc_audit(struct selinux_state *state,
/**
* avc_audit - Audit the granting or denial of permissions.
+ * @state: SELinux state
* @ssid: source security identifier
* @tsid: target security identifier
* @tclass: target security class
diff --git a/security/selinux/include/avc_ss.h b/security/selinux/include/avc_ss.h
index 88c384c5c09e..42912c917fd4 100644
--- a/security/selinux/include/avc_ss.h
+++ b/security/selinux/include/avc_ss.h
@@ -7,7 +7,7 @@
#ifndef _SELINUX_AVC_SS_H_
#define _SELINUX_AVC_SS_H_
-#include "flask.h"
+#include <linux/types.h>
struct selinux_avc;
int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
@@ -18,7 +18,7 @@ struct security_class_mapping {
const char *perms[sizeof(u32) * 8 + 1];
};
-extern struct security_class_mapping secclass_map[];
+extern const struct security_class_mapping secclass_map[];
#endif /* _SELINUX_AVC_SS_H_ */
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index 35aac62a662e..a3c380775d41 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -38,7 +38,7 @@
* Note: The name for any socket class should be suffixed by "socket",
* and doesn't contain more than one substr of "socket".
*/
-struct security_class_mapping secclass_map[] = {
+const struct security_class_mapping secclass_map[] = {
{ "security",
{ "compute_av", "compute_create", "compute_member",
"check_context", "load_policy", "compute_relabel",
@@ -253,7 +253,9 @@ struct security_class_mapping secclass_map[] = {
{ "anon_inode",
{ COMMON_FILE_PERMS, NULL } },
{ "io_uring",
- { "override_creds", "sqpoll", NULL } },
+ { "override_creds", "sqpoll", "cmd", NULL } },
+ { "user_namespace",
+ { "create", NULL } },
{ NULL }
};
diff --git a/security/selinux/include/ibpkey.h b/security/selinux/include/ibpkey.h
index e6ac1d23320b..c992f83b0aae 100644
--- a/security/selinux/include/ibpkey.h
+++ b/security/selinux/include/ibpkey.h
@@ -14,6 +14,8 @@
#ifndef _SELINUX_IB_PKEY_H
#define _SELINUX_IB_PKEY_H
+#include <linux/types.h>
+
#ifdef CONFIG_SECURITY_INFINIBAND
void sel_ib_pkey_flush(void);
int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey, u32 *sid);
diff --git a/security/selinux/include/initial_sid_to_string.h b/security/selinux/include/initial_sid_to_string.h
index 5d332aeb8b6c..60820517aa43 100644
--- a/security/selinux/include/initial_sid_to_string.h
+++ b/security/selinux/include/initial_sid_to_string.h
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
-static const char *initial_sid_to_string[] =
-{
+static const char *const initial_sid_to_string[] = {
NULL,
"kernel",
"security",
diff --git a/security/selinux/include/netnode.h b/security/selinux/include/netnode.h
index e3f784a85840..9b8b655a8cd3 100644
--- a/security/selinux/include/netnode.h
+++ b/security/selinux/include/netnode.h
@@ -17,6 +17,8 @@
#ifndef _SELINUX_NETNODE_H
#define _SELINUX_NETNODE_H
+#include <linux/types.h>
+
void sel_netnode_flush(void);
int sel_netnode_sid(void *addr, u16 family, u32 *sid);
diff --git a/security/selinux/include/netport.h b/security/selinux/include/netport.h
index 31bc16e29cd1..9096a8289948 100644
--- a/security/selinux/include/netport.h
+++ b/security/selinux/include/netport.h
@@ -16,6 +16,8 @@
#ifndef _SELINUX_NETPORT_H
#define _SELINUX_NETPORT_H
+#include <linux/types.h>
+
void sel_netport_flush(void);
int sel_netport_sid(u8 protocol, u16 pnum, u32 *sid);
diff --git a/security/selinux/include/policycap.h b/security/selinux/include/policycap.h
index 2ec038efbb03..f35d3458e71d 100644
--- a/security/selinux/include/policycap.h
+++ b/security/selinux/include/policycap.h
@@ -4,17 +4,18 @@
/* Policy capabilities */
enum {
- POLICYDB_CAPABILITY_NETPEER,
- POLICYDB_CAPABILITY_OPENPERM,
- POLICYDB_CAPABILITY_EXTSOCKCLASS,
- POLICYDB_CAPABILITY_ALWAYSNETWORK,
- POLICYDB_CAPABILITY_CGROUPSECLABEL,
- POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
- POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
- __POLICYDB_CAPABILITY_MAX
+ POLICYDB_CAP_NETPEER,
+ POLICYDB_CAP_OPENPERM,
+ POLICYDB_CAP_EXTSOCKCLASS,
+ POLICYDB_CAP_ALWAYSNETWORK,
+ POLICYDB_CAP_CGROUPSECLABEL,
+ POLICYDB_CAP_NNP_NOSUID_TRANSITION,
+ POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS,
+ POLICYDB_CAP_IOCTL_SKIP_CLOEXEC,
+ __POLICYDB_CAP_MAX
};
-#define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
+#define POLICYDB_CAP_MAX (__POLICYDB_CAP_MAX - 1)
-extern const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
+extern const char *const selinux_policycap_names[__POLICYDB_CAP_MAX];
#endif /* _SELINUX_POLICYCAP_H_ */
diff --git a/security/selinux/include/policycap_names.h b/security/selinux/include/policycap_names.h
index b89289f092c9..2a87fc3702b8 100644
--- a/security/selinux/include/policycap_names.h
+++ b/security/selinux/include/policycap_names.h
@@ -5,14 +5,15 @@
#include "policycap.h"
/* Policy capability names */
-const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
+const char *const selinux_policycap_names[__POLICYDB_CAP_MAX] = {
"network_peer_controls",
"open_perms",
"extended_socket_class",
"always_check_network",
"cgroup_seclabel",
"nnp_nosuid_transition",
- "genfs_seclabel_symlinks"
+ "genfs_seclabel_symlinks",
+ "ioctl_skip_cloexec"
};
#endif /* _SELINUX_POLICYCAP_NAMES_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index ac0ece01305a..393aff41d3ef 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -16,6 +16,8 @@
#include <linux/rcupdate.h>
#include <linux/refcount.h>
#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/printk.h>
#include "flask.h"
#include "policycap.h"
@@ -96,7 +98,7 @@ struct selinux_state {
#endif
bool checkreqprot;
bool initialized;
- bool policycap[__POLICYDB_CAPABILITY_MAX];
+ bool policycap[__POLICYDB_CAP_MAX];
struct page *status_page;
struct mutex status_lock;
@@ -150,6 +152,8 @@ static inline bool checkreqprot_get(const struct selinux_state *state)
static inline void checkreqprot_set(struct selinux_state *state, bool value)
{
+ if (value)
+ pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-checkreqprot\n");
WRITE_ONCE(state->checkreqprot, value);
}
@@ -174,49 +178,56 @@ static inline bool selinux_policycap_netpeer(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_NETPEER]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_NETPEER]);
}
static inline bool selinux_policycap_openperm(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_OPENPERM]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_OPENPERM]);
}
static inline bool selinux_policycap_extsockclass(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_EXTSOCKCLASS]);
}
static inline bool selinux_policycap_alwaysnetwork(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_ALWAYSNETWORK]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_ALWAYSNETWORK]);
}
static inline bool selinux_policycap_cgroupseclabel(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_CGROUPSECLABEL]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_CGROUPSECLABEL]);
}
static inline bool selinux_policycap_nnp_nosuid_transition(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_NNP_NOSUID_TRANSITION]);
}
static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
{
struct selinux_state *state = &selinux_state;
- return READ_ONCE(state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS]);
+ return READ_ONCE(state->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
+}
+
+static inline bool selinux_policycap_ioctl_skip_cloexec(void)
+{
+ struct selinux_state *state = &selinux_state;
+
+ return READ_ONCE(state->policycap[POLICYDB_CAP_IOCTL_SKIP_CLOEXEC]);
}
struct selinux_policy_convert_data;
@@ -254,8 +265,8 @@ struct av_decision {
#define XPERMS_AUDITALLOW 2
#define XPERMS_DONTAUDIT 4
-#define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f))
-#define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f)))
+#define security_xperm_set(perms, x) ((perms)[(x) >> 5] |= 1 << ((x) & 0x1f))
+#define security_xperm_test(perms, x) (1 & ((perms)[(x) >> 5] >> ((x) & 0x1f)))
struct extended_perms_data {
u32 p[8];
};
@@ -386,11 +397,11 @@ int security_get_allow_unknown(struct selinux_state *state);
int security_fs_use(struct selinux_state *state, struct super_block *sb);
int security_genfs_sid(struct selinux_state *state,
- const char *fstype, char *name, u16 sclass,
+ const char *fstype, const char *path, u16 sclass,
u32 *sid);
int selinux_policy_genfs_sid(struct selinux_policy *policy,
- const char *fstype, char *name, u16 sclass,
+ const char *fstype, const char *path, u16 sclass,
u32 *sid);
#ifdef CONFIG_NETLABEL
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 74159400eeee..c75839860200 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -8,7 +8,9 @@
#ifndef _SELINUX_XFRM_H_
#define _SELINUX_XFRM_H_
+#include <linux/lsm_audit.h>
#include <net/flow.h>
+#include <net/xfrm.h>
int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *uctx,
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 4a7d2ab5b960..0ac7df9a9367 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -107,7 +107,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
switch (family) {
case PF_INET:
- idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
+ idx = sel_netnode_hashfn_ipv4(*(const __be32 *)addr);
break;
case PF_INET6:
idx = sel_netnode_hashfn_ipv6(addr);
@@ -121,7 +121,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
if (node->nsec.family == family)
switch (family) {
case PF_INET:
- if (node->nsec.addr.ipv4 == *(__be32 *)addr)
+ if (node->nsec.addr.ipv4 == *(const __be32 *)addr)
return node;
break;
case PF_INET6:
@@ -164,8 +164,9 @@ static void sel_netnode_insert(struct sel_netnode *node)
if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
struct sel_netnode *tail;
tail = list_entry(
- rcu_dereference_protected(sel_netnode_hash[idx].list.prev,
- lockdep_is_held(&sel_netnode_lock)),
+ rcu_dereference_protected(
+ list_tail_rcu(&sel_netnode_hash[idx].list),
+ lockdep_is_held(&sel_netnode_lock)),
struct sel_netnode, list);
list_del_rcu(&tail->list);
kfree_rcu(tail, rcu);
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 9ba09d11c0f5..8eec6347cf01 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -113,7 +113,7 @@ static void sel_netport_insert(struct sel_netport *port)
struct sel_netport *tail;
tail = list_entry(
rcu_dereference_protected(
- sel_netport_hash[idx].list.prev,
+ list_tail_rcu(&sel_netport_hash[idx].list),
lockdep_is_held(&sel_netport_lock)),
struct sel_netport, list);
list_del_rcu(&tail->list);
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 94ea2a8b2bb7..2ee7b4ed43ef 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -25,8 +25,7 @@ struct nlmsg_perm {
u32 perm;
};
-static const struct nlmsg_perm nlmsg_route_perms[] =
-{
+static const struct nlmsg_perm nlmsg_route_perms[] = {
{ RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ },
@@ -76,6 +75,7 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_GETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETSTATS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_NEWCACHEREPORT, NETLINK_ROUTE_SOCKET__NLMSG_READ },
{ RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
@@ -91,18 +91,19 @@ static const struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_NEWNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETNEXTHOPBUCKET, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTUNNEL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
-static const struct nlmsg_perm nlmsg_tcpdiag_perms[] =
-{
+static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = {
{ TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
{ DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
{ SOCK_DIAG_BY_FAMILY, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
{ SOCK_DESTROY, NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE },
};
-static const struct nlmsg_perm nlmsg_xfrm_perms[] =
-{
+static const struct nlmsg_perm nlmsg_xfrm_perms[] = {
{ XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ },
@@ -130,8 +131,7 @@ static const struct nlmsg_perm nlmsg_xfrm_perms[] =
{ XFRM_MSG_GETDEFAULT, NETLINK_XFRM_SOCKET__NLMSG_READ },
};
-static const struct nlmsg_perm nlmsg_audit_perms[] =
-{
+static const struct nlmsg_perm nlmsg_audit_perms[] = {
{ AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
{ AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
@@ -176,7 +176,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
* structures at the top of this file with the new mappings
* before updating the BUILD_BUG_ON() macro!
*/
- BUILD_BUG_ON(RTM_MAX != (RTM_NEWNEXTHOPBUCKET + 3));
+ BUILD_BUG_ON(RTM_MAX != (RTM_NEWTUNNEL + 3));
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
sizeof(nlmsg_route_perms));
break;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index e4cd7cb856f3..a00d19139436 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -71,7 +71,7 @@ struct selinux_fs_info {
struct dentry *bool_dir;
unsigned int bool_num;
char **bool_pending_names;
- unsigned int *bool_pending_values;
+ int *bool_pending_values;
struct dentry *class_dir;
unsigned long last_class_ino;
bool policy_opened;
@@ -293,6 +293,8 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
* kernel releases until eventually it is removed
*/
pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n");
+ pr_err("SELinux: https://github.com/SELinuxProject/selinux-kernel/wiki/DEPRECATE-runtime-disable\n");
+ ssleep(5);
if (count >= PAGE_SIZE)
return -ENOMEM;
@@ -354,7 +356,7 @@ static const struct file_operations sel_policyvers_ops = {
/* declaration for sel_write_load */
static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir,
unsigned int *bool_num, char ***bool_pending_names,
- unsigned int **bool_pending_values);
+ int **bool_pending_values);
static int sel_make_classes(struct selinux_policy *newpolicy,
struct dentry *class_dir,
unsigned long *last_class_ino);
@@ -525,7 +527,7 @@ static const struct file_operations sel_policy_ops = {
};
static void sel_remove_old_bool_data(unsigned int bool_num, char **bool_names,
- unsigned int *bool_values)
+ int *bool_values)
{
u32 i;
@@ -543,7 +545,7 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
struct dentry *tmp_parent, *tmp_bool_dir, *tmp_class_dir, *old_dentry;
unsigned int tmp_bool_num, old_bool_num;
char **tmp_bool_names, **old_bool_names;
- unsigned int *tmp_bool_values, *old_bool_values;
+ int *tmp_bool_values, *old_bool_values;
unsigned long tmp_ino = fsi->last_ino; /* Don't increment last_ino in this function */
tmp_parent = sel_make_disconnected_dir(fsi->sb, &tmp_ino);
@@ -755,11 +757,13 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
char comm[sizeof(current->comm)];
memcpy(comm, current->comm, sizeof(comm));
- pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n",
- comm, current->pid);
+ pr_err("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n",
+ comm, current->pid);
}
checkreqprot_set(fsi->state, (new_value ? 1 : 0));
+ if (new_value)
+ ssleep(5);
length = count;
selinux_ima_measure_state(fsi->state);
@@ -1419,7 +1423,7 @@ static void sel_remove_entries(struct dentry *de)
static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir,
unsigned int *bool_num, char ***bool_pending_names,
- unsigned int **bool_pending_values)
+ int **bool_pending_values)
{
int ret;
ssize_t len;
@@ -1913,7 +1917,6 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
struct selinux_fs_info *fsi = sb->s_fs_info;
struct dentry *dentry = NULL;
struct inode *inode = NULL;
- int rc;
dentry = d_alloc_name(dir, "index");
if (!dentry)
@@ -1933,9 +1936,7 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- rc = sel_make_perm_files(newpolicy, classname, index, dentry);
-
- return rc;
+ return sel_make_perm_files(newpolicy, classname, index, dentry);
}
static int sel_make_classes(struct selinux_policy *newpolicy,
@@ -1983,7 +1984,7 @@ static int sel_make_policycap(struct selinux_fs_info *fsi)
struct dentry *dentry = NULL;
struct inode *inode = NULL;
- for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
+ for (iter = 0; iter <= POLICYDB_CAP_MAX; iter++) {
if (iter < ARRAY_SIZE(selinux_policycap_names))
dentry = d_alloc_name(fsi->policycap_dir,
selinux_policycap_names[iter]);
@@ -2127,6 +2128,8 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
}
ret = sel_make_avc_files(dentry);
+ if (ret)
+ goto err;
dentry = sel_make_dir(sb->s_root, "ss", &fsi->last_ino);
if (IS_ERR(dentry)) {
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index c97695ae508f..8480ec6c6e75 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -40,15 +40,15 @@ static inline int avtab_hash(const struct avtab_key *keyp, u32 mask)
u32 hash = 0;
-#define mix(input) { \
- u32 v = input; \
- v *= c1; \
- v = (v << r1) | (v >> (32 - r1)); \
- v *= c2; \
- hash ^= v; \
- hash = (hash << r2) | (hash >> (32 - r2)); \
- hash = hash * m + n; \
-}
+#define mix(input) do { \
+ u32 v = input; \
+ v *= c1; \
+ v = (v << r1) | (v >> (32 - r1)); \
+ v *= c2; \
+ hash ^= v; \
+ hash = (hash << r2) | (hash >> (32 - r2)); \
+ hash = hash * m + n; \
+ } while (0)
mix(keyp->target_class);
mix(keyp->target_type);
@@ -67,7 +67,7 @@ static inline int avtab_hash(const struct avtab_key *keyp, u32 mask)
static struct avtab_node*
avtab_insert_node(struct avtab *h, int hvalue,
- struct avtab_node *prev, struct avtab_node *cur,
+ struct avtab_node *prev,
const struct avtab_key *key, const struct avtab_datum *datum)
{
struct avtab_node *newnode;
@@ -137,7 +137,7 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key,
break;
}
- newnode = avtab_insert_node(h, hvalue, prev, cur, key, datum);
+ newnode = avtab_insert_node(h, hvalue, prev, key, datum);
if (!newnode)
return -ENOMEM;
@@ -177,7 +177,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
key->target_class < cur->key.target_class)
break;
}
- return avtab_insert_node(h, hvalue, prev, cur, key, datum);
+ return avtab_insert_node(h, hvalue, prev, key, datum);
}
struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *key)
@@ -385,7 +385,7 @@ void avtab_hash_eval(struct avtab *h, char *tag)
chain2_len_sum);
}
-static uint16_t spec_order[] = {
+static const uint16_t spec_order[] = {
AVTAB_ALLOWED,
AVTAB_AUDITDENY,
AVTAB_AUDITALLOW,
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 2ec6e5cd25d9..e11219fdf9f7 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -152,6 +152,8 @@ static void cond_list_destroy(struct policydb *p)
for (i = 0; i < p->cond_list_len; i++)
cond_node_destroy(&p->cond_list[i]);
kfree(p->cond_list);
+ p->cond_list = NULL;
+ p->cond_list_len = 0;
}
void cond_policydb_destroy(struct policydb *p)
@@ -441,7 +443,6 @@ int cond_read_list(struct policydb *p, void *fp)
return 0;
err:
cond_list_destroy(p);
- p->cond_list = NULL;
return rc;
}
@@ -566,8 +567,6 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
if (node->key.specified & AVTAB_ENABLED)
services_compute_xperms_decision(xpermd, node);
}
- return;
-
}
/* Determine whether additional permissions are granted by the conditional
* av table, and if so, add them to the result
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h
index 62990aa1ec9e..eda32c3d4c0a 100644
--- a/security/selinux/ss/context.h
+++ b/security/selinux/ss/context.h
@@ -38,7 +38,7 @@ static inline void mls_context_init(struct context *c)
memset(&c->range, 0, sizeof(c->range));
}
-static inline int mls_context_cpy(struct context *dst, struct context *src)
+static inline int mls_context_cpy(struct context *dst, const struct context *src)
{
int rc;
@@ -58,7 +58,7 @@ out:
/*
* Sets both levels in the MLS range of 'dst' to the low level of 'src'.
*/
-static inline int mls_context_cpy_low(struct context *dst, struct context *src)
+static inline int mls_context_cpy_low(struct context *dst, const struct context *src)
{
int rc;
@@ -78,7 +78,7 @@ out:
/*
* Sets both levels in the MLS range of 'dst' to the high level of 'src'.
*/
-static inline int mls_context_cpy_high(struct context *dst, struct context *src)
+static inline int mls_context_cpy_high(struct context *dst, const struct context *src)
{
int rc;
@@ -97,9 +97,10 @@ out:
static inline int mls_context_glblub(struct context *dst,
- struct context *c1, struct context *c2)
+ const struct context *c1, const struct context *c2)
{
- struct mls_range *dr = &dst->range, *r1 = &c1->range, *r2 = &c2->range;
+ struct mls_range *dr = &dst->range;
+ const struct mls_range *r1 = &c1->range, *r2 = &c2->range;
int rc = 0;
if (r1->level[1].sens < r2->level[0].sens ||
@@ -127,7 +128,7 @@ out:
return rc;
}
-static inline int mls_context_cmp(struct context *c1, struct context *c2)
+static inline int mls_context_cmp(const struct context *c1, const struct context *c2)
{
return ((c1->range.level[0].sens == c2->range.level[0].sens) &&
ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) &&
@@ -147,7 +148,7 @@ static inline void context_init(struct context *c)
memset(c, 0, sizeof(*c));
}
-static inline int context_cpy(struct context *dst, struct context *src)
+static inline int context_cpy(struct context *dst, const struct context *src)
{
int rc;
@@ -180,7 +181,7 @@ static inline void context_destroy(struct context *c)
mls_context_destroy(c);
}
-static inline int context_cmp(struct context *c1, struct context *c2)
+static inline int context_cmp(const struct context *c1, const struct context *c2)
{
if (c1->len && c2->len)
return (c1->len == c2->len && !strcmp(c1->str, c2->str));
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index 61fcbb8d0f88..d31b87be9a1e 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -28,9 +28,9 @@
static struct kmem_cache *ebitmap_node_cachep __ro_after_init;
-int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
+int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2)
{
- struct ebitmap_node *n1, *n2;
+ const struct ebitmap_node *n1, *n2;
if (e1->highbit != e2->highbit)
return 0;
@@ -50,9 +50,10 @@ int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
return 1;
}
-int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
+int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src)
{
- struct ebitmap_node *n, *new, *prev;
+ struct ebitmap_node *new, *prev;
+ const struct ebitmap_node *n;
ebitmap_init(dst);
n = src->node;
@@ -78,7 +79,7 @@ int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src)
return 0;
}
-int ebitmap_and(struct ebitmap *dst, struct ebitmap *e1, struct ebitmap *e2)
+int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2)
{
struct ebitmap_node *n;
int bit, rc;
@@ -217,9 +218,9 @@ netlbl_import_failure:
* if last_e2bit is non-zero, the highest set bit in e2 cannot exceed
* last_e2bit.
*/
-int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)
+int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit)
{
- struct ebitmap_node *n1, *n2;
+ const struct ebitmap_node *n1, *n2;
int i;
if (e1->highbit < e2->highbit)
@@ -258,9 +259,9 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)
return 1;
}
-int ebitmap_get_bit(struct ebitmap *e, unsigned long bit)
+int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit)
{
- struct ebitmap_node *n;
+ const struct ebitmap_node *n;
if (e->highbit < bit)
return 0;
@@ -359,7 +360,6 @@ void ebitmap_destroy(struct ebitmap *e)
e->highbit = 0;
e->node = NULL;
- return;
}
int ebitmap_read(struct ebitmap *e, void *fp)
@@ -468,7 +468,7 @@ bad:
goto out;
}
-int ebitmap_write(struct ebitmap *e, void *fp)
+int ebitmap_write(const struct ebitmap *e, void *fp)
{
struct ebitmap_node *n;
u32 count;
diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h
index 9eb2d0af2805..e5b57dc3fc53 100644
--- a/security/selinux/ss/ebitmap.h
+++ b/security/selinux/ss/ebitmap.h
@@ -44,7 +44,7 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit)
-static inline unsigned int ebitmap_start_positive(struct ebitmap *e,
+static inline unsigned int ebitmap_start_positive(const struct ebitmap *e,
struct ebitmap_node **n)
{
unsigned int ofs;
@@ -62,7 +62,7 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e));
}
-static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
+static inline unsigned int ebitmap_next_positive(const struct ebitmap *e,
struct ebitmap_node **n,
unsigned int bit)
{
@@ -85,7 +85,7 @@ static inline unsigned int ebitmap_next_positive(struct ebitmap *e,
#define EBITMAP_NODE_OFFSET(node, bit) \
(((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
-static inline int ebitmap_node_get_bit(struct ebitmap_node *n,
+static inline int ebitmap_node_get_bit(const struct ebitmap_node *n,
unsigned int bit)
{
unsigned int index = EBITMAP_NODE_INDEX(n, bit);
@@ -118,19 +118,19 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,
}
#define ebitmap_for_each_positive_bit(e, n, bit) \
- for (bit = ebitmap_start_positive(e, &n); \
- bit < ebitmap_length(e); \
- bit = ebitmap_next_positive(e, &n, bit)) \
-
-int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
-int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
-int ebitmap_and(struct ebitmap *dst, 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);
+ for ((bit) = ebitmap_start_positive(e, &(n)); \
+ (bit) < ebitmap_length(e); \
+ (bit) = ebitmap_next_positive(e, &(n), bit)) \
+
+int ebitmap_cmp(const struct ebitmap *e1, const struct ebitmap *e2);
+int ebitmap_cpy(struct ebitmap *dst, const struct ebitmap *src);
+int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1, const struct ebitmap *e2);
+int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, u32 last_e2bit);
+int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit);
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
void ebitmap_destroy(struct ebitmap *e);
int ebitmap_read(struct ebitmap *e, void *fp);
-int ebitmap_write(struct ebitmap *e, void *fp);
+int ebitmap_write(const struct ebitmap *e, void *fp);
u32 ebitmap_hash(const struct ebitmap *e, u32 hash);
#ifdef CONFIG_NETLABEL
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index 0ae4e4e57a40..3fb8f9026e9b 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -179,7 +179,8 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
kmem_cache_free(hashtab_node_cachep, cur);
}
}
- kmem_cache_free(hashtab_node_cachep, new);
+ kfree(new->htable);
+ memset(new, 0, sizeof(*new));
return -ENOMEM;
}
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 3f5fd124342c..99571b19d4a9 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -156,7 +156,6 @@ void mls_sid_to_context(struct policydb *p,
}
*scontext = scontextp;
- return;
}
int mls_level_isvalid(struct policydb *p, struct mls_level *l)
diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h
index 068e0d7809db..7d48d5e52233 100644
--- a/security/selinux/ss/mls_types.h
+++ b/security/selinux/ss/mls_types.h
@@ -27,13 +27,13 @@ struct mls_range {
struct mls_level level[2]; /* low == level[0], high == level[1] */
};
-static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)
+static inline int mls_level_eq(const struct mls_level *l1, const struct mls_level *l2)
{
return ((l1->sens == l2->sens) &&
ebitmap_cmp(&l1->cat, &l2->cat));
}
-static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)
+static inline int mls_level_dom(const struct mls_level *l1, const struct mls_level *l2)
{
return ((l1->sens >= l2->sens) &&
ebitmap_contains(&l1->cat, &l2->cat, 0));
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 0ae1b718194a..adcfb63b3550 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -41,8 +41,6 @@
#include "mls.h"
#include "services.h"
-#define _DEBUG_HASHES
-
#ifdef DEBUG_HASHES
static const char *symtab_name[SYM_NUM] = {
"common prefixes",
@@ -63,7 +61,7 @@ struct policydb_compat_info {
};
/* These need to be updated if SYM_NUM or OCON_NUM changes */
-static struct policydb_compat_info policydb_compat[] = {
+static const struct policydb_compat_info policydb_compat[] = {
{
.version = POLICYDB_VERSION_BASE,
.sym_num = SYM_NUM - 3,
@@ -161,18 +159,16 @@ static struct policydb_compat_info policydb_compat[] = {
},
};
-static struct policydb_compat_info *policydb_lookup_compat(int version)
+static const struct policydb_compat_info *policydb_lookup_compat(int version)
{
int i;
- struct policydb_compat_info *info = NULL;
for (i = 0; i < ARRAY_SIZE(policydb_compat); i++) {
- if (policydb_compat[i].version == version) {
- info = &policydb_compat[i];
- break;
- }
+ if (policydb_compat[i].version == version)
+ return &policydb_compat[i];
}
- return info;
+
+ return NULL;
}
/*
@@ -316,8 +312,7 @@ static int cat_destroy(void *key, void *datum, void *p)
return 0;
}
-static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
-{
+static int (*const destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
common_destroy,
cls_destroy,
role_destroy,
@@ -672,8 +667,7 @@ static int cat_index(void *key, void *datum, void *datap)
return 0;
}
-static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
-{
+static int (*const index_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
common_index,
class_index,
role_index,
@@ -704,7 +698,7 @@ static void symtab_hash_eval(struct symtab *s)
}
#else
-static inline void hash_eval(struct hashtab *h, char *hash_name)
+static inline void hash_eval(struct hashtab *h, const char *hash_name)
{
}
#endif
@@ -1641,8 +1635,8 @@ bad:
return rc;
}
-static int (*read_f[SYM_NUM]) (struct policydb *p, struct symtab *s, void *fp) =
-{
+static int (*const read_f[SYM_NUM]) (struct policydb *p,
+ struct symtab *s, void *fp) = {
common_read,
class_read,
role_read,
@@ -2213,7 +2207,7 @@ out:
return rc;
}
-static int ocontext_read(struct policydb *p, struct policydb_compat_info *info,
+static int ocontext_read(struct policydb *p, const struct policydb_compat_info *info,
void *fp)
{
int i, j, rc;
@@ -2409,7 +2403,7 @@ int policydb_read(struct policydb *p, void *fp)
u32 len, nprim, nel, perm;
char *policydb_str;
- struct policydb_compat_info *info;
+ const struct policydb_compat_info *info;
policydb_init(p);
@@ -3243,9 +3237,7 @@ static int user_write(void *vkey, void *datum, void *ptr)
return 0;
}
-static int (*write_f[SYM_NUM]) (void *key, void *datum,
- void *datap) =
-{
+static int (*const write_f[SYM_NUM]) (void *key, void *datum, void *datap) = {
common_write,
class_write,
role_write,
@@ -3256,7 +3248,7 @@ static int (*write_f[SYM_NUM]) (void *key, void *datum,
cat_write,
};
-static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
+static int ocontext_write(struct policydb *p, const struct policydb_compat_info *info,
void *fp)
{
unsigned int i, j, rc;
@@ -3613,7 +3605,7 @@ int policydb_write(struct policydb *p, void *fp)
__le32 buf[4];
u32 config;
size_t len;
- struct policydb_compat_info *info;
+ const struct policydb_compat_info *info;
/*
* refuse to write policy older than compressed avtab
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index c24d4e1063ea..ffc4e7bad205 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -370,6 +370,8 @@ static inline int put_entry(const void *buf, size_t bytes, int num, struct polic
{
size_t len = bytes * num;
+ if (len > fp->len)
+ return -EINVAL;
memcpy(fp->data, buf, len);
fp->data += len;
fp->len -= len;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 8e92af7dd284..64a6a37dc36d 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -99,7 +99,7 @@ static void context_struct_compute_av(struct policydb *policydb,
struct extended_perms *xperms);
static int selinux_set_mapping(struct policydb *pol,
- struct security_class_mapping *map,
+ const struct security_class_mapping *map,
struct selinux_map *out_map)
{
u16 i, j;
@@ -121,7 +121,7 @@ static int selinux_set_mapping(struct policydb *pol,
/* Store the raw class and permission values */
j = 0;
while (map[j].name) {
- struct security_class_mapping *p_in = map + (j++);
+ const struct security_class_mapping *p_in = map + (j++);
struct selinux_mapping *p_out = out_map->mapping + j;
/* An empty class string skips ahead */
@@ -358,27 +358,27 @@ static int constraint_expr_eval(struct policydb *policydb,
l2 = &(tcontext->range.level[1]);
goto mls_ops;
mls_ops:
- switch (e->op) {
- case CEXPR_EQ:
- s[++sp] = mls_level_eq(l1, l2);
- continue;
- case CEXPR_NEQ:
- s[++sp] = !mls_level_eq(l1, l2);
- continue;
- case CEXPR_DOM:
- s[++sp] = mls_level_dom(l1, l2);
- continue;
- case CEXPR_DOMBY:
- s[++sp] = mls_level_dom(l2, l1);
- continue;
- case CEXPR_INCOMP:
- s[++sp] = mls_level_incomp(l2, l1);
- continue;
- default:
- BUG();
- return 0;
- }
- break;
+ switch (e->op) {
+ case CEXPR_EQ:
+ s[++sp] = mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_NEQ:
+ s[++sp] = !mls_level_eq(l1, l2);
+ continue;
+ case CEXPR_DOM:
+ s[++sp] = mls_level_dom(l1, l2);
+ continue;
+ case CEXPR_DOMBY:
+ s[++sp] = mls_level_dom(l2, l1);
+ continue;
+ case CEXPR_INCOMP:
+ s[++sp] = mls_level_incomp(l2, l1);
+ continue;
+ default:
+ BUG();
+ return 0;
+ }
+ break;
default:
BUG();
return 0;
@@ -529,8 +529,6 @@ out:
/* release scontext/tcontext */
kfree(tcontext_name);
kfree(scontext_name);
-
- return;
}
/*
@@ -1452,7 +1450,7 @@ static int string_to_context_struct(struct policydb *pol,
/* Parse the security context. */
rc = -EINVAL;
- scontextp = (char *) scontext;
+ scontextp = scontext;
/* Extract the user. */
p = scontextp;
@@ -2024,7 +2022,8 @@ static inline int convert_context_handle_invalid_context(
* in `newc'. Verify that the context is valid
* under the new policy.
*/
-static int convert_context(struct context *oldc, struct context *newc, void *p)
+static int convert_context(struct context *oldc, struct context *newc, void *p,
+ gfp_t gfp_flags)
{
struct convert_context_args *args;
struct ocontext *oc;
@@ -2038,7 +2037,7 @@ static int convert_context(struct context *oldc, struct context *newc, void *p)
args = p;
if (oldc->str) {
- s = kstrdup(oldc->str, GFP_KERNEL);
+ s = kstrdup(oldc->str, gfp_flags);
if (!s)
return -ENOMEM;
@@ -2875,7 +2874,7 @@ out_unlock:
*/
static inline int __security_genfs_sid(struct selinux_policy *policy,
const char *fstype,
- char *path,
+ const char *path,
u16 orig_sclass,
u32 *sid)
{
@@ -2928,7 +2927,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,
*/
int security_genfs_sid(struct selinux_state *state,
const char *fstype,
- char *path,
+ const char *path,
u16 orig_sclass,
u32 *sid)
{
@@ -2952,7 +2951,7 @@ int security_genfs_sid(struct selinux_state *state,
int selinux_policy_genfs_sid(struct selinux_policy *policy,
const char *fstype,
- char *path,
+ const char *path,
u16 orig_sclass,
u32 *sid)
{
@@ -2982,7 +2981,6 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
}
retry:
- rc = 0;
rcu_read_lock();
policy = rcu_dereference(state->policy);
policydb = &policy->policydb;
@@ -4051,6 +4049,7 @@ int security_read_policy(struct selinux_state *state,
int security_read_state_kernel(struct selinux_state *state,
void **data, size_t *len)
{
+ int err;
struct selinux_policy *policy;
policy = rcu_dereference_protected(
@@ -4063,5 +4062,11 @@ int security_read_state_kernel(struct selinux_state *state,
if (!*data)
return -ENOMEM;
- return __security_read_policy(policy, *data, len);
+ err = __security_read_policy(policy, *data, len);
+ if (err) {
+ vfree(*data);
+ *data = NULL;
+ *len = 0;
+ }
+ return err;
}
diff --git a/security/selinux/ss/sidtab.c b/security/selinux/ss/sidtab.c
index 656d50b09f76..db5cce385bf8 100644
--- a/security/selinux/ss/sidtab.c
+++ b/security/selinux/ss/sidtab.c
@@ -27,8 +27,8 @@ struct sidtab_str_cache {
char str[];
};
-#define index_to_sid(index) (index + SECINITSID_NUM + 1)
-#define sid_to_index(sid) (sid - (SECINITSID_NUM + 1))
+#define index_to_sid(index) ((index) + SECINITSID_NUM + 1)
+#define sid_to_index(sid) ((sid) - (SECINITSID_NUM + 1))
int sidtab_init(struct sidtab *s)
{
@@ -325,7 +325,7 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context,
}
rc = convert->func(context, &dst_convert->context,
- convert->args);
+ convert->args, GFP_ATOMIC);
if (rc) {
context_destroy(&dst->context);
goto out_unlock;
@@ -404,7 +404,7 @@ static int sidtab_convert_tree(union sidtab_entry_inner *edst,
while (i < SIDTAB_LEAF_ENTRIES && *pos < count) {
rc = convert->func(&esrc->ptr_leaf->entries[i].context,
&edst->ptr_leaf->entries[i].context,
- convert->args);
+ convert->args, GFP_KERNEL);
if (rc)
return rc;
(*pos)++;
@@ -570,7 +570,7 @@ void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry,
goto out_unlock;
}
- cache = kmalloc(sizeof(struct sidtab_str_cache) + str_len, GFP_ATOMIC);
+ cache = kmalloc(struct_size(cache, str, str_len), GFP_ATOMIC);
if (!cache)
goto out_unlock;
diff --git a/security/selinux/ss/sidtab.h b/security/selinux/ss/sidtab.h
index 4eff0e49dcb2..9fce0d553fe2 100644
--- a/security/selinux/ss/sidtab.h
+++ b/security/selinux/ss/sidtab.h
@@ -65,7 +65,7 @@ struct sidtab_isid_entry {
};
struct sidtab_convert_params {
- int (*func)(struct context *oldc, struct context *newc, void *args);
+ int (*func)(struct context *oldc, struct context *newc, void *args, gfp_t gfp_flags);
void *args;
struct sidtab *target;
};
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index be83e5ce4469..c576832febc6 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -89,7 +89,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (str_len >= PAGE_SIZE)
return -ENOMEM;
- ctx = kmalloc(sizeof(*ctx) + str_len + 1, gfp);
+ ctx = kmalloc(struct_size(ctx, ctx_str, str_len + 1), gfp);
if (!ctx)
return -ENOMEM;
@@ -347,7 +347,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
int rc;
struct xfrm_sec_ctx *ctx;
char *ctx_str = NULL;
- int str_len;
+ u32 str_len;
if (!polsec)
return 0;
@@ -360,7 +360,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
if (rc)
return rc;
- ctx = kmalloc(sizeof(*ctx) + str_len, GFP_ATOMIC);
+ ctx = kmalloc(struct_size(ctx, ctx_str, str_len), GFP_ATOMIC);
if (!ctx) {
rc = -ENOMEM;
goto out;