[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 02/12] coroutine: support SafeStack in ucontext backend
From: |
Stefan Hajnoczi |
Subject: |
[PULL 02/12] coroutine: support SafeStack in ucontext backend |
Date: |
Wed, 24 Jun 2020 11:02:00 +0100 |
From: Daniele Buono <dbuono@linux.vnet.ibm.com>
LLVM's SafeStack instrumentation does not yet support programs that make
use of the APIs in ucontext.h
With the current implementation of coroutine-ucontext, the resulting
binary is incorrect, with different coroutines sharing the same unsafe
stack and producing undefined behavior at runtime.
This fix allocates an additional unsafe stack area for each coroutine,
and sets the new unsafe stack pointer before calling swapcontext() in
qemu_coroutine_new.
This is the only place where the pointer needs to be manually updated,
since sigsetjmp/siglongjmp are already instrumented by LLVM to properly
support SafeStack.
The additional stack is then freed in qemu_coroutine_delete.
Signed-off-by: Daniele Buono <dbuono@linux.vnet.ibm.com>
Message-id: 20200529205122.714-2-dbuono@linux.vnet.ibm.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/qemu/coroutine_int.h | 5 +++++
util/coroutine-ucontext.c | 28 ++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
diff --git a/include/qemu/coroutine_int.h b/include/qemu/coroutine_int.h
index bd6b0468e1..1da148552f 100644
--- a/include/qemu/coroutine_int.h
+++ b/include/qemu/coroutine_int.h
@@ -28,6 +28,11 @@
#include "qemu/queue.h"
#include "qemu/coroutine.h"
+#ifdef CONFIG_SAFESTACK
+/* Pointer to the unsafe stack, defined by the compiler */
+extern __thread void *__safestack_unsafe_stack_ptr;
+#endif
+
#define COROUTINE_STACK_SIZE (1 << 20)
typedef enum {
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
index 613f4c118e..f0b66320e1 100644
--- a/util/coroutine-ucontext.c
+++ b/util/coroutine-ucontext.c
@@ -45,6 +45,11 @@ typedef struct {
Coroutine base;
void *stack;
size_t stack_size;
+#ifdef CONFIG_SAFESTACK
+ /* Need an unsafe stack for each coroutine */
+ void *unsafe_stack;
+ size_t unsafe_stack_size;
+#endif
sigjmp_buf env;
void *tsan_co_fiber;
@@ -179,6 +184,10 @@ Coroutine *qemu_coroutine_new(void)
co = g_malloc0(sizeof(*co));
co->stack_size = COROUTINE_STACK_SIZE;
co->stack = qemu_alloc_stack(&co->stack_size);
+#ifdef CONFIG_SAFESTACK
+ co->unsafe_stack_size = COROUTINE_STACK_SIZE;
+ co->unsafe_stack = qemu_alloc_stack(&co->unsafe_stack_size);
+#endif
co->base.entry_arg = &old_env; /* stash away our jmp_buf */
uc.uc_link = &old_uc;
@@ -203,6 +212,22 @@ Coroutine *qemu_coroutine_new(void)
COROUTINE_YIELD,
&fake_stack_save,
co->stack, co->stack_size, co->tsan_co_fiber);
+
+#ifdef CONFIG_SAFESTACK
+ /*
+ * Before we swap the context, set the new unsafe stack
+ * The unsafe stack grows just like the normal stack, so start from
+ * the last usable location of the memory area.
+ * NOTE: we don't have to re-set the usp afterwards because we are
+ * coming back to this context through a siglongjmp.
+ * The compiler already wrapped the corresponding sigsetjmp call with
+ * code that saves the usp on the (safe) stack before the call, and
+ * restores it right after (which is where we return with siglongjmp).
+ */
+ void *usp = co->unsafe_stack + co->unsafe_stack_size;
+ __safestack_unsafe_stack_ptr = usp;
+#endif
+
swapcontext(&old_uc, &uc);
}
@@ -235,6 +260,9 @@ void qemu_coroutine_delete(Coroutine *co_)
#endif
qemu_free_stack(co->stack, co->stack_size);
+#ifdef CONFIG_SAFESTACK
+ qemu_free_stack(co->unsafe_stack, co->unsafe_stack_size);
+#endif
g_free(co);
}
--
2.26.2
- [PULL 00/12] Block patches, Stefan Hajnoczi, 2020/06/24
- [PULL 01/12] minikconf: explicitly set encoding to UTF-8, Stefan Hajnoczi, 2020/06/24
- [PULL 02/12] coroutine: support SafeStack in ucontext backend,
Stefan Hajnoczi <=
- [PULL 03/12] coroutine: add check for SafeStack in sigaltstack, Stefan Hajnoczi, 2020/06/24
- [PULL 04/12] configure: add flags to support SafeStack, Stefan Hajnoczi, 2020/06/24
- [PULL 05/12] check-block: enable iotests with SafeStack, Stefan Hajnoczi, 2020/06/24
- [PULL 06/12] block/nvme: poll queues without q->lock, Stefan Hajnoczi, 2020/06/24
- [PULL 07/12] block/nvme: drop tautologous assertion, Stefan Hajnoczi, 2020/06/24
- [PULL 08/12] block/nvme: don't access CQE after moving cq.head, Stefan Hajnoczi, 2020/06/24
- [PULL 09/12] block/nvme: switch to a NVMeRequest freelist, Stefan Hajnoczi, 2020/06/24
- [PULL 10/12] block/nvme: clarify that free_req_queue is protected by q->lock, Stefan Hajnoczi, 2020/06/24
- [PULL 11/12] block/nvme: keep BDRVNVMeState pointer in NVMeQueuePair, Stefan Hajnoczi, 2020/06/24
- [PULL 12/12] block/nvme: support nested aio_poll(), Stefan Hajnoczi, 2020/06/24