All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms
@ 2016-06-17 14:11 Peter Maydell
  2016-06-17 16:12 ` Richard Henderson
  2016-06-18 13:55 ` Laszlo Ersek
  0 siblings, 2 replies; 6+ messages in thread
From: Peter Maydell @ 2016-06-17 14:11 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Aurelien Jarno, Leon Alrae, Michael Tokarev,
	Daniel P. Berrange, Paolo Bonzini, Richard Henderson

Some architectures require the stack to be executable; notably
this includes MIPS, because the kernel's floating point emulator
may try to put trampoline code on the stack to handle some cases.
(See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815409
for an example of this causing QEMU to crash.)

Create a utility function qemu_alloc_stack() which allocates a
block of memory for use as a stack with the correct permissions.
Since we would prefer to make the stack non-executable if we can
as a defence against code execution exploits, we detect whether
the existing stack is mapped executable. Unfortunately this
requires us to grovel through /proc/self/maps to determine the
permissions on it.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
This method of figuring out the correct perms for the stack is
not exactly pretty; better suggestions welcome.

NB that this utility function also gives us a handy place to put
code for allocating a guard page at the bottom of the stack, or
mapping it as MAP_GROWSDOWN, or whatever.
---
 include/sysemu/os-posix.h    | 12 ++++++++
 util/coroutine-sigaltstack.c |  2 +-
 util/coroutine-ucontext.c    |  2 +-
 util/oslib-posix.c           | 70 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
index 9c7dfdf..1dc9d3c 100644
--- a/include/sysemu/os-posix.h
+++ b/include/sysemu/os-posix.h
@@ -60,4 +60,16 @@ int qemu_utimens(const char *path, const qemu_timespec *times);
 
 bool is_daemonized(void);
 
+/**
+ * qemu_alloc_stack:
+ * @sz: size of required stack in bytes
+ *
+ * Allocate memory that can be used as a stack, for instance for
+ * coroutines. If the memory cannot be allocated, this function
+ * will abort (like g_malloc()).
+ *
+ * Returns: pointer to (the lowest address of) the stack memory.
+ */
+void *qemu_alloc_stack(size_t sz);
+
 #endif
diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c
index a7c3366..209f6e5 100644
--- a/util/coroutine-sigaltstack.c
+++ b/util/coroutine-sigaltstack.c
@@ -164,7 +164,7 @@ Coroutine *qemu_coroutine_new(void)
      */
 
     co = g_malloc0(sizeof(*co));
-    co->stack = g_malloc(stack_size);
+    co->stack = qemu_alloc_stack(stack_size);
     co->base.entry_arg = &old_env; /* stash away our jmp_buf */
 
     coTS = coroutine_get_thread_state();
diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
index 2bb7e10..a455519 100644
--- a/util/coroutine-ucontext.c
+++ b/util/coroutine-ucontext.c
@@ -101,7 +101,7 @@ Coroutine *qemu_coroutine_new(void)
     }
 
     co = g_malloc0(sizeof(*co));
-    co->stack = g_malloc(stack_size);
+    co->stack = qemu_alloc_stack(stack_size);
     co->base.entry_arg = &old_env; /* stash away our jmp_buf */
 
     uc.uc_link = &old_uc;
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index e2e1d4d..311093e 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -497,3 +497,73 @@ pid_t qemu_fork(Error **errp)
     }
     return pid;
 }
