Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7bbf1373 authored by Kees Cook's avatar Kees Cook Committed by Thomas Gleixner
Browse files

nospec: Allow getting/setting on non-current task



Adjust arch_prctl_get/set_spec_ctrl() to operate on tasks other than
current.

This is needed both for /proc/$pid/status queries and for seccomp (since
thread-syncing can trigger seccomp in non-current threads).

Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent a73ec77e
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -530,31 +530,35 @@ static void ssb_select_mitigation()

#undef pr_fmt

static int ssb_prctl_set(unsigned long ctrl)
static int ssb_prctl_set(struct task_struct *task, unsigned long ctrl)
{
	bool rds = !!test_tsk_thread_flag(current, TIF_RDS);
	bool rds = !!test_tsk_thread_flag(task, TIF_RDS);

	if (ssb_mode != SPEC_STORE_BYPASS_PRCTL)
		return -ENXIO;

	if (ctrl == PR_SPEC_ENABLE)
		clear_tsk_thread_flag(current, TIF_RDS);
		clear_tsk_thread_flag(task, TIF_RDS);
	else
		set_tsk_thread_flag(current, TIF_RDS);
		set_tsk_thread_flag(task, TIF_RDS);

	if (rds != !!test_tsk_thread_flag(current, TIF_RDS))
	/*
	 * If being set on non-current task, delay setting the CPU
	 * mitigation until it is next scheduled.
	 */
	if (task == current && rds != !!test_tsk_thread_flag(task, TIF_RDS))
		speculative_store_bypass_update();

	return 0;
}

static int ssb_prctl_get(void)
static int ssb_prctl_get(struct task_struct *task)
{
	switch (ssb_mode) {
	case SPEC_STORE_BYPASS_DISABLE:
		return PR_SPEC_DISABLE;
	case SPEC_STORE_BYPASS_PRCTL:
		if (test_tsk_thread_flag(current, TIF_RDS))
		if (test_tsk_thread_flag(task, TIF_RDS))
			return PR_SPEC_PRCTL | PR_SPEC_DISABLE;
		return PR_SPEC_PRCTL | PR_SPEC_ENABLE;
	default:
@@ -564,24 +568,25 @@ static int ssb_prctl_get(void)
	}
}

int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl)
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
			     unsigned long ctrl)
{
	if (ctrl != PR_SPEC_ENABLE && ctrl != PR_SPEC_DISABLE)
		return -ERANGE;

	switch (which) {
	case PR_SPEC_STORE_BYPASS:
		return ssb_prctl_set(ctrl);
		return ssb_prctl_set(task, ctrl);
	default:
		return -ENODEV;
	}
}

int arch_prctl_spec_ctrl_get(unsigned long which)
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
{
	switch (which) {
	case PR_SPEC_STORE_BYPASS:
		return ssb_prctl_get();
		return ssb_prctl_get(task);
	default:
		return -ENODEV;
	}
+5 −2
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#define _LINUX_NOSPEC_H
#include <asm/barrier.h>

struct task_struct;

/**
 * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
 * @index: array element index
@@ -57,7 +59,8 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
})

/* Speculation control prctl */
int arch_prctl_spec_ctrl_get(unsigned long which);
int arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl);
int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which);
int arch_prctl_spec_ctrl_set(struct task_struct *task, unsigned long which,
			     unsigned long ctrl);

#endif /* _LINUX_NOSPEC_H */
+5 −4
Original line number Diff line number Diff line
@@ -2244,12 +2244,13 @@ static int propagate_has_child_subreaper(struct task_struct *p, void *data)
	return 1;
}

int __weak arch_prctl_spec_ctrl_get(unsigned long which)
int __weak arch_prctl_spec_ctrl_get(struct task_struct *t, unsigned long which)
{
	return -EINVAL;
}

int __weak arch_prctl_spec_ctrl_set(unsigned long which, unsigned long ctrl)
int __weak arch_prctl_spec_ctrl_set(struct task_struct *t, unsigned long which,
				    unsigned long ctrl)
{
	return -EINVAL;
}
@@ -2465,12 +2466,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
	case PR_GET_SPECULATION_CTRL:
		if (arg3 || arg4 || arg5)
			return -EINVAL;
		error = arch_prctl_spec_ctrl_get(arg2);
		error = arch_prctl_spec_ctrl_get(me, arg2);
		break;
	case PR_SET_SPECULATION_CTRL:
		if (arg4 || arg5)
			return -EINVAL;
		error = arch_prctl_spec_ctrl_set(arg2, arg3);
		error = arch_prctl_spec_ctrl_set(me, arg2, arg3);
		break;
	default:
		error = -EINVAL;