selinux: Add helper functions to get and set checkreqprot

checkreqprot data member in selinux_state struct is accessed directly by
SELinux functions to get and set. This could cause unexpected read or
write access to this data member due to compiler optimizations and/or
compiler's reordering of access to this field.

Add helper functions to get and set checkreqprot data member in
selinux_state struct. These helper functions use READ_ONCE and
WRITE_ONCE macros to ensure atomic read or write of memory for
this data member.

Signed-off-by: Lakshmi Ramasubramanian <nramas@linux.microsoft.com>
Suggested-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Suggested-by: Paul Moore <paul@paul-moore.com>
Acked-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
This commit is contained in:
Lakshmi Ramasubramanian 2020-09-14 10:31:57 -07:00 committed by Paul Moore
parent e8ba53d002
commit 8861d0af64
3 changed files with 16 additions and 5 deletions

View File

@ -3718,7 +3718,7 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot,
return rc; return rc;
} }
if (selinux_state.checkreqprot) if (checkreqprot_get(&selinux_state))
prot = reqprot; prot = reqprot;
return file_map_prot_check(file, prot, return file_map_prot_check(file, prot,
@ -3732,7 +3732,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
u32 sid = cred_sid(cred); u32 sid = cred_sid(cred);
if (selinux_state.checkreqprot) if (checkreqprot_get(&selinux_state))
prot = reqprot; prot = reqprot;
if (default_noexec && if (default_noexec &&
@ -7234,7 +7234,7 @@ static __init int selinux_init(void)
memset(&selinux_state, 0, sizeof(selinux_state)); memset(&selinux_state, 0, sizeof(selinux_state));
enforcing_set(&selinux_state, selinux_enforcing_boot); enforcing_set(&selinux_state, selinux_enforcing_boot);
selinux_state.checkreqprot = selinux_checkreqprot_boot; checkreqprot_set(&selinux_state, selinux_checkreqprot_boot);
selinux_avc_init(&selinux_state.avc); selinux_avc_init(&selinux_state.avc);
mutex_init(&selinux_state.status_lock); mutex_init(&selinux_state.status_lock);
mutex_init(&selinux_state.policy_mutex); mutex_init(&selinux_state.policy_mutex);

View File

@ -143,6 +143,16 @@ static inline void enforcing_set(struct selinux_state *state, bool value)
} }
#endif #endif
static inline bool checkreqprot_get(const struct selinux_state *state)
{
return READ_ONCE(state->checkreqprot);
}
static inline void checkreqprot_set(struct selinux_state *state, bool value)
{
WRITE_ONCE(state->checkreqprot, value);
}
#ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef CONFIG_SECURITY_SELINUX_DISABLE
static inline bool selinux_disabled(struct selinux_state *state) static inline bool selinux_disabled(struct selinux_state *state)
{ {

View File

@ -717,7 +717,8 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u", fsi->state->checkreqprot); length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
checkreqprot_get(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
} }
@ -759,7 +760,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
comm, current->pid); comm, current->pid);
} }
fsi->state->checkreqprot = new_value ? 1 : 0; checkreqprot_set(fsi->state, (new_value ? 1 : 0));
length = count; length = count;
out: out:
kfree(page); kfree(page);