Thread (82 messages) 82 messages, 10 authors, 2021-05-21

Re: [PATCH v26 23/30] x86/cet/shstk: Handle thread shadow stack

From: Borislav Petkov <bp@alien8.de>
Date: 2021-05-10 14:17:56
Also in: linux-api, linux-doc, linux-mm, lkml

On Tue, Apr 27, 2021 at 01:43:08PM -0700, Yu-cheng Yu wrote:
quoted hunk ↗ jump to hunk
@@ -181,6 +184,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, unsigned long arg,
 	if (clone_flags & CLONE_SETTLS)
 		ret = set_new_tls(p, tls);
 
+#ifdef CONFIG_X86_64
IS_ENABLED
+	/* Allocate a new shadow stack for pthread */
+	if (!ret)
+		ret = shstk_setup_thread(p, clone_flags, stack_size);
+#endif
+
And why is this addition here...
 	if (!ret && unlikely(test_tsk_thread_flag(current, TIF_IO_BITMAP)))
 		io_bitmap_share(p);
... instead of here?

<---
quoted hunk ↗ jump to hunk
 
diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c
index c815c7507830..d387df84b7f1 100644
--- a/arch/x86/kernel/shstk.c
+++ b/arch/x86/kernel/shstk.c
@@ -70,6 +70,55 @@ int shstk_setup(void)
 	return 0;
 }
+int shstk_setup_thread(struct task_struct *tsk, unsigned long clone_flags,
Judging by what this function does, its name wants to be

shstk_alloc_thread_stack()

or so?
+		       unsigned long stack_size)
+{
+	unsigned long addr, size;
+	struct cet_user_state *state;
+	struct cet_status *cet = &tsk->thread.cet;
The tip-tree preferred ordering of variable declarations at the
beginning of a function is reverse fir tree order::

	struct long_struct_name *descriptive_name;
	unsigned long foo, bar;
	unsigned int tmp;
	int ret;

The above is faster to parse than the reverse ordering::

	int ret;
	unsigned int tmp;
	unsigned long foo, bar;
	struct long_struct_name *descriptive_name;

And even more so than random ordering::

	unsigned long foo, bar;
	int ret;
	struct long_struct_name *descriptive_name;
	unsigned int tmp;
+
+	if (!cet->shstk_size)
+		return 0;
+
This check needs a comment.
+	if ((clone_flags & (CLONE_VFORK | CLONE_VM)) != CLONE_VM)
+		return 0;
+
+	state = get_xsave_addr(&tsk->thread.fpu.state.xsave,
+			       XFEATURE_CET_USER);
Let that line stick out.
+
+	if (!state)
+		return -EINVAL;
+
+	if (stack_size == 0)
	if (!stack_size)
+		return -EINVAL;
and that test needs to be done first in the function.
+
+	/* Cap shadow stack size to 4 GB */
Why?
+	size = min_t(unsigned long long, rlimit(RLIMIT_STACK), SZ_4G);
+	size = min(size, stack_size);
+
+	/*
+	 * Compat-mode pthreads share a limited address space.
+	 * If each function call takes an average of four slots
+	 * stack space, allocate 1/4 of stack size for shadow stack.
+	 */
+	if (in_compat_syscall())
+		size /= 4;
<---- newline here.
+	size = round_up(size, PAGE_SIZE);
+	addr = alloc_shstk(size);
+
^ Superfluous newline.
+	if (IS_ERR_VALUE(addr)) {
+		cet->shstk_base = 0;
+		cet->shstk_size = 0;
+		return PTR_ERR((void *)addr);
+	}
+
+	fpu__prepare_write(&tsk->thread.fpu);
+	state->user_ssp = (u64)(addr + size);
cet_user_state has u64, cet_status has unsigned longs. Make them all u64.

And since cet_status is per thread, but I had suggested struct
shstk_desc, I think now that that should be called

struct thread_shstk

or so to denote *exactly* what it is.

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help