Page MenuHomeFreeBSD

Activate relro and bindnow in build system
AbandonedPublic

Authored by bapt on Jul 6 2015, 9:01 AM.

Details

Reviewers
pfg
imp
Group Reviewers
security
Summary

RELRO feature support has been added to our linker in early 2012 by kib.

Given there is no know performances issues I do propose to activate it by default

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint OK
Unit
No Unit Test Coverage

Event Timeline

bapt retitled this revision from to Activate relro and bindnow in build system.
bapt updated this object.
bapt edited the test plan for this revision. (Show Details)
bapt added reviewers: security, imp.
op added a subscriber: HardenedBSD.
op added a subscriber: op.

-z now changes the symbol resolution model. Also it has performance penalty for large binaries.

In D3001#59077, @kib wrote:

Also it has performance penalty for large binaries.

Is the penalty for -z,relro, or for -z,now or for both? (I thought that relro is mainly marking the objects and penalty associated with it should be small, no?)

BTW. it looks like we are not write-protecting the PLT even when doing BIND_NOW?

In D3001#59077, @kib wrote:

Also it has performance penalty for large binaries.

Is the penalty for -z,relro, or for -z,now or for both? (I thought that relro is mainly marking the objects and penalty associated with it should be small, no?)

Never mind for this part, I misinterpreted '-z now changes' as '"-z" now changes' while you actually meant '"-z now" changes'.

In D3001#59077, @kib wrote:

Also it has performance penalty for large binaries.

Is the penalty for -z,relro, or for -z,now or for both? (I thought that relro is mainly marking the objects and penalty associated with it should be small, no?)

Performance impact of -z relro is negligible.

BTW. it looks like we are not write-protecting the PLT even when doing BIND_NOW?

GNU ld puts plt into the RX (not-writeable) segment even without -z relro, at least on x86. Plt does not need to be writeable, it references GOT (gotplt) entries which are patched by rtld during binding.

The thing is relro is pretty useless without BIND_NOW. After checking what I can see is that on linux what they do is activate relro on all binaries, and cherry-pick bind_now (like they do for PIE) only on binaries that already had a security issue in the past years.

Maybe I should only activate relro here, and add a mechanism to cherry pick bind_now

In D3001#59195, @bapt wrote:

The thing is relro is pretty useless without BIND_NOW. After checking what I can see is that on linux what they do is activate relro on all binaries, and cherry-pick bind_now (like they do for PIE) only on binaries that already had a security issue in the past years.

This is not completely true. Without -z now, the ctr/dtr and dynamic tables are still placed into the relro pages. Yes, without -z now, GOT usually cannot be placed into relro page.

Maybe I should only activate relro here, and add a mechanism to cherry pick bind_now

-z now probably should never be turned for for code which load plugins, without somebody asserting that nothing wrong happens. I think that nss is safe in this regard, but I am very much unsure about crazy tricks which could be done e.g. by perl xs modules.

Just an opinion ...
Going for the "partial" relro (without bindnow) seems like an obvious win.

In D3001#72044, @pfg wrote:

Just an opinion ...
Going for the "partial" relro (without bindnow) seems like an obvious win.

Agreed. Would it be a good idea to have bindnow as a WITH_* flag that defaults to off?

In D3001#72044, @pfg wrote:

Just an opinion ...
Going for the "partial" relro (without bindnow) seems like an obvious win.

Agreed. Would it be a good idea to have bindnow as a WITH_* flag that defaults to off?

I like this idea too.

In D3001#72044, @pfg wrote:

Just an opinion ...
Going for the "partial" relro (without bindnow) seems like an obvious win.

Agreed, is there any downside to turning on relro across the board?

In D3001#72626, @emaste wrote:
In D3001#72044, @pfg wrote:

Just an opinion ...
Going for the "partial" relro (without bindnow) seems like an obvious win.

Agreed, is there any downside to turning on relro across the board?

I can't see any downside.
We probably want to go step by step but perhaps doing it "across the board" would also mean updating the gcc specs and upstreaming the change (no idea how clang handles that)?

In D3001#72634, @pfg wrote:
In D3001#72626, @emaste wrote:
In D3001#72044, @pfg wrote:

Just an opinion ...
Going for the "partial" relro (without bindnow) seems like an obvious win.

Agreed, is there any downside to turning on relro across the board?

I can't see any downside.
We probably want to go step by step but perhaps doing it "across the board" would also mean updating the gcc specs and upstreaming the change (no idea how clang handles that)?

BTW, I found this link:
https://wiki.gentoo.org/wiki/Hardened/Toolchain#RELRO
See:
Toolchain modifications for default RELRO

Also:
"So far, the hardened project has found no issues with switching on RELRO by default. It can make the executable image a little bit bigger (on average by half a page i.e. 2K bytes) which may be of interest for targets with extremely limited memory. "