+
+#if defined(__linux__)
+static int stack_prot(void)
+{
+    static int prot;
+    gchar *maps, *start, *end;
+
+    if (prot) {
+        return prot;
+    }
+
+    /* Some architectures (notably MIPS) require an executable stack, but
+     * we would prefer to avoid making the stack executable unnecessarily,
+     * to defend against code execution exploits.
+     * Check whether the current stack is executable, and follow its lead.
+     * Unfortunately to do this we have to wade through /proc/self/maps
+     * looking for the stack memory. We default to assuming we need an
+     * executable stack and remove the permission only if we can successfully
+     * confirm that non-executable is OK.
+     */
+
+    prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+
+    if (!g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) {
+        return prot;
+    }
+
+    /* We are looking for a line like this:
+     *  7fffbe217000-7fffbe238000 rw-p 00000000 00:00 0          [stack]
+     * and checking whether it says 'rw-' or 'rwx'.
+     * We look forwards for [stack], then back to the preceding newline,
+     * then forwards for the rw- between the two.
+     */
+    end = g_strstr_len(maps, -1, "[stack]");
+    if (!end) {
+        return prot;
+    }
+    start = g_strrstr_len(maps, end - maps, "\n");
+    if (!start) {
+        start = maps;
+    }
+    if (g_strstr_len(start, end - start, "rw-")) {
+        prot &= ~PROT_EXEC;
+    }
+
+    return prot;
+}
+
+#else
+static int stack_prot(void)
+{
+    /* Assume an executable stack is needed, since we can't detect it. */
+    return PROT_READ | PROT_WRITE | PROT_EXEC;
+}
+#endif
+
+void *qemu_alloc_stack(size_t sz)
+{
+    /* Allocate memory for the coroutine's stack.
+     * Note that some architectures require this to be executable.
+     */
+    int prot = stack_prot();
+    void *stack = mmap(NULL, sz, prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+
+    if (stack == MAP_FAILED) {
+        g_error("%s: failed to allocate %zu bytes", __func__, sz);
+    }
+
+    return stack;
+}
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms
  2016-06-17 14:11 [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms Peter Maydell
@ 2016-06-17 16:12 ` Richard Henderson
  2016-06-17 16:36   ` Peter Maydell
  2016-06-18 13:55 ` Laszlo Ersek
  1 sibling, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2016-06-17 16:12 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Aurelien Jarno, Leon Alrae, Michael Tokarev,
	Daniel P. Berrange, Paolo Bonzini

On 06/17/2016 07:11 AM, Peter Maydell wrote:
> Some architectures require the stack to be executable; notably
> this includes MIPS, because the kernel's floating point emulator
> may try to put trampoline code on the stack to handle some cases.
> (See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815409
> for an example of this causing QEMU to crash.)
> 
> Create a utility function qemu_alloc_stack() which allocates a
> block of memory for use as a stack with the correct permissions.
> Since we would prefer to make the stack non-executable if we can
> as a defence against code execution exploits, we detect whether
> the existing stack is mapped executable. Unfortunately this
> requires us to grovel through /proc/self/maps to determine the
> permissions on it.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> This method of figuring out the correct perms for the stack is
> not exactly pretty; better suggestions welcome.
> 
> NB that this utility function also gives us a handy place to put
> code for allocating a guard page at the bottom of the stack, or
> mapping it as MAP_GROWSDOWN, or whatever.
...
> +    /* Some architectures (notably MIPS) require an executable stack, but
> +     * we would prefer to avoid making the stack executable unnecessarily,
> +     * to defend against code execution exploits.
> +     * Check whether the current stack is executable, and follow its lead.
> +     * Unfortunately to do this we have to wade through /proc/self/maps
> +     * looking for the stack memory. We default to assuming we need an
> +     * executable stack and remove the permission only if we can successfully
> +     * confirm that non-executable is OK.
> +     */
> +
> +    prot = PROT_READ | PROT_WRITE | PROT_EXEC;
...
> +#else
> +static int stack_prot(void)
> +{
> +    /* Assume an executable stack is needed, since we can't detect it. */
> +    return PROT_READ | PROT_WRITE | PROT_EXEC;
> +}
> +#endif


What about using dl_iterate_phdr, looking for PT_GNU_STACK?
That interface is present on a few other hosts besides Linux.

But really this is a place that I'd much rather fall back to an ifdef ladder
than assume executable permission is required.


r~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms
  2016-06-17 16:12 ` Richard Henderson
@ 2016-06-17 16:36   ` Peter Maydell
  2016-06-17 17:27     ` Richard Henderson
  0 siblings, 1 reply; 6+ messages in thread
From: Peter Maydell @ 2016-06-17 16:36 UTC (permalink / raw)
  To: Richard Henderson
  Cc: QEMU Developers, Patch Tracking, Aurelien Jarno, Leon Alrae,
	Michael Tokarev, Daniel P. Berrange, Paolo Bonzini

On 17 June 2016 at 17:12, Richard Henderson <rth@twiddle.net> wrote:
> What about using dl_iterate_phdr, looking for PT_GNU_STACK?
> That interface is present on a few other hosts besides Linux.

We could do that. I note that the MIPS kernel is buggy in that
it will assume the stack is executable even if the binary
has PT_GNU_STACK saying "please don't be executable". And
most architectures except x86-64 won't honour PT_GNU_STACK=non-exec
unless the parent process also had nonexec stack (because they
let the READ_IMPLIES_EXEC personality flag be inherited; see
https://insights.sei.cmu.edu/cert/2014/02/feeling-insecure-blame-your-parent.html
). So the PT_GNU_STACK flag doesn't necessarily match up with
either the actual executability of the standard stack or with
what the kernel actually requires.

> But really this is a place that I'd much rather fall back to an ifdef ladder
> than assume executable permission is required.

The trouble with this is that it means that as and when the MIPS
folks fix their kernel and libc and compiler to support non-exec
stacks we won't automatically pick this up, and our stacks will
remain executable. Also it requires us to audit every architecture
to find out which ones require exec-stack. But maybe it is just
MIPS? (Maybe we could just say "this is a MIPS kernel bug" ? :-))

thanks
-- PMM

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms
  2016-06-17 16:36   ` Peter Maydell
@ 2016-06-17 17:27     ` Richard Henderson
  2016-06-17 17:32       ` Peter Maydell
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Henderson @ 2016-06-17 17:27 UTC (permalink / raw)
  To: Peter Maydell
  Cc: QEMU Developers, Patch Tracking, Aurelien Jarno, Leon Alrae,
	Michael Tokarev, Daniel P. Berrange, Paolo Bonzini

On 06/17/2016 09:36 AM, Peter Maydell wrote:
> On 17 June 2016 at 17:12, Richard Henderson <rth@twiddle.net> wrote:
>> What about using dl_iterate_phdr, looking for PT_GNU_STACK?
>> That interface is present on a few other hosts besides Linux.
> 
> We could do that. I note that the MIPS kernel is buggy in that
> it will assume the stack is executable even if the binary
> has PT_GNU_STACK saying "please don't be executable". And
> most architectures except x86-64 won't honour PT_GNU_STACK=non-exec
> unless the parent process also had nonexec stack (because they
> let the READ_IMPLIES_EXEC personality flag be inherited; see
> https://insights.sei.cmu.edu/cert/2014/02/feeling-insecure-blame-your-parent.html
> ). So the PT_GNU_STACK flag doesn't necessarily match up with
> either the actual executability of the standard stack or with
> what the kernel actually requires.

How bizarre.

Glibc will most definitely honour PT_GNU_STACK when allocating thread stacks,
so it's a weird thing for the kernel to want to inherit for the initial thread
stack.

>> But really this is a place that I'd much rather fall back to an ifdef ladder
>> than assume executable permission is required.
> 
> The trouble with this is that it means that as and when the MIPS
> folks fix their kernel and libc and compiler to support non-exec
> stacks we won't automatically pick this up, and our stacks will
> remain executable. Also it requires us to audit every architecture
> to find out which ones require exec-stack. But maybe it is just
> MIPS? (Maybe we could just say "this is a MIPS kernel bug" ? :-))

I am inclined to hope that this is just a mips thing.
It's a pretty strange situation.

But I did really mean fall back.  Yes, try the other methods, but if we don't
detect anything about the stack, only enable it via ifdef ladder.


r~

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms
  2016-06-17 17:27     ` Richard Henderson
@ 2016-06-17 17:32       ` Peter Maydell
  0 siblings, 0 replies; 6+ messages in thread
From: Peter Maydell @ 2016-06-17 17:32 UTC (permalink / raw)
  To: Richard Henderson
  Cc: QEMU Developers, Patch Tracking, Aurelien Jarno, Leon Alrae,
	Michael Tokarev, Daniel P. Berrange, Paolo Bonzini

On 17 June 2016 at 18:27, Richard Henderson <rth@twiddle.net> wrote:
> On 06/17/2016 09:36 AM, Peter Maydell wrote:
>> And
>> most architectures except x86-64 won't honour PT_GNU_STACK=non-exec
>> unless the parent process also had nonexec stack (because they
>> let the READ_IMPLIES_EXEC personality flag be inherited; see
>> https://insights.sei.cmu.edu/cert/2014/02/feeling-insecure-blame-your-parent.html
>> ). So the PT_GNU_STACK flag doesn't necessarily match up with
>> either the actual executability of the standard stack or with
>> what the kernel actually requires.
>
> How bizarre.
>
> Glibc will most definitely honour PT_GNU_STACK when allocating thread stacks,
> so it's a weird thing for the kernel to want to inherit for the initial thread
> stack.

I agree. I think it's a bug in the non-x86-64 architectures
(and particularly annoying if /sbin/init happens to not be
marked as being ok for non-exec stack).

>>> But really this is a place that I'd much rather fall back to an ifdef ladder
>>> than assume executable permission is required.
>>
>> The trouble with this is that it means that as and when the MIPS
>> folks fix their kernel and libc and compiler to support non-exec
>> stacks we won't automatically pick this up, and our stacks will
>> remain executable. Also it requires us to audit every architecture
>> to find out which ones require exec-stack. But maybe it is just
>> MIPS? (Maybe we could just say "this is a MIPS kernel bug" ? :-))
>
> I am inclined to hope that this is just a mips thing.
> It's a pretty strange situation.
>
> But I did really mean fall back.  Yes, try the other methods, but
> if we don't detect anything about the stack, only enable it via
> ifdef ladder.

Oh, I see.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms
  2016-06-17 14:11 [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms Peter Maydell
  2016-06-17 16:12 ` Richard Henderson
@ 2016-06-18 13:55 ` Laszlo Ersek
  1 sibling, 0 replies; 6+ messages in thread
From: Laszlo Ersek @ 2016-06-18 13:55 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: patches, Michael Tokarev, Paolo Bonzini, Leon Alrae,
	Aurelien Jarno, Richard Henderson

On 06/17/16 16:11, Peter Maydell wrote:
> Some architectures require the stack to be executable; notably
> this includes MIPS, because the kernel's floating point emulator
> may try to put trampoline code on the stack to handle some cases.
> (See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815409
> for an example of this causing QEMU to crash.)
> 
> Create a utility function qemu_alloc_stack() which allocates a
> block of memory for use as a stack with the correct permissions.
> Since we would prefer to make the stack non-executable if we can
> as a defence against code execution exploits, we detect whether
> the existing stack is mapped executable. Unfortunately this
> requires us to grovel through /proc/self/maps to determine the
> permissions on it.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> This method of figuring out the correct perms for the stack is
> not exactly pretty; better suggestions welcome.
> 
> NB that this utility function also gives us a handy place to put
> code for allocating a guard page at the bottom of the stack, or
> mapping it as MAP_GROWSDOWN, or whatever.
> ---
>  include/sysemu/os-posix.h    | 12 ++++++++
>  util/coroutine-sigaltstack.c |  2 +-
>  util/coroutine-ucontext.c    |  2 +-
>  util/oslib-posix.c           | 70 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 84 insertions(+), 2 deletions(-)
> 
> diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
> index 9c7dfdf..1dc9d3c 100644
> --- a/include/sysemu/os-posix.h
> +++ b/include/sysemu/os-posix.h
> @@ -60,4 +60,16 @@ int qemu_utimens(const char *path, const qemu_timespec *times);
>  
>  bool is_daemonized(void);
>  
> +/**
> + * qemu_alloc_stack:
> + * @sz: size of required stack in bytes
> + *
> + * Allocate memory that can be used as a stack, for instance for
> + * coroutines. If the memory cannot be allocated, this function
> + * will abort (like g_malloc()).
> + *
> + * Returns: pointer to (the lowest address of) the stack memory.
> + */
> +void *qemu_alloc_stack(size_t sz);
> +
>  #endif
> diff --git a/util/coroutine-sigaltstack.c b/util/coroutine-sigaltstack.c
> index a7c3366..209f6e5 100644
> --- a/util/coroutine-sigaltstack.c
> +++ b/util/coroutine-sigaltstack.c
> @@ -164,7 +164,7 @@ Coroutine *qemu_coroutine_new(void)
>       */
>  
>      co = g_malloc0(sizeof(*co));
> -    co->stack = g_malloc(stack_size);
> +    co->stack = qemu_alloc_stack(stack_size);
>      co->base.entry_arg = &old_env; /* stash away our jmp_buf */
>  
>      coTS = coroutine_get_thread_state();
> diff --git a/util/coroutine-ucontext.c b/util/coroutine-ucontext.c
> index 2bb7e10..a455519 100644
> --- a/util/coroutine-ucontext.c
> +++ b/util/coroutine-ucontext.c
> @@ -101,7 +101,7 @@ Coroutine *qemu_coroutine_new(void)
>      }
>  
>      co = g_malloc0(sizeof(*co));
> -    co->stack = g_malloc(stack_size);
> +    co->stack = qemu_alloc_stack(stack_size);
>      co->base.entry_arg = &old_env; /* stash away our jmp_buf */
>  
>      uc.uc_link = &old_uc;
> diff --git a/util/oslib-posix.c b/util/oslib-posix.c
> index e2e1d4d..311093e 100644
> --- a/util/oslib-posix.c
> +++ b/util/oslib-posix.c
> @@ -497,3 +497,73 @@ pid_t qemu_fork(Error **errp)
>      }
>      return pid;
>  }
> +
> +#if defined(__linux__)
> +static int stack_prot(void)
> +{
> +    static int prot;
> +    gchar *maps, *start, *end;
> +
> +    if (prot) {
> +        return prot;
> +    }
> +
> +    /* Some architectures (notably MIPS) require an executable stack, but
> +     * we would prefer to avoid making the stack executable unnecessarily,
> +     * to defend against code execution exploits.
> +     * Check whether the current stack is executable, and follow its lead.
> +     * Unfortunately to do this we have to wade through /proc/self/maps
> +     * looking for the stack memory. We default to assuming we need an
> +     * executable stack and remove the permission only if we can successfully
> +     * confirm that non-executable is OK.
> +     */
> +
> +    prot = PROT_READ | PROT_WRITE | PROT_EXEC;
> +
> +    if (!g_file_get_contents("/proc/self/maps", &maps, NULL, NULL)) {
> +        return prot;
> +    }
> +
> +    /* We are looking for a line like this:
> +     *  7fffbe217000-7fffbe238000 rw-p 00000000 00:00 0          [stack]
> +     * and checking whether it says 'rw-' or 'rwx'.
> +     * We look forwards for [stack], then back to the preceding newline,
> +     * then forwards for the rw- between the two.
> +     */
> +    end = g_strstr_len(maps, -1, "[stack]");
> +    if (!end) {
> +        return prot;
> +    }
> +    start = g_strrstr_len(maps, end - maps, "\n");
> +    if (!start) {
> +        start = maps;
> +    }
> +    if (g_strstr_len(start, end - start, "rw-")) {
> +        prot &= ~PROT_EXEC;
> +    }
> +
> +    return prot;
> +}
> +
> +#else
> +static int stack_prot(void)
> +{
> +    /* Assume an executable stack is needed, since we can't detect it. */
> +    return PROT_READ | PROT_WRITE | PROT_EXEC;
> +}
> +#endif
> +
> +void *qemu_alloc_stack(size_t sz)
> +{
> +    /* Allocate memory for the coroutine's stack.
> +     * Note that some architectures require this to be executable.
> +     */
> +    int prot = stack_prot();
> +    void *stack = mmap(NULL, sz, prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +
> +    if (stack == MAP_FAILED) {
> +        g_error("%s: failed to allocate %zu bytes", __func__, sz);
> +    }
> +
> +    return stack;
> +}
> 

Shouldn't you adapt the qemu_coroutine_delete() functions in
"util/coroutine-sigaltstack.c" and "util/coroutine-ucontext.c"? Both of
those call g_free(co->stack). I think a qemu_free_stack() function,
calling munmap(), is necessary.

Thanks,
Laszlo

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2016-06-18 13:55 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-17 14:11 [Qemu-devel] [PATCH] oslib-posix: New qemu_alloc_stack() to allocate stack with correct perms Peter Maydell
2016-06-17 16:12 ` Richard Henderson
2016-06-17 16:36   ` Peter Maydell
2016-06-17 17:27     ` Richard Henderson
2016-06-17 17:32       ` Peter Maydell
2016-06-18 13:55 ` Laszlo Ersek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.