[Patch v7 15/18] security: Update speculation restriction of a process when modifying its dumpability

From: Tim Chen
Date: Tue Nov 20 2018 - 19:42:47 EST


When a task is made non-dumpable, a higher level of security is implied
implicitly as its memory is imposed with access restriction. Many
daemons touching sensitive data (e.g. sshd) make theselves non-dumpable.
Such tasks should have speculative execution restricted to protect them
from attacks taking advantage of CPU speculation side channels.

Add calls to arch_update_spec_restiction() to put speculative restriction
on a task when changing its dumpability. Restrict speculative execution
on a non-dumpable task and relax the restrictions on a dumpable task.

A change to dumpability occurs via setgid, setuid, or
prctl(SUID_SET_DUMPABLE) syscalls. The user should expect associated
change in speculative restriction occurs only on the task that issued
such syscall. Speculative restriction changes are not extended to other
threads in the same process. This should not be a problem as such
changes should be made before spawning additional threads.

Signed-off-by: Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx>
---
fs/exec.c | 3 +++
include/linux/cpu.h | 3 +++
kernel/cpu.c | 5 +++++
kernel/cred.c | 5 ++++-
kernel/sys.c | 7 +++++++
5 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/fs/exec.c b/fs/exec.c
index fc281b7..d72e20d 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -62,6 +62,7 @@
#include <linux/oom.h>
#include <linux/compat.h>
#include <linux/vmalloc.h>
+#include <linux/cpu.h>

#include <linux/uaccess.h>
#include <asm/mmu_context.h>
@@ -1366,6 +1367,8 @@ void setup_new_exec(struct linux_binprm * bprm)
else
set_dumpable(current->mm, SUID_DUMP_USER);

+ arch_update_spec_restriction(current);
+
arch_setup_new_exec();
perf_event_exec();
__set_task_comm(current, kbasename(bprm->filename), true);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 6f43024..4fef90a 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -187,4 +187,7 @@ static inline void cpu_smt_check_topology(void) { }
DECLARE_STATIC_KEY_TRUE(cpu_smt_enabled);
#endif

+/* Update CPU's speculation restrictions on a task based on task's properties */
+extern int arch_update_spec_restriction(struct task_struct *task);
+
#endif /* _LINUX_CPU_H_ */
diff --git a/kernel/cpu.c b/kernel/cpu.c
index f846416..fe93a8a 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2291,6 +2291,11 @@ void init_cpu_online(const struct cpumask *src)
cpumask_copy(&__cpu_online_mask, src);
}

+int __weak arch_update_spec_restriction(struct task_struct *task)
+{
+ return 0;
+}
+
/*
* Activate the first processor.
*/
diff --git a/kernel/cred.c b/kernel/cred.c
index ecf0365..bc47653 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -19,6 +19,7 @@
#include <linux/security.h>
#include <linux/binfmts.h>
#include <linux/cn_proc.h>
+#include <linux/cpu.h>

#if 0
#define kdebug(FMT, ...) \
@@ -445,8 +446,10 @@ int commit_creds(struct cred *new)
!uid_eq(old->fsuid, new->fsuid) ||
!gid_eq(old->fsgid, new->fsgid) ||
!cred_cap_issubset(old, new)) {
- if (task->mm)
+ if (task->mm) {
set_dumpable(task->mm, suid_dumpable);
+ arch_update_spec_restriction(task);
+ }
task->pdeath_signal = 0;
smp_wmb();
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 123bd73..621ea94 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -2290,6 +2290,13 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
break;
}
set_dumpable(me->mm, arg2);
+ /*
+ * Any speculative execution restriction updates
+ * associated with change in dumpability
+ * applies only to the current task that issues
+ * the request.
+ */
+ arch_update_spec_restriction(me);
break;

case PR_SET_UNALIGN:
--
2.9.4