On Thu, Jan 11, 2018 at 08:39:25PM -0700, Theo de Raadt wrote:
> Stefan (stefan@) and I have been working for a few months on this
> diff, with help from a few others.
>
> At every trap and system call, it checks if the stack-pointer is on a
> page that is marked MAP_STACK. execve() is changed to create such
> mappings for the process stack. Also, libpthread is taught the new
> MAP_STACK flag to use with mmap().
>
> There is no corresponding system call which can set MAP_FLAG on an
> existing page, you can only set the flag by mapping new memory into
> place. That is a piece of the security model.
>
> The purpose of this change is to twart stack pivots, which apparently
> have gained some popularity in JIT ROP attacks. It makes it difficult
> to place the ROP stack in regular data memory, and then perform a
> system call from it. Workarounds are cumbersome, increasing the need
> for far more gadgetry. But also the trap case -- if any memory
> experiences a demand page fault, the same check will occur and
> potentially also kill the process.
>
> We have experimented a little with performing this check during device
> interrupts, but there are some locking concerns and performance may
> then become a concern. It'll be best to gain experience from handle
> of syncronous trap cases first.
>
> chrome and other applications I use run fine!
>
> I'm asking for some feedback to discover what ports this breaks, we'd
> like to know. Those would be ports which try to (unconvenionally)
> create their stacks in malloc()'d memory or inside another
> datastructure. Most of them are probably easily fixed ...
lang/sbcl will need a small patch:
$OpenBSD$
Index: src/runtime/thread.c
--- src/runtime/thread.c.orig
+++ src/runtime/thread.c
@@ -636,9 +636,16 @@ create_thread_struct(lispobj initial_function) {
* on the alignment passed from os_validate, since that might
* assume the current (e.g. 4k) pagesize, while we calculate with
* the biggest (e.g. 64k) pagesize allowed by the ABI. */
+#ifdef MAP_STACK
+ spaces = mmap(0, THREAD_STRUCT_SIZE, OS_VM_PROT_ALL,
+ MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
+ if(spaces == MAP_FAILED)
+ return NULL;
+#else
spaces=os_validate(0, THREAD_STRUCT_SIZE);
if(!spaces)
return NULL;
+#endif
/* Aligning up is safe as THREAD_STRUCT_SIZE has
* THREAD_ALIGNMENT_BYTES padding. */
aligned_spaces = (void *)((((uword_t)(char *)spaces)