为什么 ghc 不支持 Linux 中的 PIE 和 Full RelRO?

问题描述 投票:0回答:1

我是 Haskell 初学者。我写了一个简单的代码并用ghc编译它。使用命令 checksec 检查编译的二进制文件的结果是,未应用 PIE,并且 RelRO 设置为部分。

λ vm-ubuntu22 projects → checksec --file haskell_code
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      FILE
Partial RELRO   No canary found   NX enabled    No PIE          No RPATH   No RUNPATH   haskell_code

我想编译二进制文件以具有 PIE 和完整的 ReloRO。我也尝试过

-fPIE
选项,但它没有改变。我该如何应用它?

仅供参考,我使用的是 ghc 9.6.6 版本,操作系统是 ubuntu 22.04。

security haskell
1个回答
0
投票

简短回答:尝试:

ghc -fforce-recomp -O2 -fPIE -pie -dynamic -dynload deploy -optl=-znow -optl=-s Hello.hs

生成启用 PIE 的完整 RELO、带有剥离符号的动态链接可执行文件。 如果您想要静态链接,请参见下文。

-fforce-recomp
并不是严格需要的,但如果您正在进行一些实验,某些标志更改不会自动触发重新编译,因此您可能会得到误导性的结果。

更长的答案:您应该能够使用

-fPIE -pie -dynamic
生成启用PIE的可执行文件:

$ ghc -O2 -fPIE -pie -dynamic Hello.hs
Loaded package environment from /u/buhr/.ghc/x86_64-linux-9.6.4/environments/default
[1 of 2] Compiling Main             ( Hello.hs, Hello.o )
[2 of 2] Linking Hello

这里,

-pie
对于以位置无关的方式链接可执行文件是必要的,
-dynamic
对于强制GHC使用已编译包和运行时的共享库版本是必要的,这些版本是用
-fPIC编译的
.

在我的机器上,这会提供一个启用了 PIE 的二进制文件,但带有新的 RW-RUNPATH 警告:

$ checksec --file=Hello
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH      Symbols     FORTIFY Fortified   Fortifiable FILE
Partial RELRO   No canary found   NX enabled    PIE enabled     No RPATH   RW-RUNPATH   56 Symbols    No    0       0       Hello

这是因为

-dynamic
标志具有动态链接到所有 Haskell 库的效果。 这实际上是一个很大的优点,因为它产生的二进制文件比通常的静态链接小得多:

$ ls -l Hello
-rwxr-xr-x 1 buhr buhr 128104 Oct 23 11:49 Hello

但是,默认的 GHC 库搜索策略是

-dynload sysdep
,它添加了 RUNPATH。 (在这个例子中,我的 RUNPATH 有可写目录,因为我的 Haskell 库都安装在我的 homedir 下的
.ghcup
.stack
中。)您可以通过向 GHC 添加额外的
-dynload deploy
标志来禁止添加 RUNPATH命令:

$ ghc -fforce-recomp -O2 -fPIE -pie -dynamic -dynload deploy Hello.hs

(这是一个需要

-fforce-recomp
的示例,如果您已经在没有
-dynload
设置的情况下进行了编译,因为在这种情况下 GHC 不会重新链接。)

如果您想要一个仍然位置无关的静态链接可执行文件,您可以尝试删除

-dynamic
标志:

$ ghc -O2 -fPIE -pie Hello.hs

如果幸运的话,您的发行版可能拥有所有已使用

-fPIC
构建的静态 Haskell 运行时和内置包,并且它可以正常工作。 在我的 Debian 机器上,它生成了一大堆关于需要使用
-fPIC
重新编译库的链接错误。 如果你遇到这个问题,我认为你唯一的选择是从头开始重新编译 GHC,并使用一些补丁来构建运行时的静态版本和带有
-fPIC
的内置包。 请参阅此博客文章了解该过程的演练。

要获得完整的 RELRO 可执行文件,您需要将

-znow
选项传递给链接器。 以下似乎有效:

$ ghc -O2 -optl=-znow Hello.hs

您还可以使用单独的

strip
命令或仅将
-s
作为链接器选项传递,来剥离可执行文件以删除符号。

因此,以下 GHC 命令行:

ghc -fforce-recomp -O2 -fPIE -pie -dynamic -dynload deploy -optl=-znow -optl=-s Hello.hs

应该为您提供一个可执行文件,可以通过除金丝雀和强化测试之外的所有测试:

$ ghc -fforce-recomp -O2 -fPIE -pie -dynamic -dynload deploy -optl=-znow -optl=-s Hello.hs
Loaded package environment from /u/buhr/.ghc/x86_64-linux-9.6.4/environments/default
[1 of 2] Compiling Main             ( Hello.hs, Hello.o )
[2 of 2] Linking Hello [Objects changed]
$ checksec --file=Hello
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH  Symbols     FORTIFY Fortified   Fortifiable FILE
Full RELRO      No canary found   NX enabled    PIE enabled     No RPATH   No RUNPATH   No Symbols    No    0       0       Hello
© www.soinside.com 2019 - 2024. All rights reserved.