This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH 05/14 v6] Open-code the memcpy() at static TLS initialization time.
- From: Florian Weimer <fweimer at redhat dot com>
- To: Nix <nix at esperi dot org dot uk>, libc-alpha at sourceware dot org
- Cc: Nick Alcock <nick dot alcock at oracle dot com>
- Date: Fri, 24 Jun 2016 14:42:02 +0200
- Subject: Re: [PATCH 05/14 v6] Open-code the memcpy() at static TLS initialization time.
- Authentication-results: sourceware.org; auth=none
- References: <1465297576-10981-1-git-send-email-nix at esperi dot org dot uk> <1465297576-10981-6-git-send-email-nix at esperi dot org dot uk>
On 06/07/2016 01:06 PM, Nix wrote:
From: Nick Alcock <nick.alcock@oracle.com>
This one is a bit nasty. Now that we are initializing TLS earlier for
the stack canary's sake, existing memcpy() implementations become
problematic. We can use the multiarch implementations, but they might
not always be present, and even if they are present they might not always
be in assembler, so might be compiled with stack-protection. We cannot
use posix/memcpy.c without marking both it and */wordcopy.c as non-stack-
protected, which for memcpy() of all things seems like a seriously bad
idea: if any function in glibc should be stack-protected, it's memcpy()
(though stack-protecting the many optimized assembly versions is not done
in this patch series).
Some of the pathnames in this explanation appear to be incorrect.
I looked at the memcpy.c and wordcopy.c implementations, and I do not
see why these functions would need the stack protector. They should not
have addressable local variables, they should all be in registers. As a
result, the implementation should never derive a pointer from the
current stack frame.
These functions might be passed pointers into the callers stack frame,
but the memory looks like this (addresses increase from bottom to top,
so the stack grows downwards on most architectures (except HPPA)):
: :
+-----------------------------+
| Caller stack frame |
| |
| (end of buf) |
| : |
| : |
| char buf[64]; |
| |
+-----------------------------+
| Return address |
| memcpy stack frame |
| |
+-(current top of stack)------+
: :
+=============================+
| XXX guard page XXXXXXXXXXXX |
: :
As a result, a buffer overflow will run away from the return address
associated with the memcpy activation frame. To avoid that, you'd need
a memcpy call with a destination address which points below the current
top of stack before memcpy is called, that is an invalid, dangling
pointer. A random pointer with an excessive size is unlikely to work
because the copying operation would eventually hit the guard page below
the stack. This is not a straight stack-based overflow anymore, and not
something stack protector can help with.
(Attacks against runaway memcpy calls (with size arguments approaching
SIZE_MAX) work against some memcpy implementations not because these
implementations lack stack protector, but because they load variables
from the stack in the inner loop, which may have been overwritten by
attacker-controlled values.)
Anyway, if the above analysis is right, it should be safe to disable
stack protector for functions such as memcpy (essentially doing manually
what -fstack-protector-strong does automatically). This would be my
preferred approach here.
Thanks,
Florian