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