Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Date: Sat, 4 Apr 2015 23:44:12 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: The path to building libc with stack protector

Since having libc itself built with stack protector would have
rendered CVE-2015-1817 at-most-DoS, I've added ssp in libc to the
roadmap for this release cycle and started working on how to achieve
it. The core difficulty is avoiding running code that depends on the
stack protector canary being setup/available before it actually is.
Since the way the canary is accessed varies by arch and there are two
main methods (and some archs even support both as runtime options):

1. Thread-local canary at a fixed offset from the thread pointer. This
   requires the thread pointer to be setup.

2. Global variable storing canary. This requires symbol relocations to
   have been performed.

Both are basically non-issues for static linking; we can just build
__libc_start_main.c, __stack_chk_fail.c, and __init_tls.c without
stack protector and all is well.

Dynamic linking is much harder for both cases.

For variant 1 (TLS), we can't know the size of TLS needed until all
libraries are loaded, but by that time we've already called a lot of
code that needs to be protected by stack protector. The only solution
I see here is to initialize the thread pointer twice. We can aim to
optimize out the second call as long as the final TLS fits in the
builtin_tls object and doesn't have increased alignment requirements,
reducing the runtime cost a bit, but in general we may need to perform
the operation twice. In any case, I consider this a solved problem.

For variant 2 (global), things are much harder. The final location
where the global will reside cannot be known until the main program's
relocations are processed, since there may be a copy relocation. And
if the dynamic linker is being used as a command to load the main
program, it needs to make a number of calls before the main program is
even loaded. So I see no clean solution except to do tentative
relocations early and possibly override them later. We could do this
only for the __stack_chk_guard symbol, or for all symbols in libc.

I would really prefer to do the latter -- tentatively resolve all
relocations in libc.so before doing anything else. This would have a
number of additional benefits besides making ssp-libc possible:

- We would be immune to poor compiler and linker choices whether to
  use PC-relative or GOT-based access and whether to resolve these
  references at ld time or leave them for the dynamic linker; old
  toolchains without -Bsymbolic-functions should even work.

- It lets us setup a true compiler barrier between GOT relocation and
  GOT accesses. Right now, the compiler can theoretically load
  addresses from the GOT (and cache them in registers or on the stack
  for later use) before the GOT is relocated.

- It might allow us to reduce or eliminate the need for arch-specific
  early relocation code like mips, powerpc, and microblaze use now.

- It eliminates the undocumented and fragile assumptions the dynamic
  linker makes about what functions it can call early. Right now, it
  can't call anything that depends on relocations having been
  performed, so for instance it can't use any of the standard stdio
  FILE streams because these objects contain function pointers. This
  would also allow us to eliminate the static wrap_write function in
  vfprintf.c and other similar hacks.

- We could allow symbol interposition if we want, e.g. replacing
  malloc (of course other major remain for that one).

One complication of doing early relocations that might need to be
replaced later is that, on archs without RELA, the original addend is
clobbered when the relocation is performed. Fortunately, PLT and GOT
type relocations don't have addends, and these seem to be the only
ones we'd actually need to re-do later.

The above is all just high-level conceptual. Actually implementing
this cleanly is still a pretty big task, and I might end up making a
lot of cleanup/overhaul in the dynamic linker in the process. I'll
keep posting more updates on design ideas as I make progress on it.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.