Arch 打包準則/安全
32 位 – 安全 – CLR – CMake – DKMS – Eclipse – Electron – Free Pascal – GNOME – Go – Haskell – Java – 交叉編譯工具 – KDE – Lisp – Meson – MinGW – 內核模塊 – Node.js – Nonfree – 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 語言軟體打包準則#Flags and build options。
Stack canary
Stack canary(又稱棧警惕標誌)由編譯器添加在棧的緩衝區和控制數據之間。如果該已知值被破壞,就代表出現了緩衝區溢出,運行中的程序就會報出段錯誤(segfaults),以防止執行潛在的錯誤代碼。
gcc包 包默認通過 --enable-default-ssp 編譯選項啟用了棧保護。
NX
C/C++
可執行空間保護會將內存區域標記為非可執行,使得在該區域執行機器碼時會出現報錯。該功能使用了類似 NX 位(No-eXecute bit,禁止執行位)的硬體功能,有時也會使用軟體模擬這些特性。
PIE
C/C++
gcc包 包默認通過 --enable-default-pie 選項為 C/C++ 啟用了該特性。
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
PrivateDevices 會為執行中的進程配置新的 /dev 命名空間,其中只包含類似 /dev/null、/dev/zero 和 /dev/random 的 API 偽設備,不包含任何物理設備、系統內存、系統埠和其它設備。該選項可以防止進程直接向物理設備進行寫入,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
還可以按架構來限制系統調用,例如限制在 64 位設備上執行 32 位二進制文件(即非原生架構二進制文件):
SystemCallArchitectures=native
網絡
如果進程不需要訪問網絡,可以為進程配置一個新的網絡命名空間,並只配置迴環接口,以此完全禁用網絡訪問:
PrivateNetwork=true
如果需要網絡,還可以限制 socket(2) 系統調用可使用的地址族類型,以只允許 UNIX socket 為例:
RestrictAddressFamilies=AF_UNIX
也可以對只需連接到 localhost(本機)或特定 IP 段的情況進行限制,以只允許 localhost 為例:
IPAddressAllow=localhost IPAddressDeny=any
更多網絡過濾相關的信息請參考 systemd.resource-control(5)。
其它
為執行的進程配置新的 UTS 命名空間,並禁止修改主機名或域名:
ProtectHostname=true