Avoid reading text section in generate code
Summary
Some OSs (Android, OpenBSD) are moving to execute-only (xonly) unreadable code as a
mitigation technique.
GHC should put any data that it reads at runtime outside .text
section and into .rodata
.
Steps to reproduce
OpenBSD 7.3 is likely to ship with xonly enabled by default. Right now this is a development set of patches. With these patches GHC build process fails as soon as it creates and runs the first program. The program happens to be ghc-cabal
which gets a SIGSEGV promptly at startup. The problem is easy to reproduce with other binaries, but I didn't minimize the repro.
The details indicate reading from text
.
% /usr/ports/pobj/ghc-9.2.5/ghc-9.2.5/inplace/bin/ghc-cabal
[1] 99461 segmentation fault (core dumped) /usr/ports/pobj/ghc-9.2.5/ghc-9.2.5/inplace/bin/ghc-cabal
% egdb /usr/ports/pobj/ghc-9.2.5/ghc-9.2.5/inplace/bin/ghc-cabal ghc-cabal.core
Core was generated by `ghc-cabal'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0000077e6f693de3 in stg_enter_info ()
(gdb) disassemble
Dump of assembler code for function stg_enter_info:
0x0000077e6f693dd8 <+0>: mov 0x8(%rbp),%rax
0x0000077e6f693ddc <+4>: test $0x7,%al
0x0000077e6f693dde <+6>: jne 0x77e6f693e2f <stg_enter_info+87>
0x0000077e6f693de0 <+8>: mov (%rax),%rbx
=> 0x0000077e6f693de3 <+11>: movslq -0x8(%rbx),%rcx
0x0000077e6f693de7 <+15>: cmp $0x1a,%rcx
0x0000077e6f693deb <+19>: jb 0x77e6f693e15 <stg_enter_info+61>
0x0000077e6f693ded <+21>: cmp $0x1c,%rcx
0x0000077e6f693df1 <+25>: jb 0x77e6f693e03 <stg_enter_info+43>
0x0000077e6f693df3 <+27>: cmp $0x1d,%rcx
0x0000077e6f693df7 <+31>: jae 0x77e6f693e09 <stg_enter_info+49>
0x0000077e6f693df9 <+33>: mov 0x8(%rax),%rax
0x0000077e6f693dfd <+37>: mov %rax,0x8(%rbp)
0x0000077e6f693e01 <+41>: jmp 0x77e6f693ddc <stg_enter_info+4>
0x0000077e6f693e03 <+43>: cmp $0x1b,%rcx
0x0000077e6f693e07 <+47>: jae 0x77e6f693df9 <stg_enter_info+33>
0x0000077e6f693e09 <+49>: mov %rbx,%rcx
0x0000077e6f693e0c <+52>: mov %rax,%rbx
0x0000077e6f693e0f <+55>: add $0x10,%rbp
0x0000077e6f693e13 <+59>: jmpq *%rcx
0x0000077e6f693e15 <+61>: cmp $0xf,%rcx
0x0000077e6f693e19 <+65>: jb 0x77e6f693e29 <stg_enter_info+81>
0x0000077e6f693e1b <+67>: cmp $0x19,%rcx
0x0000077e6f693e1f <+71>: jae 0x77e6f693e2f <stg_enter_info+87>
0x0000077e6f693e21 <+73>: cmp $0x17,%rcx
0x0000077e6f693e25 <+77>: jne 0x77e6f693e09 <stg_enter_info+49>
0x0000077e6f693e27 <+79>: jmp 0x77e6f693e2f <stg_enter_info+87>
0x0000077e6f693e29 <+81>: cmp $0x8,%rcx
0x0000077e6f693e2d <+85>: jb 0x77e6f693e09 <stg_enter_info+49>
0x0000077e6f693e2f <+87>: mov %rax,%rbx
0x0000077e6f693e32 <+90>: add $0x10,%rbp
0x0000077e6f693e36 <+94>: jmpq *0x0(%rbp)
End of assembler dump.
(gdb) p/x $rbx
$1 = 0x77e6f48b7c8
(gdb) x/100bx $rbx
0x77e6f48b7c8 <ZCMain_main_info>: 0x48 0x8d 0x45 0xf0 0x4c 0x39 0xf8 0x72
0x77e6f48b7d0 <ZCMain_main_info+8>: 0x45 0x48 0x83 0xec 0x08 0x4c 0x89 0xe8
0x77e6f48b7d8 <ZCMain_main_info+16>: 0x48 0x89 0xde 0x48 0x89 0xc7 0x31 0xc0
0x77e6f48b7e0 <ZCMain_main_info+24>: 0xe8 0xeb 0x3b 0x20 0x00 0x48 0x83 0xc4
0x77e6f48b7e8 <ZCMain_main_info+32>: 0x08 0x48 0x85 0xc0 0x74 0x26 0x48 0x8d
0x77e6f48b7f0 <ZCMain_main_info+40>: 0x1d 0x13 0xf0 0x20 0x00 0x48 0x89 0x5d
0x77e6f48b7f8 <ZCMain_main_info+48>: 0xf0 0x48 0x89 0x45 0xf8 0x4c 0x8d 0x35
0x77e6f48b800 <ZCMain_main_info+56>: 0x6c 0x9e 0x45 0x00 0x48 0x8d 0x1d 0x25
0x77e6f48b808 <ZCMain_main_info+64>: 0xc9 0x47 0x00 0x48 0x83 0xc5 0xf0 0xe9
0x77e6f48b810 <ZCMain_main_info+72>: 0x8c 0x32 0x21 0x00 0xff 0x23 0x41 0xff
0x77e6f48b818 <ZCMain_main_info+80>: 0x65 0xf0 0xcc 0xcc 0xcc 0xcc 0xcc 0xcc
0x77e6f48b820 <_hs_text_memcpy>: 0x4c 0x8b 0x1d 0x01 0x67 0x21 0x00 0x4c
0x77e6f48b828 <_hs_text_memcpy+8>: 0x33 0x1c 0x24 0x55
Expected behavior
Data gets placed into .rodata
and programs run fine when built with --execute-only
linker flag. As it stands I will be disabling this feature for all GHC-compiled programs on OpenBSD.
Environment
- GHC version used: 8.10.7 from bootstrap, but newer versions like 9.2.5 are similarly affected.
Optional:
- Operating System: OpenBSD
- System Architecture: amd64