summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2021-04-27 22:42:11 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2021-04-27 22:42:11 +0200
commitf1c921fb70de06c7eda59104470134aecc7a07c4 (patch)
tree9e4bc137ef8396b8cdb64d7380e3be26d3fbf8b0 /security
parentMerge tag 'afs-netfs-lib-20210426' of git://git.kernel.org/pub/scm/linux/kern... (diff)
parentselinux: add proper NULL termination to the secclass_map permissions (diff)
downloadlinux-f1c921fb70de06c7eda59104470134aecc7a07c4.tar.xz
linux-f1c921fb70de06c7eda59104470134aecc7a07c4.zip
Merge tag 'selinux-pr-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux
Pull selinux updates from Paul Moore: - Add support for measuring the SELinux state and policy capabilities using IMA. - A handful of SELinux/NFS patches to compare the SELinux state of one mount with a set of mount options. Olga goes into more detail in the patch descriptions, but this is important as it allows more flexibility when using NFS and SELinux context mounts. - Properly differentiate between the subjective and objective LSM credentials; including support for the SELinux and Smack. My clumsy attempt at a proper fix for AppArmor didn't quite pass muster so John is working on a proper AppArmor patch, in the meantime this set of patches shouldn't change the behavior of AppArmor in any way. This change explains the bulk of the diffstat beyond security/. - Fix a problem where we were not properly terminating the permission list for two SELinux object classes. * tag 'selinux-pr-20210426' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: selinux: add proper NULL termination to the secclass_map permissions smack: differentiate between subjective and objective task credentials selinux: clarify task subjective and objective credentials lsm: separate security_task_getsecid() into subjective and objective variants nfs: account for selinux security context when deciding to share superblock nfs: remove unneeded null check in nfs_fill_super() lsm,selinux: add new hook to compare new mount to an existing mount selinux: fix misspellings using codespell tool selinux: fix misspellings using codespell tool selinux: measure state and policy capabilities selinux: Allow context mounts for unpriviliged overlayfs
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/lsm.c3
-rw-r--r--security/integrity/ima/ima_appraise.c2
-rw-r--r--security/integrity/ima/ima_main.c14
-rw-r--r--security/security.c20
-rw-r--r--security/selinux/hooks.c170
-rw-r--r--security/selinux/ima.c87
-rw-r--r--security/selinux/include/classmap.h5
-rw-r--r--security/selinux/include/ima.h6
-rw-r--r--security/selinux/include/security.h2
-rw-r--r--security/selinux/selinuxfs.c6
-rw-r--r--security/selinux/ss/hashtab.c2
-rw-r--r--security/selinux/ss/services.c2
-rw-r--r--security/smack/smack.h18
-rw-r--r--security/smack/smack_lsm.c39
14 files changed, 303 insertions, 73 deletions
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 240a53387e6b..f72406fe1bf2 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1252,7 +1252,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_free, apparmor_task_free),
LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
- LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid),
+ LSM_HOOK_INIT(task_getsecid_subj, apparmor_task_getsecid),
+ LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid),
LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
LSM_HOOK_INIT(task_kill, apparmor_task_kill),
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 565e33ff19d0..4e5eb0236278 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -76,7 +76,7 @@ int ima_must_appraise(struct user_namespace *mnt_userns, struct inode *inode,
if (!ima_appraise)
return 0;
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
return ima_match_policy(mnt_userns, inode, current_cred(), secid, func,
mask, IMA_APPRAISE | IMA_HASH, NULL, NULL, NULL);
}
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 9ef748ea829f..b85d9e429426 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -391,7 +391,7 @@ int ima_file_mmap(struct file *file, unsigned long prot)
u32 secid;
if (file && (prot & PROT_EXEC)) {
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, NULL,
0, MAY_EXEC, MMAP_CHECK);
}
@@ -429,7 +429,7 @@ int ima_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
!(prot & PROT_EXEC) || (vma->vm_flags & VM_EXEC))
return 0;
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
inode = file_inode(vma->vm_file);
action = ima_get_action(file_mnt_user_ns(vma->vm_file), inode,
current_cred(), secid, MAY_EXEC, MMAP_CHECK,
@@ -470,7 +470,7 @@ int ima_bprm_check(struct linux_binprm *bprm)
int ret;
u32 secid;
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
ret = process_measurement(bprm->file, current_cred(), secid, NULL, 0,
MAY_EXEC, BPRM_CHECK);
if (ret)
@@ -495,7 +495,7 @@ int ima_file_check(struct file *file, int mask)
{
u32 secid;
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, NULL, 0,
mask & (MAY_READ | MAY_WRITE | MAY_EXEC |
MAY_APPEND), FILE_CHECK);
@@ -686,7 +686,7 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id,
/* Read entire file for all partial reads. */
func = read_idmap[read_id] ?: FILE_CHECK;
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, NULL,
0, MAY_READ, func);
}
@@ -729,7 +729,7 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size,
}
func = read_idmap[read_id] ?: FILE_CHECK;
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
return process_measurement(file, current_cred(), secid, buf, size,
MAY_READ, func);
}
@@ -872,7 +872,7 @@ void process_buffer_measurement(struct user_namespace *mnt_userns,
* buffer measurements.
*/
if (func) {
- security_task_getsecid(current, &secid);
+ security_task_getsecid_subj(current, &secid);
action = ima_get_action(mnt_userns, inode, current_cred(),
secid, 0, func, &pcr, &template,
func_data);
diff --git a/security/security.c b/security/security.c
index 5ac96b16f8fa..94383f83ba42 100644
--- a/security/security.c
+++ b/security/security.c
@@ -890,6 +890,13 @@ int security_sb_eat_lsm_opts(char *options, void **mnt_opts)
}
EXPORT_SYMBOL(security_sb_eat_lsm_opts);
+int security_sb_mnt_opts_compat(struct super_block *sb,
+ void *mnt_opts)
+{
+ return call_int_hook(sb_mnt_opts_compat, 0, sb, mnt_opts);
+}
+EXPORT_SYMBOL(security_sb_mnt_opts_compat);
+
int security_sb_remount(struct super_block *sb,
void *mnt_opts)
{
@@ -1762,12 +1769,19 @@ int security_task_getsid(struct task_struct *p)
return call_int_hook(task_getsid, 0, p);
}
-void security_task_getsecid(struct task_struct *p, u32 *secid)
+void security_task_getsecid_subj(struct task_struct *p, u32 *secid)
+{
+ *secid = 0;
+ call_void_hook(task_getsecid_subj, p, secid);
+}
+EXPORT_SYMBOL(security_task_getsecid_subj);
+
+void security_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
*secid = 0;
- call_void_hook(task_getsecid, p, secid);
+ call_void_hook(task_getsecid_obj, p, secid);
}
-EXPORT_SYMBOL(security_task_getsecid);
+EXPORT_SYMBOL(security_task_getsecid_obj);
int security_task_setnice(struct task_struct *p, int nice)
{
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ddd097790d47..92f909a2e8f7 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -230,9 +230,22 @@ 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(const struct task_struct *task)
+static inline u32 task_sid_obj(const struct task_struct *task)
{
u32 sid;
@@ -242,6 +255,29 @@ static inline u32 task_sid(const struct task_struct *task)
return sid;
}
+/*
+ * get the security ID of a task for use with binder
+ */
+static inline u32 task_sid_binder(const struct task_struct *task)
+{
+ /*
+ * In many case where this function is used we should be using the
+ * task's subjective SID, but we can't reliably access the subjective
+ * creds of a task other than our own so we must use the objective
+ * creds/SID, which are safe to access. The downside is that if a task
+ * is temporarily overriding it's creds it will not be reflected here;
+ * however, it isn't clear that binder would handle that case well
+ * anyway.
+ *
+ * If this ever changes and we can safely reference the subjective
+ * creds/SID of another task, this function will make it easier to
+ * identify the various places where we make use of the task SIDs in
+ * the binder code. It is also likely that we will need to adjust
+ * the main drivers/android binder code as well.
+ */
+ return task_sid_obj(task);
+}
+
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
/*
@@ -760,7 +796,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (sb->s_user_ns != &init_user_ns &&
strcmp(sb->s_type->name, "tmpfs") &&
strcmp(sb->s_type->name, "ramfs") &&
- strcmp(sb->s_type->name, "devpts")) {
+ strcmp(sb->s_type->name, "devpts") &&
+ strcmp(sb->s_type->name, "overlay")) {
if (context_sid || fscontext_sid || rootcontext_sid ||
defcontext_sid) {
rc = -EACCES;
@@ -2034,11 +2071,8 @@ static inline u32 open_file_to_av(struct file *file)
static int selinux_binder_set_context_mgr(struct task_struct *mgr)
{
- u32 mysid = current_sid();
- u32 mgrsid = task_sid(mgr);
-
return avc_has_perm(&selinux_state,
- mysid, mgrsid, SECCLASS_BINDER,
+ current_sid(), task_sid_binder(mgr), SECCLASS_BINDER,
BINDER__SET_CONTEXT_MGR, NULL);
}
@@ -2046,8 +2080,7 @@ static int selinux_binder_transaction(struct task_struct *from,
struct task_struct *to)
{
u32 mysid = current_sid();
- u32 fromsid = task_sid(from);
- u32 tosid = task_sid(to);
+ u32 fromsid = task_sid_binder(from);
int rc;
if (mysid != fromsid) {
@@ -2058,19 +2091,16 @@ static int selinux_binder_transaction(struct task_struct *from,
return rc;
}
- return avc_has_perm(&selinux_state,
- fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
- NULL);
+ return avc_has_perm(&selinux_state, fromsid, task_sid_binder(to),
+ SECCLASS_BINDER, BINDER__CALL, NULL);
}
static int selinux_binder_transfer_binder(struct task_struct *from,
struct task_struct *to)
{
- u32 fromsid = task_sid(from);
- u32 tosid = task_sid(to);
-
return avc_has_perm(&selinux_state,
- fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
+ task_sid_binder(from), task_sid_binder(to),
+ SECCLASS_BINDER, BINDER__TRANSFER,
NULL);
}
@@ -2078,7 +2108,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
struct task_struct *to,
struct file *file)
{
- u32 sid = task_sid(to);
+ u32 sid = task_sid_binder(to);
struct file_security_struct *fsec = selinux_file(file);
struct dentry *dentry = file->f_path.dentry;
struct inode_security_struct *isec;
@@ -2114,10 +2144,10 @@ static int selinux_binder_transfer_file(struct task_struct *from,
}
static int selinux_ptrace_access_check(struct task_struct *child,
- unsigned int mode)
+ unsigned int mode)
{
u32 sid = current_sid();
- u32 csid = task_sid(child);
+ u32 csid = task_sid_obj(child);
if (mode & PTRACE_MODE_READ)
return avc_has_perm(&selinux_state,
@@ -2130,15 +2160,15 @@ static int selinux_ptrace_access_check(struct task_struct *child,
static int selinux_ptrace_traceme(struct task_struct *parent)
{
return avc_has_perm(&selinux_state,
- task_sid(parent), current_sid(), SECCLASS_PROCESS,
- PROCESS__PTRACE, NULL);
+ task_sid_subj(parent), task_sid_obj(current),
+ 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(&selinux_state,
- current_sid(), task_sid(target), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(target), SECCLASS_PROCESS,
PROCESS__GETCAP, NULL);
}
@@ -2263,7 +2293,7 @@ static u32 ptrace_parent_sid(void)
rcu_read_lock();
tracer = ptrace_parent(current);
if (tracer)
- sid = task_sid(tracer);
+ sid = task_sid_obj(tracer);
rcu_read_unlock();
return sid;
@@ -2684,6 +2714,61 @@ free_opt:
return rc;
}
+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;
+
+ /*
+ * Superblock not initialized (i.e. no options) - reject if any
+ * options specified, otherwise accept.
+ */
+ if (!(sbsec->flags & SE_SBINITIALIZED))
+ return opts ? 1 : 0;
+
+ /*
+ * Superblock initialized and no options specified - reject if
+ * superblock has any options set, otherwise accept.
+ */
+ 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))
+ 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))
+ return 1;
+ }
+ if (opts->rootcontext) {
+ 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))
+ 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))
+ return 1;
+ }
+ return 0;
+}
+
static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
{
struct selinux_mnt_opts *opts = mnt_opts;
@@ -3920,7 +4005,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
struct file *file;
- u32 sid = task_sid(tsk);
+ u32 sid = task_sid_obj(tsk);
u32 perm;
struct file_security_struct *fsec;
@@ -4139,47 +4224,52 @@ static int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETPGID, NULL);
}
static int selinux_task_getpgid(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETPGID, NULL);
}
static int selinux_task_getsid(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSESSION, NULL);
}
-static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
+static void selinux_task_getsecid_subj(struct task_struct *p, u32 *secid)
+{
+ *secid = task_sid_subj(p);
+}
+
+static void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
- *secid = task_sid(p);
+ *secid = task_sid_obj(p);
}
static int selinux_task_setnice(struct task_struct *p, int nice)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getioprio(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
@@ -4210,7 +4300,7 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max)
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p),
+ current_sid(), task_sid_obj(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
return 0;
@@ -4219,21 +4309,21 @@ 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(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
static int selinux_task_getscheduler(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL);
}
static int selinux_task_movememory(struct task_struct *p)
{
return avc_has_perm(&selinux_state,
- current_sid(), task_sid(p), SECCLASS_PROCESS,
+ current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL);
}
@@ -4252,14 +4342,14 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
else
secid = cred_sid(cred);
return avc_has_perm(&selinux_state,
- secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
+ secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
}
static void selinux_task_to_inode(struct task_struct *p,
struct inode *inode)
{
struct inode_security_struct *isec = selinux_inode(inode);
- u32 sid = task_sid(p);
+ u32 sid = task_sid_obj(p);
spin_lock(&isec->lock);
isec->sclass = inode_mode_to_security_class(inode->i_mode);
@@ -6152,7 +6242,7 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
struct ipc_security_struct *isec;
struct msg_security_struct *msec;
struct common_audit_data ad;
- u32 sid = task_sid(target);
+ u32 sid = task_sid_subj(target);
int rc;
isec = selinux_ipc(msq);
@@ -7077,6 +7167,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
+ LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat),
LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
@@ -7148,7 +7239,8 @@ 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, selinux_task_getsecid),
+ LSM_HOOK_INIT(task_getsecid_subj, selinux_task_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),
LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
diff --git a/security/selinux/ima.c b/security/selinux/ima.c
index 03715893ff97..34d421861bfc 100644
--- a/security/selinux/ima.c
+++ b/security/selinux/ima.c
@@ -13,18 +13,83 @@
#include "ima.h"
/*
- * selinux_ima_measure_state - Measure hash of the SELinux policy
+ * selinux_ima_collect_state - Read selinux configuration settings
*
- * @state: selinux state struct
+ * @state: selinux_state
*
- * NOTE: This function must be called with policy_mutex held.
+ * On success returns the configuration settings string.
+ * On error, returns NULL.
*/
-void selinux_ima_measure_state(struct selinux_state *state)
+static char *selinux_ima_collect_state(struct selinux_state *state)
{
+ const char *on = "=1;", *off = "=0;";
+ char *buf;
+ int buf_len, len, i, rc;
+
+ buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
+
+ len = strlen(on);
+ for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++)
+ buf_len += strlen(selinux_policycap_names[i]) + len;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ rc = strscpy(buf, "initialized", buf_len);
+ WARN_ON(rc < 0);
+
+ rc = strlcat(buf, selinux_initialized(state) ? on : off, buf_len);
+ WARN_ON(rc >= buf_len);
+
+ rc = strlcat(buf, "enforcing", buf_len);
+ WARN_ON(rc >= buf_len);
+
+ rc = strlcat(buf, enforcing_enabled(state) ? on : off, buf_len);
+ WARN_ON(rc >= buf_len);
+
+ rc = strlcat(buf, "checkreqprot", buf_len);
+ WARN_ON(rc >= buf_len);
+
+ rc = strlcat(buf, checkreqprot_get(state) ? on : off, buf_len);
+ WARN_ON(rc >= buf_len);
+
+ for (i = 0; i < __POLICYDB_CAPABILITY_MAX; i++) {
+ rc = strlcat(buf, selinux_policycap_names[i], buf_len);
+ WARN_ON(rc >= buf_len);
+
+ rc = strlcat(buf, state->policycap[i] ? on : off, buf_len);
+ WARN_ON(rc >= buf_len);
+ }
+
+ return buf;
+}
+
+/*
+ * selinux_ima_measure_state_locked - Measure SELinux state and hash of policy
+ *
+ * @state: selinux state struct
+ */
+void selinux_ima_measure_state_locked(struct selinux_state *state)
+{
+ char *state_str = NULL;
void *policy = NULL;
size_t policy_len;
int rc = 0;
+ WARN_ON(!mutex_is_locked(&state->policy_mutex));
+
+ state_str = selinux_ima_collect_state(state);
+ if (!state_str) {
+ pr_err("SELinux: %s: failed to read state.\n", __func__);
+ return;
+ }
+
+ ima_measure_critical_data("selinux", "selinux-state",
+ state_str, strlen(state_str), false);
+
+ kfree(state_str);
+
/*
* Measure SELinux policy only after initialization is completed.
*/
@@ -42,3 +107,17 @@ void selinux_ima_measure_state(struct selinux_state *state)
vfree(policy);
}
+
+/*
+ * selinux_ima_measure_state - Measure SELinux state and hash of policy
+ *
+ * @state: selinux state struct
+ */
+void selinux_ima_measure_state(struct selinux_state *state)
+{
+ WARN_ON(mutex_is_locked(&state->policy_mutex));
+
+ mutex_lock(&state->policy_mutex);
+ selinux_ima_measure_state_locked(state);
+ mutex_unlock(&state->policy_mutex);
+}
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index ba2e01a6955c..62d19bccf3de 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -242,11 +242,12 @@ struct security_class_mapping secclass_map[] = {
{ "infiniband_endport",
{ "manage_subnet", NULL } },
{ "bpf",
- {"map_create", "map_read", "map_write", "prog_load", "prog_run"} },
+ { "map_create", "map_read", "map_write", "prog_load", "prog_run",
+ NULL } },
{ "xdp_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "perf_event",
- {"open", "cpu", "kernel", "tracepoint", "read", "write"} },
+ { "open", "cpu", "kernel", "tracepoint", "read", "write", NULL } },
{ "lockdown",
{ "integrity", "confidentiality", NULL } },
{ "anon_inode",
diff --git a/security/selinux/include/ima.h b/security/selinux/include/ima.h
index d69c36611423..75ca92b4a462 100644
--- a/security/selinux/include/ima.h
+++ b/security/selinux/include/ima.h
@@ -15,10 +15,16 @@
#ifdef CONFIG_IMA
extern void selinux_ima_measure_state(struct selinux_state *selinux_state);
+extern void selinux_ima_measure_state_locked(
+ struct selinux_state *selinux_state);
#else
static inline void selinux_ima_measure_state(struct selinux_state *selinux_state)
{
}
+static inline void selinux_ima_measure_state_locked(
+ struct selinux_state *selinux_state)
+{
+}
#endif
#endif /* _SELINUX_IMA_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 7650de048570..ac0ece01305a 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -426,7 +426,7 @@ extern struct page *selinux_kernel_status_page(struct selinux_state *state);
#define SELINUX_KERNEL_STATUS_VERSION 1
struct selinux_kernel_status {
- u32 version; /* version number of thie structure */
+ u32 version; /* version number of the structure */
u32 sequence; /* sequence number of seqlock logic */
u32 enforcing; /* current setting of enforcing mode */
u32 policyload; /* times of policy reloaded */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index fff6babeeae6..e4cd7cb856f3 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -41,6 +41,7 @@
#include "security.h"
#include "objsec.h"
#include "conditional.h"
+#include "ima.h"
enum sel_inos {
SEL_ROOT_INO = 2,
@@ -182,6 +183,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
selinux_status_update_setenforce(state, new_value);
if (!new_value)
call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);
+
+ selinux_ima_measure_state(state);
}
length = count;
out:
@@ -758,6 +761,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
checkreqprot_set(fsi->state, (new_value ? 1 : 0));
length = count;
+
+ selinux_ima_measure_state(fsi->state);
+
out:
kfree(page);
return length;
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c
index 3881787ce492..b8f6b3e0a921 100644
--- a/security/selinux/ss/hashtab.c
+++ b/security/selinux/ss/hashtab.c
@@ -13,7 +13,7 @@ static struct kmem_cache *hashtab_node_cachep __ro_after_init;
/*
* Here we simply round the number of elements up to the nearest power of two.
- * I tried also other options like rouding down or rounding to the closest
+ * I tried also other options like rounding down or rounding to the closest
* power of two (up or down based on which is closer), but I was unable to
* find any significant difference in lookup/insert performance that would
* justify switching to a different (less intuitive) formula. It could be that
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 301633145040..f0ba82611343 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2202,7 +2202,7 @@ static void selinux_notify_policy_change(struct selinux_state *state,
selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
- selinux_ima_measure_state(state);
+ selinux_ima_measure_state_locked(state);
}
void selinux_policy_commit(struct selinux_state *state,
diff --git a/security/smack/smack.h b/security/smack/smack.h
index a9768b12716b..08f9cb80655c 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -383,7 +383,23 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
return tsp->smk_task;
}
-static inline struct smack_known *smk_of_task_struct(
+static inline struct smack_known *smk_of_task_struct_subj(
+ const struct task_struct *t)
+{
+ struct smack_known *skp;
+ const struct cred *cred;
+
+ rcu_read_lock();
+
+ cred = rcu_dereference(t->cred);
+ skp = smk_of_task(smack_cred(cred));
+
+ rcu_read_unlock();
+
+ return skp;
+}
+
+static inline struct smack_known *smk_of_task_struct_obj(
const struct task_struct *t)
{
struct smack_known *skp;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 12a45e61c1a5..cd14bec4ad80 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -159,7 +159,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
{
struct task_smack *tsp = smack_cred(current_cred());
- struct smack_known *smk_task = smk_of_task_struct(otp);
+ struct smack_known *smk_task = smk_of_task_struct_obj(otp);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (rc <= 0)
@@ -479,7 +479,7 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
struct smack_known *skp;
- skp = smk_of_task_struct(ctp);
+ skp = smk_of_task_struct_obj(ctp);
return smk_ptrace_rule_check(current, skp, mode, __func__);
}
@@ -2033,7 +2033,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access,
const char *caller)
{
struct smk_audit_info ad;
- struct smack_known *skp = smk_of_task_struct(p);
+ struct smack_known *skp = smk_of_task_struct_subj(p);
int rc;
smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);
@@ -2078,15 +2078,29 @@ static int smack_task_getsid(struct task_struct *p)
}
/**
- * smack_task_getsecid - get the secid of the task
- * @p: the object task
+ * smack_task_getsecid_subj - get the subjective secid of the task
+ * @p: the task
* @secid: where to put the result
*
- * Sets the secid to contain a u32 version of the smack label.
+ * Sets the secid to contain a u32 version of the task's subjective smack label.
+ */
+static void smack_task_getsecid_subj(struct task_struct *p, u32 *secid)
+{
+ struct smack_known *skp = smk_of_task_struct_subj(p);
+
+ *secid = skp->smk_secid;
+}
+
+/**
+ * smack_task_getsecid_obj - get the objective secid of the task
+ * @p: the task
+ * @secid: where to put the result
+ *
+ * Sets the secid to contain a u32 version of the task's objective smack label.
*/
-static void smack_task_getsecid(struct task_struct *p, u32 *secid)
+static void smack_task_getsecid_obj(struct task_struct *p, u32 *secid)
{
- struct smack_known *skp = smk_of_task_struct(p);
+ struct smack_known *skp = smk_of_task_struct_obj(p);
*secid = skp->smk_secid;
}
@@ -2174,7 +2188,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
{
struct smk_audit_info ad;
struct smack_known *skp;
- struct smack_known *tkp = smk_of_task_struct(p);
+ struct smack_known *tkp = smk_of_task_struct_obj(p);
int rc;
if (!sig)
@@ -2212,7 +2226,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
struct inode_smack *isp = smack_inode(inode);
- struct smack_known *skp = smk_of_task_struct(p);
+ struct smack_known *skp = smk_of_task_struct_obj(p);
isp->smk_inode = skp;
isp->smk_flags |= SMK_INODE_INSTANT;
@@ -3483,7 +3497,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
static int smack_getprocattr(struct task_struct *p, char *name, char **value)
{
- struct smack_known *skp = smk_of_task_struct(p);
+ struct smack_known *skp = smk_of_task_struct_subj(p);
char *cp;
int slen;
@@ -4759,7 +4773,8 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(task_setpgid, smack_task_setpgid),
LSM_HOOK_INIT(task_getpgid, smack_task_getpgid),
LSM_HOOK_INIT(task_getsid, smack_task_getsid),
- LSM_HOOK_INIT(task_getsecid, smack_task_getsecid),
+ LSM_HOOK_INIT(task_getsecid_subj, smack_task_getsecid_subj),
+ LSM_HOOK_INIT(task_getsecid_obj, smack_task_getsecid_obj),
LSM_HOOK_INIT(task_setnice, smack_task_setnice),
LSM_HOOK_INIT(task_setioprio, smack_task_setioprio),
LSM_HOOK_INIT(task_getioprio, smack_task_getioprio),