Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20161204164708.GC5749@port70.net>
Date: Sun, 4 Dec 2016 17:47:08 +0100
From: Szabolcs Nagy <nsz@...t70.net>
To: Thomas Petazzoni <thomas.petazzoni@...e-electrons.com>
Cc: Rich Felker <dalias@...c.org>, musl@...ts.openwall.com
Subject: Re: [resend] Solving the SSP+PIE issue on i386: recommended solution

* Thomas Petazzoni <thomas.petazzoni@...e-electrons.com> [2016-12-04 16:38:57 +0100]:
> Buildroot is facing the well-known __stack_chk_fail_local unresolved
> symbol issue when PIE executables are built on i386. We have this issue
> at least when building openssh, cups and ipmiutil (and possible other
> packages which build their code as PIE by default, for one reason or
> another).
> 
> However, the solution to this problem is not very clear:
> 
>  - It seems like Alpine Linux [1] and OpenWRT [2] have chosen to build a
>    small piece of code implementing __stack_chk_fail_local() and build
>    it into a libssp_nonshared.a library.
> 
>    However, it is not clear to me why the __stack_chk_fail_local()
>    symbol provided by musl in libc.so is not sufficient.
> 

this a gcc bug

on i386 (and powerpc) gcc can generate *local* calls to
__stack_chk_fail_local, so the symbol must be defined in the
binary that makes the call (not in an external library like
libc.so) this saves code size on targets where making an
extern call overhead: they call a local function first which
makes the heavy extern call (otherwise every canary check
failure path would need to do the heavy extern call in every
function).

musl defines this symbol because musl itself can be built
with stack protection (and for static linking).

ideally if the compiler generates local calls as an optimization,
then it is the compiler runtime's job to make sure that call is
defined (i.e. it should be in libgcc.a that is static linked into
the binary).

>    [1] http://git.alpinelinux.org/cgit/aports/tree/main/musl/APKBUILD
>    [2] https://github.com/openwrt/openwrt/blob/master/toolchain/musl/patches/200-add_libssp_nonshared.patch
> 
>    I guess they are also patching the gcc LINK_SSP_SPEC to link with
>    ssp_nonshared. It's done in [3] for OpenWRT, and [4] for Alpine.
> 
>    [3] https://github.com/openwrt/openwrt/blob/master/toolchain/gcc/patches/5.3.0/230-musl_libssp.patch
>    [4] http://git.alpinelinux.org/cgit/aports/tree/main/gcc/gcc-6.1-musl-libssp.patch
> 
>  - On the other side, the musl-cross project seems to have taken a
>    different approach: they patch the LINK_SSP_SPEC of gcc to link with
>    libssp_nonshared, and they [5] claim that their patch, in
>    combination with commit 55d061f031085f24d138664c897791aebe9a2fab in
>    musl solves the problem.
> 
>    But how does it work? musl doesn't build/install a libssp_nonshared
>    library. If the fix is that simple, why are Alpine Linux and OpenWRT
>    producing on their own a minimal libssp_nonshared.a ?
> 

gcc did not do the right thing instead it has a (broken) libssp
implementation which includes a small libssp_nonshared.a and it
adds -lssp and -lssp_nonshared to the link spec when necessary.
but since libssp is broken the libc has to provide a sane ssp runtime.

so gcc allows the libc to implement ssp, but then it requires
the libc to provide the loccal symbol too which is not possible
(in case of dynamic linking). ..and it is a gcc internal target
specific optimization thing so it does not make sense to do this
in the libc even if it is possible.

what glibc does: the libc.so visible to ld is a linker script that
magically adds glibc's libssp_nonshared.a to the link command.
(and they build gcc with disabled libssp)
(of course this linker script can cause horrible pains and misery)

what musl does: implements the public api in libc.so, but requires
the compiler to provide the local definition. So e.g. you can build
gcc with libssp enabled which has libssp_nonshared.a or you can
provide one yourself.. but gcc does not add -lssp_nonshared if it
thinks the libc provides ssp, so that's why those patches are
needed: they add -lssp_nonshared back. (providing this lib yourself
is better since that avoids uselessly building and installing the
rest of libssp which can cause trouble if somebody accidentally
uses -lssp explicitly)

>    [5] https://github.com/GregorR/musl-gcc-patches/commit/43fc05be584b8fa7cff566045e8582c525212286
> 
> What is the recommended fix for this problem ?
> 

fix gcc to be saner.

- move __stack_chk_fail_local to libgcc.a (and only on the
  targets where it is actually generated), and fix up the
  link_spec in the driver (-lssp_nonshared is not needed
  anymore).

- have an option that does not generate any call at all:
  emitting a __builtin_trap instruction is safer and smaller
  than any form of extern call.

given the amount of hackery around this in gcc these are not
easy to do, i think alpine originally tried to do the right
thing but they run into bootstrapping problems when the
toolchain itself is built with ssp.

> Thanks a lot,
> 
> Thomas
> -- 
> Thomas Petazzoni, CTO, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

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.