為什麼我們需要在呼叫 SECCOMP_MODE_FILTER 之前設置 no_new_privs?
在手冊頁上,我閱讀了以下行:
導致嘗試使用 setuid(2) 將呼叫者的使用者 ID 設置為非零值,而不是在不實際進行系統呼叫的情況下返回 0
我不明白他們想說什麼。誰能給我解釋一下?
謝謝。
首先,請注意
seccomp(2)
手冊頁中的以下段落:SECCOMP_RET_ERRNO
該值導致過濾器返回值的 SECCOMP_RET_DATA 部分作為 errno 值傳遞給使用者空間,而不執行系統呼叫。
因此,seccomp 過濾器可能會使核心跳過真正的系統呼叫執行,而是返回一些值來假裝系統呼叫已執行並產生了指定的結果。如果返回值設置為零,這也包括成功的結果。
這是
libseccomp
基於範例的程序 (sec.c
),它顯示了它是如何工作的(為簡潔起見,省略了所有錯誤檢查):#include <stdio.h> #include <seccomp.h> int main() { scmp_filter_ctx seccomp; seccomp = seccomp_init(SCMP_ACT_ALLOW); // Make the `openat(2)` syscall always "succeed". seccomp_rule_add(seccomp, SCMP_ACT_ERRNO(0), SCMP_SYS(openat), 0); // Install the filter. seccomp_load(seccomp); FILE *file = fopen("/non-existent-file", "r"); // Do something with the file and then perform the cleanup. // <...> return 0; }
在跟踪執行的同時編譯和執行這個程序表明
openat(2)
系統呼叫返回零(即“執行”成功),儘管/non-existent-file
文件系統中不存在該文件:$ gcc sec.c -lseccomp -o sec # Run the program showing the openat(2) invocations and their results. $ strace -e trace=openat ./sec ... openat(AT_FDCWD, "/non-existent-file", O_RDONLY) = 0 ... # Ensure that the file does not exist. $ stat /non-existent-file stat: cannot stat '/non-existent-file': No such file or directory
好了,現在我們了解了 seccomp 過濾器的功能。讓我們更接近您在問題中引用的段落的要點。想兩件事:
- 非特權程序可能會使用一些核心機制來提升其特權;
- 有一些工具使用這種機制來臨時授予權限,並且僅用於有限數量的操作。
典型的例子是
sudo(8)
實用程序,它是root
–owned SUID 二進製文件。在非特權程序的上下文中執行它會授予呼叫程序完全的超級使用者權限(除了沙盒和容器等一些特殊情況),然後sudo(8)
檢查/etc/sudoers
文件以了解是否允許呼叫使用者執行請求的操作。如果是,則sudo(8)
繼續執行,如果不是,則拒絕執行。此外,sudo(8)
允許代表任意使用者執行 - 在這種情況下,它將在執行請求的操作之前設置適當的憑據。例如,假設
/etc/sudoers
文件包含以下記錄testuser ALL=(anotheruser) NOPASSWD: /bin/bash
使用者
testuser
將能夠anotheruser
使用以下命令代表執行 shell:sudo -u anotheruser -i /bin/bash
現在,我們更接近正題了:如果
testuser
–owned 程序安裝了 seccomp 過濾器,這使得核心在setuid(2)
沒有實際執行的情況下返回,然後執行sudo -u anotheruser -i /bin/bash
呢?走著瞧:
- 核心看到二進製文件中的 SUID 位
sudo(8)
並適當地提升呼叫程序的權限;sudo(8)
檢查/etc/sudoers
並確保testuser
允許執行/bin/bash
為anotheruser
;- 然後
sudo(8)
呼叫setuid(2)
適當地更改程序的憑據並“降級”其權限;- 使用者安裝的seccomp過濾器靜默報告成功,假裝“降級”完成;
sudo(8)
相信該過程現在代表……anotheruser
執行並繼續執行/bin/bash
……- 實際上以超級使用者權限執行它,因為
setuid(2)
被過濾器跳過並且沒有真正執行!因此,允許非特權使用者安裝 seccomp 過濾器還允許該使用者通過擷取呼叫來“劫持”特權憑據,
setuid(2)
同時以升級的權限臨時執行,因此在手冊頁中指定了限制:呼叫執行緒必須在其使用者命名空間中具有 CAP_SYS_ADMIN 功能,或者該執行緒必須已經設置了 no_new_privs 位。
很清楚這句話的第一部分是什麼意思:
CAP_SYS_ADMIN
是一種授予程序大量特權的能力,因此可以安全地假設擁有它的程序已經足夠強大,可以對系統造成嚴重破壞。第二部分呢?該
no_new_privs
位是程序的一個屬性,如果設置,它會告訴核心不要使用像 SUID 位這樣的特權升級機制(因此,呼叫類似的東西sudo(8)
根本不起作用),因此允許使用該位的非特權程序是安全的設置為使用 seccomp 過濾器:即使是暫時的,這個程序也沒有任何可能提升權限,因此,將無法“劫持”這些權限。