Page MenuHomeFreeBSD

Prototype WITH_PIE knob
ClosedPublic

Authored by emaste on Dec 3 2018, 6:04 PM.
Tags
None
Referenced Files
Unknown Object (File)
Sat, Dec 14, 4:22 PM
Unknown Object (File)
Sat, Nov 30, 9:47 PM
Unknown Object (File)
Sat, Nov 23, 1:41 PM
Unknown Object (File)
Nov 20 2024, 9:19 AM
Unknown Object (File)
Nov 4 2024, 3:33 PM
Unknown Object (File)
Nov 4 2024, 3:12 PM
Unknown Object (File)
Oct 30 2024, 9:48 AM
Unknown Object (File)
Oct 27 2024, 11:38 AM

Details

Summary

Add WITH_PIE knob to build position-independent binaries

  • kerberos5/tools/asn1_compile and kerberos5/tools/slc/Makefile link non-internal/private libroken.a explicitly; set MK_PIE=no for them
  • build private and internal libs as PIC when WITH_PIE is set
  • never build i386 boot components as PIE

Diff Detail

Lint
Lint Skipped
Unit
Tests Skipped

Event Timeline

Presumably we should build INTERNALLIBs and PRIVATELIBs as both libfoo.a and libfoo_pic.a (or some similar scheme) and choose the appropriate one when linking the binary. I don't know how far down that path we want to go though.

Presumably we should build INTERNALLIBs and PRIVATELIBs as both libfoo.a and libfoo_pic.a (or some similar scheme) and choose the appropriate one when linking the binary. I don't know how far down that path we want to go though.

Yes, I argued that this is the only correct way. We must not build normal libXXX.a with PIC, but we do need libXXX_pic.a. Also, formally architectures can have different -fPIC and -fPIE ABIs, so perhaps we really need libXXX_pie.a, and e.g. libc_pic.a and libc_pie.a simultaneously.

Also, formally architectures can have different -fPIC and -fPIE ABIs, so perhaps we really need libXXX_pie.a, and e.g. libc_pic.a and libc_pie.a simultaneously.

Do you have a reference for this? At least for any architecture relevant to us today I don't think this is a practical case, so perhaps we ought to build _pic.a for PIE use for now, with a comment in bsd.lib.mk?

For reference I see PRIVATELIB or INTERNALLIB under:

  • gnu/usr.bin/binutils
  • gnu/usr.bin/cc
  • gnu/usr.bin/gdb
  • kerberos5/lib
  • lib/atf
  • lib/clang
  • lib/libbsdstat
  • lib/libdevdctl
  • lib/libelftc
  • lib/libevent
  • lib/libifconfig
  • lib/libldns
  • lib/libnetbsd
  • lib/libopenbsd
  • lib/libpe
  • lib/libpmcstat
  • lib/libsm
  • lib/libsmdb
  • lib/libsmutil
  • lib/libsqlite3
  • lib/libtelnet
  • lib/libucl
  • lib/libunbound
  • lib/libzstd
  • rescue
  • sbin/ipf
  • secure/lib/libssh
  • stand/liblua
  • stand/usb
  • tools/tools/net80211
  • usr.sbin/svn/lib
  • usr.sbin/amd
  • usr.sbin/bsnmpd
  • usr.sbin/cron
  • usr.sbin/fifolog
  • usr.sbin/lpr
  • usr.sbin/ntp

Multiple subdirectories under some of these elided, there are a total of 69.

We could of course build _pie.a or _pic.a versions of these libs only if the WITH_PIE knob is set. We could even build only the _pie.a or _pic.a version when set.

Also, formally architectures can have different -fPIC and -fPIE ABIs, so perhaps we really need libXXX_pie.a, and e.g. libc_pic.a and libc_pie.a simultaneously.

Do you have a reference for this? At least for any architecture relevant to us today I don't think this is a practical case, so perhaps we ought to build _pic.a for PIE use for now, with a comment in bsd.lib.mk?

-fPIE code does not need to redirect all its external symbol accesses through GOT/PLT. This does not matter for x86 at compile time, only at the link time, but it might give an opportunity to optimize for other arches. Also the default TLS model might be different.

This does not matter for x86 at compile time, only at the link time

Right, in particular I wonder if any architectures will do something different at compile time -- we need _pie.a vs _pic.a only if so.

Share the INSTALL_PIC_ARCHIVE logic to install libXXX_pic.a versions of INTERNALLIBs and PRIVATELIBs.

kerberos5/tools/asn1_compile/Makefile
9

We could instead build a libroken_pic.a and link against it, but it doesn't seem worth the effort.

share/mk/bsd.lib.mk
72–79

Moving this is not necessary now, will move back.

268

