Linux

為什麼我們需要在呼叫 SECCOMP_MODE_FILTER 之前設置 no_new_privs?

  • January 19, 2020

手冊頁上,我閱讀了以下行:

導致嘗試使用 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/bashanotheruser;
  • 然後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 過濾器:即使是暫時的,這個程序也沒有任何可能提升權限,因此,將無法“劫持”這些權限。

引用自:https://unix.stackexchange.com/questions/562260