pfg requested changes to this revision.Sep 27 2015, 4:03 PM
pfg added a reviewer: pfg.

I don't like this approach:

  • First of all we don't want bindnow because it has many issues, it may be set conditionally but for now we can avoid it altogether.
  • I looked into how other OSs do RELRO and it appears to be common to add relro to the gcc specs: the approach is difficult to maintain with different compilers. I found that Redhat (CentOS) sets it as a default in the linker.

I adapted a patch to our binutils and I have asked for an exp-run (PR 203394) along with another change (stack-protector-strong) which may be expected to be of small/no impact.

Note that older GNU strip had issues with relro, so we should test BSD strip(1):

https://sourceware.org/bugzilla/show_bug.cgi?id=3015

This revision now requires changes to proceed.Sep 27 2015, 4:03 PM
In D3001#77165, @pfg wrote:

I don't like this approach:

  • First of all we don't want bindnow because it has many issues, it may be set conditionally but for now we can avoid it altogether.

I'm curious as to what those issues are.

In D3001#77165, @pfg wrote:

I don't like this approach:

  • First of all we don't want bindnow because it has many issues, it may be set conditionally but for now we can avoid it altogether.

I'm curious as to what those issues are.

Google is your friend ...

https://wiki.gentoo.org/wiki/Hardened/Toolchain#Issues_arising_from_default_NOW

In D3001#77165, @pfg wrote:

I don't like this approach:

  • First of all we don't want bindnow because it has many issues, it may be set conditionally but for now we can avoid it altogether.
  • I looked into how other OSs do RELRO and it appears to be common to add relro to the gcc specs: the approach is difficult to maintain with different compilers. I found that Redhat (CentOS) sets it as a default in the linker.

I adapted a patch to our binutils and I have asked for an exp-run (PR 203394) along with another change (stack-protector-strong) which may be expected to be of small/no impact.

Note that older GNU strip had issues with relro, so we should test BSD strip(1):

https://sourceware.org/bugzilla/show_bug.cgi?id=3015

I do not think it is reasonable to change default linker behaviour to diverge from the upstream. Not all linker trickery lives in ports, your change will certainly break some private code. Compare how less ABI-damaging --hash-style=gnu or similarly affecting --enable-new-dtags are handled.

When Linux/glibc people changed the value of --copy-dt-needed-entries, they did that with a year-long campaign to ensure that the transition went smooth. relro is lesser feature, but it still can damage someone.

In D3001#77174, @kib wrote:
In D3001#77165, @pfg wrote:

I don't like this approach:

  • First of all we don't want bindnow because it has many issues, it may be set conditionally but for now we can avoid it altogether.
  • I looked into how other OSs do RELRO and it appears to be common to add relro to the gcc specs: the approach is difficult to maintain with different compilers. I found that Redhat (CentOS) sets it as a default in the linker.

I adapted a patch to our binutils and I have asked for an exp-run (PR 203394) along with another change (stack-protector-strong) which may be expected to be of small/no impact.

Note that older GNU strip had issues with relro, so we should test BSD strip(1):

https://sourceware.org/bugzilla/show_bug.cgi?id=3015

I do not think it is reasonable to change default linker behaviour to diverge from the upstream. Not all linker trickery lives in ports, your change will certainly break some private code. Compare how less ABI-damaging --hash-style=gnu or similarly affecting --enable-new-dtags are handled.

I agree the change is controversial: we are indeed choosing between adding GNUisms to our build or maintaining an extra line in the linker.

For some reason Redhat (CentOS), which also owns sourceware, carries this patch and it seems more practical than the alternatives. Doing it as a build flag will leave all ports unaffected unless we add the new ldflags also to the ports tree.

When Linux/glibc people changed the value of --copy-dt-needed-entries, they did that with a year-long campaign to ensure that the transition went smooth. relro is lesser feature, but it still can damage someone.

Private code can still disable relro, but I see your point.

Nevertheless, it still will be interesting to see, through the exp-run, how ports react to having relro by default.

In D3001#77189, @pfg wrote:

Private code can still disable relro, but I see your point.

Nevertheless, it still will be interesting to see, through the exp-run, how ports react to having relro by default.

You would only see a half of the interesting things, at best. Another half happens at runtime, which cannot be tested by an exp-run.

In D3001#77190, @kib wrote:
In D3001#77189, @pfg wrote:

Private code can still disable relro, but I see your point.

Nevertheless, it still will be interesting to see, through the exp-run, how ports react to having relro by default.

You would only see a half of the interesting things, at best. Another half happens at runtime, which cannot be tested by an exp-run.

The toolchain will certainly be runtime tested, and some ports have testing targets.

I am also running it on my box. The question is .. what would be affected? Is there any particular port I should check?

In D3001#77191, @pfg wrote:
In D3001#77190, @kib wrote:
In D3001#77189, @pfg wrote:

Private code can still disable relro, but I see your point.