Perhaps rearrange this file to move SOBJS+= out of the INTERNALLIB block, but I think it's easier to leave it this way for development and review.

emaste added inline comments.
share/mk/bsd.lib.mk
270

Will remove PRIVATELIB from here, it should be redundant (PRIVATELIBs are installed .sos).

335

and remove PRIVATELIB from here.

In D18423#392118, @kib wrote:

Presumably we should build INTERNALLIBs and PRIVATELIBs as both libfoo.a and libfoo_pic.a (or some similar scheme) and choose the appropriate one when linking the binary. I don't know how far down that path we want to go though.

Yes, I argued that this is the only correct way. We must not build normal libXXX.a with PIC, but we do need libXXX_pic.a. Also, formally architectures can have different -fPIC and -fPIE ABIs, so perhaps we really need libXXX_pie.a, and e.g. libc_pic.a and libc_pie.a simultaneously.

What architectures would require having both a _pic.a and _pie.a? In a userland address space that addresses less than 48 bits (32-bit archs, fbsd/riscv), address space randomization is effectively useless. So, really, amd64, arm64, and mips64 are currently the only relevant architectures with respect to address space randomization and position-independent executables. If FreeBSD were to use SV64 instead of SV39 for riscv, then riscv would be in the picture, too.

This is suboptimal - consider this test code:

int global_variable;

int
lib_function1(int a)
{
        return (a + global_variable);
}

int
lib_function2(int a)
{
        return (lib_function1(a));
}

-fPIC causes Clang to emit a GOT access to global_variable and a PLT call to lib_function1 while -fPIE omits GOT and PLT use. (By comparison GCC emits GOT and PLT use in both cases.)

Demo: https://github.com/emaste/pic-pie
Clang diff: https://people.freebsd.org/~emaste/pic-pie/clang.html
GCC diff: https://people.freebsd.org/~emaste/pic-pie/gcc.html

So we'll want to build a separate _pie.a lib.

Compile objs with -fpie or -fPIE and use _pie suffix instead of reusing _pic build infrastructure as generated code may be different. (PIE objects do not need to support symbol interposition and thus avoid GOT/PLT use.)

libexec/rtld-elf/Makefile
11

Probably should have a comment explaining why this is here -- it's because rtld is already built PIC using bespoke logic.

share/mk/bsd.lib.mk
135

I'm cheating here and have omitted -DPIC from the C++ case, because Clang has function arguments named PIC. Probably the right approach is to leave -DPIC here and add CXXFLAGS+=-UPIC in the Makefile for Clang libs.

share/mk/bsd.opts.mk
64

Added to __DEFAULT_YES_OPTIONS in my tree for testing, would be disabled by default for commit (at least initially).

usr.bin/clang/clang.prog.mk
14–15

Maybe just use MK_PIE:= no for now

usr.bin/svn/Makefile.inc
41–43

Maybe just MK_PIE:=no for now

share/mk/bsd.lib.mk
135

In my opinion, we should stop defining PIC, and just use __PIC__ instead, which is automatically defined by the compiler when you compile in PIC mode. This kind of identifier can always clash with contributed code.

share/mk/bsd.lib.mk
135

Sounds good to me. I'll leave it out of the C++ .pieo case.

Just turn off PIE for clang and svn (their Makefiles explicitly reference .a archives and need invasive changes to add ${PIE_SUFFIX} - that may come in a later commit but this smaller change is easier to review.

I believe this is ready to commit now (disabled by default); commit message:

Add WITH_PIE knob to build base system as Position Independent Executables

Building binaries as PIE allows the executable itself to be loaded at a
random address with ASLR enabled, not just its shared libraries.

PIE objects have a .pieo extension and INTERNALLIB libraries 
libXXX_pie.a.

MK_PIE is disabled for some kerberos5 tools, Clang, and Subversion, as 
they explicitly reference .a libraries in their Makefiles.  These can 
be addressed on an individual basis later.  MK_PIE is also disabled for
rtld-elf because it is already position-independent using bespoke
Makefile rules.

I believe this is ready to commit now (disabled by default); commit message:

Do static binaries work ? I suspect they do not, or they work by a chance. Most scary is init(8) of course, but other static binaries esp. rescue(8) are also questionable.

In D18423#410852, @kib wrote:

Do static binaries work ? I suspect they do not, or they work by a chance. Most scary is init(8) of course, but other static binaries esp. rescue(8) are also questionable.

Untested, the intent is that the knob applies only to dynamically linked binaries in this iteration. There was indeed a bug in bsd.prog.mk though, will be updated shortly.

This revision is now accepted and ready to land.Feb 15 2019, 7:06 PM
This revision was automatically updated to reflect the committed changes.