Arch 软件包指南/安全
32 位 – CLR – CMake – 交叉编译 – DKMS – Eclipse – Electron – 字体 – Free Pascal – GNOME – Go – Haskell – Java – KDE – 内核模块 – Lisp – Meson – MinGW – Node.js – 非自由软件 – OCaml – Perl – PHP – Python – R – Ruby – Rust - 安全 – Shell – VCS – Web – Wine
本页面描述了 Arch Linux 软件包的安全打包指南。对于 C/C++ 项目,编译器和链接器可以应用安全加固选项。Arch Linux 默认应用 PIE、FORTIFY_SOURCE、栈保护、nx 和 relro。
用法
可以通过运行 checksec 来查看加固保护。
$ checksec --file=/usr/bin/cat
RELRO
RELRO 是一种通用的缓解技术,用于加固 ELF 二进制文件/进程的数据段。当程序加载时,链接器需要写入几个 ELF 内存段,但在将控制权交给程序之前,可以将其设置为只读。这可以防止攻击者覆盖某些 ELF 段。RELRO 有两种不同的模式
- 部分 RELRO (
-Wl,-z,relro
) 程序加载后,某些段被标记为只读,但 GOT (.got.plt
) 仍然可写。 - 完全 RELRO (
-Wl,-z,now
) 在程序加载期间,所有动态符号都被解析,允许将完整的 GOT 标记为只读。
如果应用程序报告部分 relro,请调查构建工具链是否传递了我们的 LDFLAGS 或允许覆盖 LDFLAGS。对于 Go 软件包,请调查构建方法是否使用 build.go
作为纯 golang Makefile 替代品,后者不允许传递 LDFLAGS。
Haskell
目前尚不清楚如何为 Haskell 实现完全 RELRO。
Go
请参阅 Go 软件包指南#标志和构建选项。
栈金丝雀
栈金丝雀是由编译器添加到栈上缓冲区和控制数据之间的值。如果这个已知值被破坏,则发生了缓冲区溢出,并且正在运行的程序会发生段错误,以防止可能的任意代码执行。
gcc 软件包默认启用栈保护,并使用 --enable-default-ssp 编译选项。
NX
C/C++
可执行空间保护将内存区域标记为不可执行,这样,尝试在这些区域中执行机器代码将导致异常。它利用了硬件功能,例如 NX 位(禁止执行位),或者在某些情况下,软件模拟这些功能。
PIE
C/C++
gcc 软件包默认为 C/C++ 启用 PIE,并使用 --enable-default-pie。
Golang
将以下标志传递给 go build
export GOFLAGS='-buildmode=pie' export CGO_CPPFLAGS="-D_FORTIFY_SOURCE=3" export CGO_LDFLAGS="-Wl,-z,relro,-z,now"
Haskell
将以下标志传递给 runhaskell Setup.hs configure
--ghc-option='-pie'
RPATH/RUNPATH
RUNPATH/RPATH 为列出它的对象提供了进一步的搜索路径(它可以用于可执行文件和共享对象)。
$ objdump -x /usr/bin/perl | grep -E 'RPATH|RUNPATH'
如果 RPATH 值包含攻击者可控制的路径,则可能会通过在该目录中安装恶意库来执行代码,例如 CVE-2006-1566 CVE-2005-4280。请参阅 Debian:RpathIssue。
RPATH 条目由链接器通过将以下字符串传递给 LDFLAGS 来设置,例如 -Wl,-rpath -Wl,/usr/local/lib
。要创建 RUNPATH 条目,请将 --enable-new-dtags
附加到链接器标志。
FORTIFY
Fortify source 是一个宏,它在各种对内存和字符串执行操作的函数中添加缓冲区溢出保护。它检查攻击者是否尝试复制更多字节来溢出缓冲区,然后停止程序的执行。此保护通过默认的 CPPFLAGS
启用
makepkg.conf
CPPFLAGS="-D_FORTIFY_SOURCE=3"
请参阅 makepkg#配置。
systemd 服务
如果软件包附带了 systemd 服务文件(因为上游未提供任何文件),请考虑应用以下 systemd 服务加固功能。Systemd 提供了一种分析服务启用的安全功能的方法。
$ systemd-analyze security reflector.service
文件访问
可以通过限制文件系统访问来加固服务。
为执行的进程设置新的文件系统命名空间,并在其中挂载私有的 /tmp
和 var/tmp
目录,这些目录不与命名空间外的进程共享。对于将数据写入 /tmp
的程序很有用。
PrivateTmp=true
ProtectSystem 有三种不同的变体,用于将目录挂载为执行进程的只读目录。“full”选项将 /usr
、/boot
和 /etc
挂载为只读。ProtectHome 使执行进程无法访问 /home
、/root
和 /run/user
。
ProtectSystem=strict ProtectHome=true
为执行的进程设置新的 /dev
命名空间,并且仅添加 API 伪设备,例如 /dev/null
、/dev/zero
或 /dev/random
,但不添加物理设备或系统内存、系统端口和其他设备。这对于保护执行进程免于直接写入物理设备很有用,systemd 还为 @raw-io
集中的调用添加了系统调用过滤器。
PrivateDevices=true
这些选项使执行的进程无法更改可通过 /proc/sys
、/sys
等访问的内核变量。ProtectControlGroups 使 /sys/fs/cgroup
层次结构只读。
ProtectKernelTunables=true ProtectControlGroups=true
使文件路径不可访问可以按如下方式完成
InaccessiblePaths=/etc
更多详细信息可以在 systemd.exec(5) 中找到。
用户
确保执行的进程及其子进程永远无法通过 execve(2) 获得新的特权。
NoNewPrivileges=true
内存
禁止尝试创建既可写又可执行的内存映射,禁止更改映射为可执行,或创建可执行的共享内存。这会对进程进行沙盒化,以防止攻击者写入也执行的内存。请注意,启用此功能与所有依赖于 JIT 的应用程序不兼容。
MemoryDenyWriteExecute=true
系统调用
锁定 personality(2) 系统调用,以便无法更改内核执行域。
LockPersonality=true
系统调用也可以在服务中受到限制,systemd 可以显示要过滤的系统调用
$ systemd-analyze syscall-filter
预定义的组可用,例如,要使用推荐的系统服务系统调用白名单起点,请使用
SystemCallFilter=@system-service
系统调用可以按其架构进行限制,例如防止 32 位二进制文件在 64 位计算机上执行(无非原生二进制文件)
SystemCallArchitectures=native
网络
如果运行的进程不需要任何网络访问,则可以通过为该进程设置新的网络命名空间并仅配置环回接口来完全禁用网络访问。
PrivateNetwork=true
如果需要网络,则可以限制 socket(2) 系统调用的地址族类型,例如仅允许 UNIX 套接字。
RestrictAddressFamilies=AF_UNIX
对于仅需要连接到 localhost 或特定 IP 范围的网络,可以通过仅允许网络访问 localhost 来限制进程。
IPAddressAllow=localhost IPAddressDeny=any
有关网络过滤的更多信息,请参见 systemd.resource-control(5)。
各种
为执行进程设置新的 UTS 命名空间,并禁止更改主机名或域名。
ProtectHostname=true