Opened 3 years ago

Closed 4 months ago

#9007 closed bug (duplicate)

fails to build with hardening flags enabled (relocation R_X86_64_32 against `stg_CHARLIKE_closure'...)

Reported by: nomeata Owned by: nomeata
Priority: high Milestone: 8.2.1
Component: Compiler Version: 7.9
Keywords: Cc: simonmar, slyfox, erikd
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Building GHC failed Test Case:
Blocked By: Blocking:
Related Tickets: #12759 Differential Rev(s):
Wiki Page:

Description

Building HEAD on Debian wheezy with the Debian packaging setup fails:

configure: Building in-tree ghc-pwd
/usr/bin/ld: utils/ghc-pwd/dist-boot/Main.o: relocation R_X86_64_32 against `stg_CHARLIKE_closure' can not be used when making a shared object; recompile with -fPIC
utils/ghc-pwd/dist-boot/Main.o: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
configure: error: Building ghc-pwd failed

http://deb.haskell.org/dailies/2014-04-16/ghc_7.9.20140416-0.daily_amd64.build

This is possibly related to the Hardening flags added by Debian:

~ $ dpkg-buildflags --get LDFLAGS
-Wl,-z,relro
~ $ dpkg-buildflags --get CFLAGS
-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security

Other related bug might be #3668 and https://bugs.debian.org/712228

I’ll disable the hardening flags and see if it helps. The error first occurred 2014-03-27.

Change History (28)

comment:1 Changed 3 years ago by simonmar

Cc: simonmar added

comment:2 Changed 3 years ago by nomeata

Summary: relocation R_X86_64_32 against `stg_CHARLIKE_closure' can not be used when making a shared objectfails to build with hardening flags enabled (relocation R_X86_64_32 against `stg_CHARLIKE_closure'...)

Yes, without the hardening flags it builds. So it is likely caused by 2aa78106ae8f3c9b71d7b85c2a8a5558c4c35fb4.

comment:3 Changed 3 years ago by simonmar

So you should be able to repro this manually. I just tried with -optl-Wl,-z,relro, but didn't see an error. You can look in config.log to see the exact command line that GHC was invoked with.

comment:4 Changed 3 years ago by simonmar

Milestone: 7.8.3
Owner: set to simonmar
Priority: normalhigh

Milestoning 7.8.3 since this patch was merged into the 7.8 branch too.

comment:5 Changed 3 years ago by simonmar

Status: newinfoneeded

Marking infoneeded as I'm not sure how to repro this. Ideally I need to see the exact command line that GHC was invoked with.

comment:6 Changed 3 years ago by nomeata

Owner: simonmar deleted

I’ll work on it when I find the time.

comment:7 Changed 3 years ago by nomeata

Status: infoneedednew

comment:8 Changed 3 years ago by nomeata

Owner: set to nomeata

(Sorry for the multiple changes, but I don’t the the permissions to assign the ticket to me otherwise.)

comment:9 Changed 3 years ago by nomeata

Status: newinfoneeded

comment:10 Changed 3 years ago by thoughtpolice

Milestone: 7.8.37.8.4

Moving to 7.8.4.

comment:11 Changed 3 years ago by rwbarton

I managed to reproduce this by making a Frankenpackage from ghc HEAD plus the debian directory from apt-get source ghc. Here are the flags that are being used:

rwbarton@morphism:/tmp$ ghc -optl-fPIE -optl-pie -optl-Wl,-z,relro -optl-Wl,-z,now test
[1 of 1] Compiling Main             ( test.hs, test.o )
Linking test ...
/usr/bin/ld: test.o: relocation R_X86_64_32S against `stg_bh_upd_frame_info' can not be used when making a shared object; recompile with -fPIC
test.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status

-optl-pie is the offending flag.

(test.hs is just a trivial program main = print "hi".)

comment:12 Changed 3 years ago by ulysses4ever

Are there any straightforward workarounds for this problem? I have similar issue while building GHC from sources (reported in #9302) when processing Data.Array.Parallel. The reason for me was the choise of quickest type of build.

Last edited 3 years ago by ulysses4ever (previous) (diff)

comment:13 Changed 2 years ago by thoughtpolice

Milestone: 7.8.47.10.1

Moving (in bulk) to 7.10.4

comment:14 Changed 2 years ago by thoughtpolice

Milestone: 7.10.17.12.1

Moving to 7.12.1

comment:15 Changed 21 months ago by mitchty

It appears I'm hitting an instance of this, or a related case after porting ghc to Alpine Linux. Though the situation I'm encountering is slightly different, the error I see is the same as rwbarton noted earlier with the stg function.

What I am seeing with a ghc --make test.hs compile of a really simple haskell program: https://gist.githubusercontent.com/mitchty/296be0fd030aba6aa7b5/raw/f845993582c32e9b8e4e1752d64f7f1a9b3fc1aa/make.out

If you note from that make.out example, stg_bh_upd_frame_info is not PIC after its been statically linked.

To explain a bit more, Alpine linux is setup to compile with PIE executables by default, as well as PIC libraries. This can be changed for errant things which cannot use aslr if needed, but the default ABI requires PIE/PIC. Effectively Alpine linux is running the same as Debian when hardened. However if necessary you can use an escape hatch of -nopie -fno-PIC, which is how I had to port ghc.

This presents a problem however, as it appears ghc will not emit PIC assembly in this case. Nor is there apparently an option to do so that one can toggle via configure or auto tools or editing the settings file directly to achieve that goal.

What would appear to be needed here after chatting with rwbarton on irc is some way to have ghc emit PIC assembly on Linux x86_64 platforms when necessary. Note that in the case of Alpine Linux, we would want PIC/PIE to always be on. For Debian hardened that may not hold true in that ghc itself might need to be built as a pie executable but executables it creates in this situation may not need to be pie.

As an example, gcc on Alpine Linux has the following macros set by default with no feature switches enabled to gcc: $ echo ";" | gcc -E -dD -c -| grep PIC #define PIC 2 $ echo ";" | gcc -E -dD -c -| grep PIE #define PIE 2

Also note, unlike the Debian hardening, there is no easy way to change these defaults outside of possibly recompiling gcc. From the discussion in irc the following two options seem reasonable:

  • Add a value to the settings file to control if ghc will emit PIC assembly by default or not
  • Possibly attempt to detect that the Linux in use requires PIC/PIE via some trick like the above gcc preprocessor dumps

The latter may be a better option overall but I will need to compare against the other hardened linux flavors in all their possible settings. As an example Gentoo linux allows you to change the gcc hardened settings at run time, which would make detection of the "right" thing to do rather difficult. Similar behavior would apply to fedora as well.

I'm not sure the correct way forward but for the moment a setting to adjust what type of assembly ghc emits would seem the best option. Right now I have to force all binaries to be nopie as a workaround to this issue.

comment:16 Changed 21 months ago by slyfox

Cc: slyfox added

comment:17 Changed 21 months ago by slyfox

I propose to extent SysTools.hs:getCompilerInfo to detect PIC at ghc startup time as we do with gcc/clang and set fPIC default accordingly.

comment:18 Changed 21 months ago by rwbarton

If we do so should we apply the options from -optc-foo when doing this detection?

I was going to object that the C compiler options can vary between input files in a single compilation (with OPTIONS_GHC) though technically the same is true of the C compiler program and it looks like we don't currently handle that correctly either. Probably it would not be unreasonably difficult to redo the detection only when the program/options have actually changed.

Does the Debian (or Fedora/Gentoo) build system have some extra magic that makes all invocations of gcc produce PIC/PIE by default? Otherwise ghc -optl-fPIE -optl-pie -optl-Wl,-z,relro -optl-Wl,-z,now is not going to get the job done in any case, and the build systems will have to learn about how to specify either -fPIC or -optc-fPIC to ghc even if we do this autodetection and it uses the C compiler options.

comment:19 in reply to:  18 ; Changed 21 months ago by slyfox

Replying to rwbarton:

If we do so should we apply the options from -optc-foo when doing this detection?

I think we need to ignore -optc during autodetection and should check only vanilla pgmC. It should simplify meaning of ghc -fPIC -optc-fno-PIC. I would say ghc -fno-PIC should disable PIC for both gcc/ghc even if fPIC is a default.

I was going to object that the C compiler options can vary between input files in a single compilation (with OPTIONS_GHC) though technically the same is true of the C compiler program and it looks like we don't currently handle that correctly either. Probably it would not be unreasonably difficult to redo the detection only when the program/options have actually changed.

Does the Debian (or Fedora/Gentoo) build system have some extra magic that makes all invocations of gcc produce PIC/PIE by default? Otherwise ghc -optl-fPIE -optl-pie -optl-Wl,-z,relro -optl-Wl,-z,now is not going to get the job done in any case, and the build systems will have to learn about how to specify either -fPIC or -optc-fPIC to ghc even if we do this autodetection and it uses the C compiler options.

Hardened gentoo patches gcc to default to -fPIC -fPIE -pie. Defaults there:

# gcc -dM -E - < /dev/null | grep -E -i 'pic|pie'
#define __pie__ 2
#define __PIE__ 2
#define __pic__ 2
#define __PIC__ 2

What bothers me is -optl-pie seems not to work even for -split-objs case on vanilla gcc/ghc:

$ echo 'main = print "hello"' > a.hs
$ ghc --make -optl-pie -fPIC -optc-fPIC -dynamic a.hs -fforce-recomp
[1 of 1] Compiling Main             ( a.hs, a.o )
Linking a ...
$ ghc --make -optl-pie -fPIC -optc-fPIC -dynamic a.hs -fforce-recomp -split-objs
[1 of 1] Compiling Main             ( a.hs, a.o )
/usr/lib/gcc/x86_64-pc-linux-gnu/5.1.0/../../../../x86_64-pc-linux-gnu/bin/ld: -r and -shared may not be used together
collect2: error: ld returned 1 exit status

An evil corner case as we use ld for partial linking. Can be an argument for native fPIE/pie support in ghc.

comment:20 Changed 21 months ago by rwbarton

Hmph. Another terrible error message from the linker, too (who said anything about -shared?)

I think I need to understand the exact behavior of the Debian build system at this point, the more I look into this the more confused I get.

comment:21 in reply to:  19 ; Changed 21 months ago by kgardas

Replying to slyfox:

Hardened gentoo patches gcc to default to -fPIC -fPIE -pie. Defaults there:

# gcc -dM -E - < /dev/null | grep -E -i 'pic|pie'
#define __pie__ 2
#define __PIE__ 2
#define __pic__ 2
#define __PIC__ 2

What bothers me is -optl-pie seems not to work even for -split-objs case on vanilla gcc/ghc:

$ echo 'main = print "hello"' > a.hs
$ ghc --make -optl-pie -fPIC -optc-fPIC -dynamic a.hs -fforce-recomp
[1 of 1] Compiling Main             ( a.hs, a.o )
Linking a ...
$ ghc --make -optl-pie -fPIC -optc-fPIC -dynamic a.hs -fforce-recomp -split-objs
[1 of 1] Compiling Main             ( a.hs, a.o )
/usr/lib/gcc/x86_64-pc-linux-gnu/5.1.0/../../../../x86_64-pc-linux-gnu/bin/ld: -r and -shared may not be used together
collect2: error: ld returned 1 exit status

An evil corner case as we use ld for partial linking. Can be an argument for native fPIE/pie support in ghc.

I'm curious but isn't -split-objs purely static library thing? IMHO it's not usable for -shared nor -dynamic nor -fPIC etc. Please correct me if I'm wrong here...

comment:22 in reply to:  21 Changed 21 months ago by slyfox

Replying to kgardas:

Replying to slyfox:

Hardened gentoo patches gcc to default to -fPIC -fPIE -pie. Defaults there: ... An evil corner case as we use ld for partial linking. Can be an argument for native fPIE/pie support in ghc.

I'm curious but isn't -split-objs purely static library thing? IMHO it's not usable for -shared nor -dynamic nor -fPIC etc. Please correct me if I'm wrong here...

A couple of points here:

  • -fPIC is valid for static libraries (it's used for hardening even statically linked binaries), recent example of accidental fPIC no a static haskell library: https://ghc.haskell.org/trac/ghc/ticket/10402#comment:14 . It's not necessary but not outright harmful.
  • -split-objs used to split .o files into smaller .o files to allow linker remove unused code. That unused code can come from:
    • external static haskell library (typical case) when linking static binary, no need to run -spit-objs
    • internal static or dynamic haskell library (or binary)

I would say it makes sense to run -split-objs every time object files are produced. I view it as trick similar to 'gcc -function-sections -fdata-sections -Wl,--gc-sections'.

comment:23 Changed 19 months ago by thoughtpolice

Milestone: 7.12.18.0.1

Milestone renamed

comment:24 Changed 14 months ago by rwbarton

Status: infoneedednew

I don't know whether this will resolve the original issue, but I think we should implement slyfox's suggestion as described in comment:17 and comment:19.

comment:25 Changed 13 months ago by bgamari

Milestone: 8.0.18.2.1

Sadly not happening for 8.0.1.

comment:26 Changed 5 months ago by erikd

Cc: erikd added

comment:28 Changed 4 months ago by bgamari

Resolution: duplicate
Status: newclosed

Indeed, I believe this should have been fixed by #12759.

Note: See TracTickets for help on using tickets.