Nevertheless, it still will be interesting to see, through the exp-run, how ports react to having relro by default.

You would only see a half of the interesting things, at best. Another half happens at runtime, which cannot be tested by an exp-run.

The toolchain will certainly be runtime tested, and some ports have testing targets.

It is definitely not toolchain but the final linked binaries which should be tested.

I am also running it on my box. The question is .. what would be affected? Is there any particular port I should check?

I do not aware about in-ports apps. I would expect the hacks like runtime API intereceptors to break (which is, so to say, the purpose of relro).

In D3001#77191, @pfg wrote:
In D3001#77190, @kib wrote:
In D3001#77189, @pfg wrote:

Private code can still disable relro, but I see your point.

Nevertheless, it still will be interesting to see, through the exp-run, how ports react to having relro by default.

You would only see a half of the interesting things, at best. Another half happens at runtime, which cannot be tested by an exp-run.

The toolchain will certainly be runtime tested, and some ports have testing targets.

I am also running it on my box. The question is .. what would be affected? Is there any particular port I should check?

Yes, you should take a look at Xorg port, we running into some issue with full relro in our test builds, but for more details ask Shawn.
(And yes, this issue is already documented in gentoo's wiki.)

In D3001#77192, @kib wrote:
In D3001#77191, @pfg wrote:
In D3001#77190, @kib wrote:
In D3001#77189, @pfg wrote:

Private code can still disable relro, but I see your point.

Nevertheless, it still will be interesting to see, through the exp-run, how ports react to having relro by default.

You would only see a half of the interesting things, at best. Another half happens at runtime, which cannot be tested by an exp-run.

The toolchain will certainly be runtime tested, and some ports have testing targets.

It is definitely not toolchain but the final linked binaries which should be tested.

I meant the linked binaries from the toolchains. Not only the base binaries but stuff like gcc48. Also emacs and java (I think) has some bootstrapping code.
I find it difficult to believe that if CentOS sues this by default we will find something new but still testing is good.

I am also running it on my box. The question is .. what would be affected? Is there any particular port I should check?

I do not aware about in-ports apps. I would expect the hacks like runtime API intereceptors to break (which is, so to say, the purpose of relro).

I will rebuild Java, perhaps that is affected.

To make things clear: I am just testing the waters.
As I see it we could do things gradually: first LDFLAGS+=, and eventually make it the default in the linker. This is also not a ground-breaking feature, we could just wait for upstream to make RELRO the default.

As expected an exp-run with partial relro enabled didn't find any issue.

It appears upstream (binutils) will not make partial relro the default as it is not supported everywhere. For reference: NetBSD doesn't support it yet and OpenBSD does relro by default in their native toolchain but they intentionally left no way to turn it off.

I brought the subject to the GNU binutils list and a Gentoo developer recommended the linker approach, claiming they have been doing it for 9 years. Apparently there is a recurring subject with a patch to enable it as a configure option but they haven't agreed on the details.

We've been running with a modified version of this patch in HardenedBSD for a while now. It only applies to base and not ports, though we have some ports opting into RELRO + BIND_NOW. Would this be something that could be committed? Or are there still objections?

We've been running with a modified version of this patch in HardenedBSD for a while now. It only applies to base and not ports, though we have some ports opting into RELRO + BIND_NOW. Would this be something that could be committed? Or are there still objections?

Nothing has changed ... I don't think FreeBSD should follow that path. Eventually, performance issues with BIND_NOW need to be evaluated on a per-case basis.

OTOH, if you want to see *partial* RELRO as a default in the future, you could work with upstream binutils to get their WIP patch cleaned up:
https://sourceware.org/ml/binutils/2015-09/msg00222.html
(be sure to check the whole thread)

you could work with upstream binutils to get their WIP patch cleaned up

Note that binutils 2.27 now supports a configure-time relro default, and it is enabled by default on (non-frv|hppa|ia64|mips) Linux. We can set it by default in our binutils ports, and then push it upstream.

you could work with upstream binutils to get their WIP patch cleaned up

Note that binutils 2.27 now supports a configure-time relro default, and it is enabled by default on (non-frv|hppa|ia64|mips) Linux. We can set it by default in our binutils ports, and then push it upstream.

Good, I was expecting it to happen someday ;).

I have a patch for our base binutils here:
https://people.freebsd.org/~pfg/patches/partial-relro.diff

Our binutils port is still in version 2.25 so we will have to wait, also I am not sure if FreeBSD-9.0 supports partial relro so enabling relro will depend on OSVERSION.

In D3001#158873, @pfg wrote:

...
Our binutils port is still in version 2.25 so we will have to wait, also I am not sure if FreeBSD-9.0 supports partial relro so enabling relro will depend on OSVERSION.

Answering to myself: support for RELRO was merged to FreeBSD 9-Stable on r231579 and included in 9.1 so it appears all supported OS versions can use RELRO.