Landlock: 非特權訪問控制

作者:

Mickaël Salaün

日期:

2025 年 3 月

Landlock 的目標是允許限制一組程序的環境許可權(例如,全域性檔案系統或網路訪問)。 由於 Landlock 是一個可堆疊的 LSM,它使得除了現有的系統範圍的訪問控制之外,還可以建立安全的安全沙箱作為新的安全層。 這種沙箱有望幫助緩解使用者空間應用程式中錯誤或意外/惡意行為的安全影響。 Landlock 使任何程序(包括非特權程序)都能夠安全地限制自身。

我們可以透過在核心日誌中查詢“landlock: Up and running”(以 root 身份)來快速確保 Landlock 在執行系統中啟用:dmesg | grep landlock || journalctl -kb -g landlock 。 開發人員還可以透過相關的系統呼叫輕鬆檢查 Landlock 支援。 如果當前不支援 Landlock,我們需要適當地配置核心

Landlock 規則

Landlock 規則描述了程序打算對物件執行的操作。 一組規則聚合在一個規則集中,然後可以限制強制執行它的執行緒及其未來的子執行緒。

兩種現有的規則型別是

檔案系統規則

對於這些規則,物件是一個檔案層次結構,相關的檔案系統操作透過檔案系統訪問許可權定義。

網路規則(自 ABI v4 起)

對於這些規則,物件是一個 TCP 埠,相關的操作透過網路訪問許可權定義。

定義和強制執行安全策略

我們首先需要定義將包含我們的規則的規則集。

對於此示例,規則集將包含僅允許檔案系統讀取操作並建立特定 TCP 連線的規則。 檔案系統寫入操作和其他 TCP 操作將被拒絕。

然後,規則集需要處理這兩種操作。 這是向後和向前相容所必需的(即,核心和使用者空間可能不知道彼此支援的限制),因此需要明確關於預設拒絕的訪問許可權。

struct landlock_ruleset_attr ruleset_attr = {
    .handled_access_fs =
        LANDLOCK_ACCESS_FS_EXECUTE |
        LANDLOCK_ACCESS_FS_WRITE_FILE |
        LANDLOCK_ACCESS_FS_READ_FILE |
        LANDLOCK_ACCESS_FS_READ_DIR |
        LANDLOCK_ACCESS_FS_REMOVE_DIR |
        LANDLOCK_ACCESS_FS_REMOVE_FILE |
        LANDLOCK_ACCESS_FS_MAKE_CHAR |
        LANDLOCK_ACCESS_FS_MAKE_DIR |
        LANDLOCK_ACCESS_FS_MAKE_REG |
        LANDLOCK_ACCESS_FS_MAKE_SOCK |
        LANDLOCK_ACCESS_FS_MAKE_FIFO |
        LANDLOCK_ACCESS_FS_MAKE_BLOCK |
        LANDLOCK_ACCESS_FS_MAKE_SYM |
        LANDLOCK_ACCESS_FS_REFER |
        LANDLOCK_ACCESS_FS_TRUNCATE |
        LANDLOCK_ACCESS_FS_IOCTL_DEV,
    .handled_access_net =
        LANDLOCK_ACCESS_NET_BIND_TCP |
        LANDLOCK_ACCESS_NET_CONNECT_TCP,
    .scoped =
        LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
        LANDLOCK_SCOPE_SIGNAL,
};

因為我們可能不知道應用程式將在哪個核心版本上執行,所以遵循盡力而為的安全方法更安全。 實際上,無論使用者使用哪個核心,我們都應該儘可能地保護使用者。

為了與舊的 Linux 版本相容,我們檢測可用的 Landlock ABI 版本,並且僅使用可用的訪問許可權子集

int abi;

abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 0) {
    /* Degrades gracefully if Landlock is not handled. */
    perror("The running kernel does not enable to use Landlock");
    return 0;
}
switch (abi) {
case 1:
    /* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
    ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
    __attribute__((fallthrough));
case 2:
    /* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
    ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
    __attribute__((fallthrough));
case 3:
    /* Removes network support for ABI < 4 */
    ruleset_attr.handled_access_net &=
        ~(LANDLOCK_ACCESS_NET_BIND_TCP |
          LANDLOCK_ACCESS_NET_CONNECT_TCP);
    __attribute__((fallthrough));
case 4:
    /* Removes LANDLOCK_ACCESS_FS_IOCTL_DEV for ABI < 5 */
    ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL_DEV;
    __attribute__((fallthrough));
case 5:
    /* Removes LANDLOCK_SCOPE_* for ABI < 6 */
    ruleset_attr.scoped &= ~(LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET |
                             LANDLOCK_SCOPE_SIGNAL);
}

這使得可以建立包含規則的包含性規則集。

int ruleset_fd;

ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
if (ruleset_fd < 0) {
    perror("Failed to create a ruleset");
    return 1;
}

現在,我們可以透過返回的引用此規則集的檔案描述符向此規則集新增新規則。 該規則將僅允許讀取檔案層次結構/usr 。 如果沒有其他規則,則寫入操作將被規則集拒絕。 要將/usr新增到規則集中,我們使用O_PATH標誌開啟它,並使用此檔案描述符填充&struct landlock_path_beneath_attr

int err;
struct landlock_path_beneath_attr path_beneath = {
    .allowed_access =
        LANDLOCK_ACCESS_FS_EXECUTE |
        LANDLOCK_ACCESS_FS_READ_FILE |
        LANDLOCK_ACCESS_FS_READ_DIR,
};

path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC);
if (path_beneath.parent_fd < 0) {
    perror("Failed to open file");
    close(ruleset_fd);
    return 1;
}
err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
                        &path_beneath, 0);
close(path_beneath.parent_fd);
if (err) {
    perror("Failed to update ruleset");
    close(ruleset_fd);
    return 1;
}

還可能需要按照與規則集建立相同的邏輯建立規則,方法是根據 Landlock ABI 版本過濾訪問許可權。 在此示例中,不需要這樣做,因為所有請求的allowed_access許可權已在 ABI 1 中可用。

對於網路訪問控制,我們可以新增一組允許將埠號用於特定操作的規則:HTTPS 連線。

struct landlock_net_port_attr net_port = {
    .allowed_access = LANDLOCK_ACCESS_NET_CONNECT_TCP,
    .port = 443,
};

err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
                        &net_port, 0);

下一步是限制當前執行緒獲得更多許可權(例如,透過 SUID 二進位制檔案)。 我們現在有一個規則集,第一個規則允許讀取對/usr的訪問,同時拒絕檔案系統的所有其他處理的訪問,第二個規則允許 HTTPS 連線。

if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
    perror("Failed to restrict privileges");
    close(ruleset_fd);
    return 1;
}

當前執行緒現在已準備好使用規則集對自己進行沙箱化。

if (landlock_restrict_self(ruleset_fd, 0)) {
    perror("Failed to enforce ruleset");
    close(ruleset_fd);
    return 1;
}
close(ruleset_fd);

如果landlock_restrict_self系統呼叫成功,則當前執行緒現在受到限制,並且此策略將在其隨後建立的所有子執行緒上強制執行。 一旦執行緒被 Landlock 鎖定,就無法刪除其安全策略; 只允許新增更多限制。 這些執行緒現在位於一個新的 Landlock 域中,該域是其父域(如果有)與新規則集的合併。

完整的有效程式碼可以在samples/landlock/sandboxer.c中找到。

良好實踐

建議儘可能將訪問許可權設定為檔案層次結構的葉子。 例如,最好將~/doc/作為只讀層次結構,並將~/tmp/作為讀寫層次結構,而不是將~/作為只讀層次結構,並將~/tmp/作為讀寫層次結構。 遵循這種良好實踐會導致不依賴於其位置(即父目錄)的自給自足的層次結構。 當我們想要允許連結或重新命名時,這一點尤其重要。 實際上,對每個目錄使用一致的訪問許可權可以更改此類目錄的位置,而無需依賴目標目錄的訪問許可權(除了此操作所需的訪問許可權,請參閱LANDLOCK_ACCESS_FS_REFER文件)。

具有自給自足的層次結構也有助於將所需的訪問許可權收緊到最小的資料集。 這也有助於避免沉澱目錄,即可以連結到但不能從其中連結的資料的目錄。 但是,這取決於資料組織,這可能不受開發人員的控制。 在這種情況下,授予對~/tmp/的讀寫訪問許可權,而不是隻寫訪問許可權,可能會允許將~/tmp/移動到不可讀目錄,並且仍然能夠列出~/tmp/的內容。

檔案路徑訪問許可權的層

每次執行緒強制執行規則集時,它都會使用新的策略層更新其 Landlock 域。 此補充策略與可能已經限制此執行緒的任何其他規則集堆疊在一起。 然後,沙箱執行緒可以使用新的強制執行的規則集安全地向自身新增更多約束。

如果路徑上遇到的至少一個規則授予訪問許可權,則一個策略層授予對檔案路徑的訪問許可權。 只有當所有強制執行的策略層都授予訪問許可權以及所有其他系統訪問控制(例如,檔案系統 DAC、其他 LSM 策略等)時,沙箱執行緒才能訪問檔案路徑。

繫結掛載和 OverlayFS

Landlock 允許限制對檔案層次結構的訪問,這意味著這些訪問許可權可以透過繫結掛載傳播(請參閱共享子樹),但不能透過Overlay 檔案系統傳播。

繫結掛載將原始檔層次結構映象到目標。 然後,目標層次結構由完全相同的檔案組成,Landlock 規則可以透過源或目標路徑繫結到這些檔案。 這些規則限制了在路徑上遇到它們時的訪問,這意味著它們可以同時限制對多個檔案層次結構的訪問,無論這些層次結構是否是繫結掛載的結果。

OverlayFS 掛載點由上層和下層組成。 這些層組合在一個合併目錄中,並且該合併目錄在掛載點處可用。 此合併層次結構可能包括來自上層和下層的檔案,但在合併層次結構上執行的修改僅反映在上層。 從 Landlock 策略的角度來看,所有 OverlayFS 層和合並層次結構都是獨立的,並且每個都包含它們自己的檔案和目錄集,這與繫結掛載不同。 限制 OverlayFS 層的策略不會限制生成的合併層次結構,反之亦然。 然後,Landlock 使用者應該只考慮他們想要允許訪問的檔案層次結構,而不管底層檔案系統如何。

繼承

每個由clone(2)產生的新執行緒都從其父執行緒繼承 Landlock 域限制。 這類似於 seccomp 繼承(請參閱Seccomp BPF (使用過濾器進行安全計算))或處理任務的憑據(7)的任何其他 LSM。 例如,一個程序的執行緒可以將其 Landlock 規則應用於自身,但它們不會自動應用於其他兄弟執行緒(與 POSIX 執行緒憑據更改不同,請參閱nptl(7))。

當執行緒對自己進行沙箱化時,我們保證相關的安全策略將始終在此執行緒的所有後代上強制執行。 這允許為每個應用程式建立獨立和模組化的安全策略,這些策略將根據其執行時父策略自動相互組合。

Ptrace 限制

與非沙箱程序相比,沙箱程序的許可權較少,因此在操作另一個程序時必須受到額外的限制。 要允許在目標程序上使用ptrace(2)和相關係統呼叫,沙箱程序應具有目標程序訪問許可權的超集,這意味著被追蹤者必須是追蹤者的子域。

IPC 範圍限定

與隱式Ptrace 限制類似,我們可能希望進一步限制沙箱之間的互動。 因此,在規則集建立時,每個 Landlock 域都可以限制某些操作的範圍,以便這些操作只能到達同一 Landlock 域或巢狀 Landlock 域(“範圍”)中的程序。

可以限定範圍的操作包括

LANDLOCK_SCOPE_SIGNAL

這限制了將訊號傳送到在同一或巢狀 Landlock 域中執行的目標程序。

LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET

這限制了我們可以connect(2)到的抽象unix(7)套接字集,這些套接字地址是由同一或巢狀 Landlock 域中的程序建立的。

在非連線資料報套接字上進行sendto(2)的處理方式就像它在進行隱式connect(2)一樣,如果遠端端不是來自同一或巢狀 Landlock 域,則會被阻止。

先前連線的套接字上的sendto(2)將不受限制。 這適用於資料報套接字和流套接字。

IPC 範圍限定不支援透過landlock_add_rule(2)進行異常。 如果操作限定在域內,則無法新增規則以允許訪問範圍外的資源或程序。

截斷檔案

LANDLOCK_ACCESS_FS_WRITE_FILELANDLOCK_ACCESS_FS_TRUNCATE涵蓋的操作都更改了檔案的內容,並且有時以非直觀的方式重疊。 建議始終將這兩者一起指定。

一個特別令人驚訝的例子是creat(2)。 名稱表明此係統呼叫需要建立和寫入檔案的許可權。 但是,如果同名下的現有檔案已經存在,它也需要截斷許可權。

還應注意的是,截斷檔案不需要LANDLOCK_ACCESS_FS_WRITE_FILE許可權。 除了truncate(2)系統呼叫外,還可以透過open(2)與標誌O_RDONLY | O_TRUNC來完成。

截斷許可權與開啟的檔案關聯(見下文)。

與檔案描述符關聯的許可權

開啟檔案時,LANDLOCK_ACCESS_FS_TRUNCATELANDLOCK_ACCESS_FS_IOCTL_DEV許可權的可用性與新建立的檔案描述符相關聯,並將用於後續的截斷和使用ftruncate(2)ioctl(2)進行的 ioctl 嘗試。 此行為類似於開啟檔案進行讀取或寫入,許可權在open(2)期間檢查,但在後續的read(2)write(2)呼叫期間不檢查。

因此,一個程序可能具有多個引用同一檔案的開啟的檔案描述符,但 Landlock 在使用這些檔案描述符進行操作時會強制執行不同的操作。 當強制執行 Landlock 規則集並且程序保留在強制執行之前和之後開啟的檔案描述符時,可能會發生這種情況。 也可以在程序之間傳遞此類檔案描述符,保留其 Landlock 屬性,即使某些涉及的程序沒有強制執行 Landlock 規則集。

相容性

向後和向前相容性

Landlock 旨在與核心的過去和未來版本相容。 這要歸功於系統呼叫屬性和關聯的位標誌,特別是規則集的handled_access_fs 。 使處理的訪問許可權明確可以使核心和使用者空間彼此之間有一個清晰的合同。 這是確保沙箱化不會隨著系統更新而變得更嚴格(這可能會破壞應用程式)所必需的。

開發人員可以訂閱Landlock 郵件列表,以便有意使用最新的可用功能更新和測試其應用程式。 為了使用者的利益,並且因為他們可能使用不同的核心版本,強烈建議遵循盡力而為的安全方法,方法是在執行時檢查 Landlock ABI 版本並且僅強制執行支援的功能。

Landlock ABI 版本

可以使用sys_landlock_create_ruleset()系統呼叫讀取 Landlock ABI 版本

int abi;

abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 0) {
    switch (errno) {
    case ENOSYS:
        printf("Landlock is not supported by the current kernel.\n");
        break;
    case EOPNOTSUPP:
        printf("Landlock is currently disabled.\n");
        break;
    }
    return 0;
}
if (abi >= 2) {
    printf("Landlock supports LANDLOCK_ACCESS_FS_REFER.\n");
}

第一個 ABI 版本隱式支援以下核心介面。 僅從特定版本支援的功能會明確標記為這樣。

核心介面

訪問許可權

可以透過屬性(例如,struct landlock_path_beneath_attr)定義核心物件上的一組操作,包括訪問的位掩碼。

檔案系統標誌

這些標誌允許將沙箱程序限制為對檔案和目錄執行的一組操作。 在沙箱化之前開啟的檔案或目錄不受這些限制的約束。

以下訪問許可權僅適用於檔案

  • LANDLOCK_ACCESS_FS_EXECUTE:執行檔案。

  • LANDLOCK_ACCESS_FS_WRITE_FILE:以寫入訪問許可權開啟檔案。 開啟檔案進行寫入時,通常還需要LANDLOCK_ACCESS_FS_TRUNCATE許可權。 在許多情況下,這些系統呼叫會在覆蓋現有檔案時截斷它們(例如,creat(2))。

  • LANDLOCK_ACCESS_FS_READ_FILE:以讀取訪問許可權開啟檔案。

  • LANDLOCK_ACCESS_FS_TRUNCATE:使用truncate(2)ftruncate(2)creat(2)open(2)O_TRUNC截斷檔案。 自 Landlock ABI 的第三個版本以來,此訪問許可權可用。

是否可以使用ftruncate(2)截斷開啟的檔案或與ioctl(2)一起使用,是在open(2)期間確定的,其方式與使用LANDLOCK_ACCESS_FS_READ_FILELANDLOCK_ACCESS_FS_WRITE_FILEopen(2)期間檢查讀取和寫入許可權的方式相同。

目錄可以接收與檔案或目錄相關的訪問許可權。 以下訪問許可權適用於目錄本身及其下方的目錄

  • LANDLOCK_ACCESS_FS_READ_DIR:開啟目錄或列出其內容。

但是,以下訪問許可權僅適用於目錄的內容,而不適用於目錄本身

  • LANDLOCK_ACCESS_FS_REMOVE_DIR:刪除空目錄或重新命名目錄。

  • LANDLOCK_ACCESS_FS_REMOVE_FILE:取消連結(或重新命名)檔案。

  • LANDLOCK_ACCESS_FS_MAKE_CHAR:建立(或重新命名或連結)字元裝置。

  • LANDLOCK_ACCESS_FS_MAKE_DIR:建立(或重新命名)目錄。

  • LANDLOCK_ACCESS_FS_MAKE_REG:建立(或重新命名或連結)常規檔案。

  • LANDLOCK_ACCESS_FS_MAKE_SOCK:建立(或重新命名或連結)UNIX 域套接字。

  • LANDLOCK_ACCESS_FS_MAKE_FIFO:建立(或重新命名或連結)命名管道。

  • LANDLOCK_ACCESS_FS_MAKE_BLOCK:建立(或重新命名或連結)塊裝置。

  • LANDLOCK_ACCESS_FS_MAKE_SYM:建立(或重新命名或連結)符號連結。

  • LANDLOCK_ACCESS_FS_REFER:將檔案從一個不同的目錄連結或重新命名到另一個目錄(即,重新確定檔案層次結構的父目錄)。

    自 Landlock ABI 的第二個版本以來,此訪問許可權可用。

    這是任何規則集預設拒絕的唯一訪問許可權,即使未在規則集建立時將其指定為處理。 要使規則集授予此許可權的唯一方法是明確允許它用於特定目錄,方法是向規則集新增匹配的規則。

    特別是,當使用第一個 Landlock ABI 版本時,Landlock 將始終拒絕在不同目錄之間重新確定檔案父目錄的嘗試。

    除了源目錄和目標目錄具有LANDLOCK_ACCESS_FS_REFER訪問許可權外,嘗試的連結或重新命名操作還必須滿足以下約束

    • 重新確定的檔案的訪問許可權在目標目錄中不得超過其先前在源目錄中擁有的訪問許可權。 如果嘗試這樣做,則操作將導致EXDEV錯誤。

    • 連結或重新命名時,必須為目標目錄授予相應檔案型別的LANDLOCK_ACCESS_FS_MAKE_*許可權。 否則,操作將導致EACCES錯誤。

    • 重新命名時,必須為源目錄授予相應檔案型別的LANDLOCK_ACCESS_FS_REMOVE_*許可權。 否則,操作將導致EACCES錯誤。

    如果未滿足多個要求,則EACCES錯誤程式碼優先於EXDEV

以下訪問許可權同時適用於檔案和目錄

  • LANDLOCK_ACCESS_FS_IOCTL_DEV:在開啟的字元或塊裝置上呼叫ioctl(2)命令。

    此訪問許可權適用於裝置驅動程式實現的所有ioctl(2)命令。 但是,以下常見 IOCTL 命令繼續可以呼叫,而與LANDLOCK_ACCESS_FS_IOCTL_DEV許可權無關

    • 面向檔案描述符的 IOCTL 命令(FIOCLEXFIONCLEX),

    • 面向檔案描述的 IOCTL 命令(FIONBIOFIOASYNC),

    • 面向檔案系統的 IOCTL 命令(FIFREEZEFITHAWFIGETBSZFS_IOC_GETFSUUIDFS_IOC_GETFSSYSFSPATH

    • 某些 IOCTL 命令在與裝置一起使用時沒有意義,但它們的實現是安全的並返回正確的錯誤程式碼(FS_IOC_FIEMAPFICLONEFICLONERANGEFIDEDUPERANGE

    自 Landlock ABI 的第五個版本以來,此訪問許可權可用。

警告

目前無法限制可透過這些 syscall 系列訪問的某些檔案相關操作:chdir(2)stat(2)flock(2)chmod(2)chown(2)setxattr(2)utime(2)fcntl(2)access(2)。 未來的 Landlock 演變將能夠限制它們。

網路標誌

這些標誌允許將沙箱程序限制為一組網路操作。

自 Landlock ABI 版本 4 起,支援此功能。

以下訪問許可權適用於 TCP 埠號

  • LANDLOCK_ACCESS_NET_BIND_TCP:將 TCP 套接字繫結到本地埠。

  • LANDLOCK_ACCESS_NET_CONNECT_TCP:將活動 TCP 套接字連線到遠端埠。

範圍標誌

這些標誌允許將沙箱程序與一組 IPC 操作隔離。 為規則集設定標誌會將 Landlock 域隔離,以禁止連線到域外的資源。

自 Landlock ABI 版本 6 起,支援此功能。

範圍

  • LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET:限制沙箱程序連線到由相關 Landlock 域外的程序(例如,父域或非沙箱程序)建立的抽象 UNIX 套接字。

  • LANDLOCK_SCOPE_SIGNAL: 限制沙盒程序向域外的另一個程序傳送訊號。

建立新的規則集

long sys_landlock_create_ruleset(const struct landlock_ruleset_attr __user *const attr, const size_t size, const __u32 flags)

建立一個新的規則集

引數

const struct landlock_ruleset_attr __user *const attr

指向 struct landlock_ruleset_attr 的指標,用於標識新規則集的範圍。

const size_t size

指向的 struct landlock_ruleset_attr 的大小(用於向後和向前相容)。

const __u32 flags

支援的值

  • LANDLOCK_CREATE_RULESET_VERSION

  • LANDLOCK_CREATE_RULESET_ERRATA

描述

此係統呼叫允許建立一個新的 Landlock 規則集,並在成功時返回相關的檔案描述符。

如果設定了 LANDLOCK_CREATE_RULESET_VERSIONLANDLOCK_CREATE_RULESET_ERRATA,則 attr 必須為 NULL,且 size 必須為 0。

可能返回的錯誤有

  • EOPNOTSUPP: 核心支援 Landlock,但在啟動時被停用;

  • EINVAL: 未知的 flags,或未知的訪問許可權,或未知的範圍,或太小的 size;

  • E2BIG: attrsize 不一致;

  • EFAULT: attrsize 不一致;

  • ENOMSG: 空的 landlock_ruleset_attr.handled_access_fs

標誌

LANDLOCK_CREATE_RULESET_VERSION

獲取最高支援的 Landlock ABI 版本 (從 1 開始)。

LANDLOCK_CREATE_RULESET_ERRATA

獲取當前 Landlock ABI 版本中已修復問題的位掩碼。

struct landlock_ruleset_attr

規則集定義。

定義:

struct landlock_ruleset_attr {
    __u64 handled_access_fs;
    __u64 handled_access_net;
    __u64 scoped;
};

成員

handled_access_fs

處理的檔案系統操作的位掩碼 (參見 檔案系統標誌)。

handled_access_net

處理的網路操作的位掩碼 (參見 網路標誌)。

scoped

作用域的位掩碼 (參見 作用域標誌),限制 Landlock 域訪問外部資源 (例如,IPC)。

描述

sys_landlock_create_ruleset() 的引數。

此結構定義了一組處理的訪問許可權,即對不同物件型別的一組操作,當規則集生效時,這些操作應預設被拒絕。 反之,此處未明確列出的訪問許可權,當規則集生效時,不會被該規則集拒絕。

由於歷史原因,即使 handled_access_fs 中未設定其位,LANDLOCK_ACCESS_FS_REFER 許可權始終預設被拒絕。 為了新增具有此訪問許可權的新規則,仍然必須顯式設定該位 (參見 檔案系統標誌)。

顯式列出處理的訪問許可權是出於向後相容性考慮。 在大多數用例中,使用 Landlock 的程序將處理它們在構建時瞭解的(並且已經在支援所有這些許可權的核心上測試過的)各種或所有訪問許可權。

此結構在未來的 Landlock 版本中可能會增長。

擴充套件規則集

long sys_landlock_add_rule(const int ruleset_fd, const enum landlock_rule_type rule_type, const void __user *const rule_attr, const __u32 flags)

向規則集新增新規則

引數

const int ruleset_fd

與應使用新規則擴充套件的規則集繫結的檔案描述符。

const enum landlock_rule_type rule_type

標識 rule_attr 指向的結構型別:LANDLOCK_RULE_PATH_BENEATHLANDLOCK_RULE_NET_PORT

const void __user *const rule_attr

指向規則的指標 (與 rule_type 匹配)。

const __u32 flags

必須為 0。

描述

此係統呼叫允許定義新規則並將其新增到現有規則集。

可能返回的錯誤有

  • EOPNOTSUPP: 核心支援 Landlock,但在啟動時被停用;

  • EAFNOSUPPORT: rule_typeLANDLOCK_RULE_NET_PORT,但執行中的核心不支援 TCP/IP;

  • EINVAL: flags 不為 0;

  • EINVAL: 規則訪問不一致 (即,landlock_path_beneath_attr.allowed_accesslandlock_net_port_attr.allowed_access 不是規則集處理的訪問許可權的子集)

  • EINVAL: landlock_net_port_attr.port 大於 65535;

  • ENOMSG: 空訪問 (例如,landlock_path_beneath_attr.allowed_access 為 0);

  • EBADF: ruleset_fd 不是當前執行緒的檔案描述符,或者 rule_attr 的成員不是預期的檔案描述符;

  • EBADFD: ruleset_fd 不是規則集檔案描述符,或者 rule_attr 的成員不是預期的檔案描述符型別;

  • EPERM: ruleset_fd 沒有對底層規則集的寫入訪問許可權;

  • EFAULT: rule_attr 不是有效的地址。

enum landlock_rule_type

Landlock 規則型別

常量

LANDLOCK_RULE_PATH_BENEATH

struct landlock_path_beneath_attr 的型別。

LANDLOCK_RULE_NET_PORT

struct landlock_net_port_attr 的型別。

描述

sys_landlock_add_rule() 的引數。

struct landlock_path_beneath_attr

路徑層次結構定義

定義:

struct landlock_path_beneath_attr {
    __u64 allowed_access;
    __s32 parent_fd;
};

成員

allowed_access

此檔案層次結構允許的操作的位掩碼 (參見 檔案系統標誌)。

parent_fd

檔案描述符,最好使用 O_PATH 開啟,用於標識檔案層次結構的父目錄,或僅標識一個檔案。

描述

sys_landlock_add_rule() 的引數。

struct landlock_net_port_attr

網路埠定義

定義:

struct landlock_net_port_attr {
    __u64 allowed_access;
    __u64 port;
};

成員

allowed_access

埠允許的網路操作的位掩碼 (參見 網路標誌)。

port

主機位元組序中的網路埠。

應該注意的是,傳遞給 bind(2) 的埠 0 將繫結到臨時埠範圍內的可用埠。 這可以透過 /proc/sys/net/ipv4/ip_local_port_range sysctl 進行配置(也用於 IPv6)。

具有埠 0 和 LANDLOCK_ACCESS_NET_BIND_TCP 許可權的 Landlock 規則表示允許請求繫結到埠 0,它將自動轉換為繫結到相關的埠範圍。

描述

sys_landlock_add_rule() 的引數。

強制執行規則集

long sys_landlock_restrict_self(const int ruleset_fd, const __u32 flags)

在呼叫執行緒上強制執行規則集

引數

const int ruleset_fd

與要與目標合併的規則集繫結的檔案描述符。

const __u32 flags

支援的值

  • LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF

  • LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON

  • LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF

描述

此係統呼叫允許在當前執行緒上強制執行 Landlock 規則集。 強制執行規則集要求任務在其名稱空間中具有 CAP_SYS_ADMIN 或以 no_new_privs 執行。 這避免了非特權任務會影響特權子程序的行為的情況。

可能返回的錯誤有

  • EOPNOTSUPP: 核心支援 Landlock,但在啟動時被停用;

  • EINVAL: flags 包含未知位。

  • EBADF: ruleset_fd 不是當前執行緒的檔案描述符;

  • EBADFD: ruleset_fd 不是規則集檔案描述符;

  • EPERM: ruleset_fd 沒有對底層規則集的讀取訪問許可權,或者當前執行緒未以 no_new_privs 執行,或者在其名稱空間中沒有 CAP_SYS_ADMIN

  • E2BIG: 當前執行緒已達到堆疊規則集的最大數量。

標誌

預設情況下,源自沙盒自身的程式的拒絕訪問將透過審計子系統記錄。 此類事件通常指示意外行為,例如錯誤或利用嘗試。 但是,為了避免過度記錄,預設情況下,不由發起程式建立的域拒絕的訪問請求不會被記錄。 理由是程式應該知道自己的行為,但不一定知道其他程式的行為。 此預設配置適用於大多數沙盒自身的程式。 對於特定用例,以下標誌允許程式修改此預設日誌記錄行為。

LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFFLANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON 標誌應用於新建立的 Landlock 域。

LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF

停用源自建立 Landlock 域的執行緒及其子程序的拒絕訪問的日誌記錄,只要它們繼續執行相同的可執行程式碼(即,沒有中間的 execve(2) 呼叫)。 這適用於在不呼叫 execve(2) 的情況下執行未知程式碼的程式,例如指令碼直譯器。 僅沙盒自身的程式不應設定此標誌,以便可以透過系統日誌通知使用者未經授權的訪問嘗試。

LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON

execve(2) 呼叫後啟用拒絕訪問的日誌記錄,從而提供對建立的 Landlock 域內新執行程式未經授權的訪問嘗試的可見性。 僅當域中所有潛在的可執行檔案都應符合訪問限制時,才建議使用此標誌,因為過多的審計日誌條目可能會使識別關鍵事件變得更加困難。

LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF

停用源自呼叫方或其後代建立的巢狀 Landlock 域的拒絕訪問的日誌記錄。 應根據執行時配置設定此標誌,而不是硬編碼,以避免抑制重要的安全事件。 它對於容器執行時或沙盒工具非常有用,這些工具可能會啟動本身建立 Landlock 域的程式,否則可能會生成過多的日誌。 與 LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF 不同,此標誌僅影響未來的巢狀域,而不影響正在建立的域。 它也可以與值為 -1 的 ruleset_fd 一起使用,以使子域日誌靜音而不建立域。

當前限制

檔案系統拓撲修改

使用檔案系統限制進行沙盒化的執行緒無法修改檔案系統拓撲,無論是透過 mount(2) 還是 pivot_root(2)。 但是,不拒絕 chroot(2) 呼叫。

特殊檔案系統

可以透過 Landlock 限制對常規檔案和目錄的訪問,具體取決於規則集的處理的訪問許可權。 但是,不來自使用者可見的檔案系統(例如管道,套接字)的檔案,但仍然可以透過 /proc/<pid>/fd/* 訪問,目前無法明確限制。 同樣,某些特殊的核心檔案系統(例如 nsfs),可以透過 /proc/<pid>/ns/* 訪問,目前也無法明確限制。 但是,由於 ptrace 限制,對這些敏感 /proc 檔案的訪問會根據域層次結構自動受到限制。 未來的 Landlock 演變仍然可以透過專用的規則集標誌來明確限制此類路徑。

規則集層

堆疊規則集限制為 16 層。 對於希望在其 16 個繼承的規則集之外強制執行新規則集的任務,這可能是一個問題。 一旦達到此限制,sys_landlock_restrict_self() 將返回 E2BIG。 然後強烈建議線上程的生命週期中仔細構建規則集一次,特別是對於能夠啟動其他可能也想沙盒化自身的應用程式的應用程式(例如,shell,容器管理器等)。

記憶體使用情況

分配用於建立規則集的核心記憶體會被記錄,並且可以透過 記憶體資源控制器 來限制。

IOCTL 支援

LANDLOCK_ACCESS_FS_IOCTL_DEV 許可權限制了 ioctl(2) 的使用,但它僅適用於新開啟的裝置檔案。 這明確意味著預先存在的檔案描述符(如 stdin,stdout 和 stderr)不受影響。

使用者應該意識到,傳統上,TTY 裝置允許透過 TIOCSTITIOCLINUX IOCTL 命令來控制同一 TTY 上的其他程序。 這兩者都需要現代 Linux 系統上的 CAP_SYS_ADMIN,但是 TIOCSTI 的行為是可配置的。

因此,在較舊的系統上,建議關閉繼承的 TTY 檔案描述符,或者從 /proc/self/fd/* 重新開啟它們,而無需 LANDLOCK_ACCESS_FS_IOCTL_DEV 許可權(如果可能)。

目前,Landlock 的 IOCTL 支援是粗粒度的,但將來可能會變得更細粒度。 在那之前,建議使用者透過檔案層次結構建立他們需要的保證,僅在真正需要的地方允許 LANDLOCK_ACCESS_FS_IOCTL_DEV 許可權。

以前的限制

檔案重新命名和連結 (ABI < 2)

由於 Landlock 的目標是無特權訪問控制,因此它需要正確處理規則的組合。 這種屬性也意味著規則巢狀。 正確處理多個規則集層,每個規則集都能夠限制對檔案的訪問,也意味著從父級到其層次結構繼承規則集限制。 由於檔案是透過其層次結構來識別和限制的,因此將檔案從一個目錄移動或連結到另一個目錄意味著層次結構約束的傳播,或者根據可能丟失的約束來限制這些操作。 為了防止透過重新命名或連結進行特權提升,並且為了簡單起見,Landlock 以前將連結和重新命名限制為同一目錄。 從 Landlock ABI 版本 2 開始,由於有了新的 LANDLOCK_ACCESS_FS_REFER 訪問許可權,現在可以安全地控制重新命名和連結。

檔案截斷 (ABI < 3)

在第三個 Landlock ABI 之前,檔案截斷無法被拒絕,因此在使用僅支援第一個或第二個 ABI 的核心時,始終允許檔案截斷。

從 Landlock ABI 版本 3 開始,由於有了新的 LANDLOCK_ACCESS_FS_TRUNCATE 訪問許可權,現在可以安全地控制截斷。

TCP 繫結和連線 (ABI < 4)

從 Landlock ABI 版本 4 開始,由於有了新的 LANDLOCK_ACCESS_NET_BIND_TCPLANDLOCK_ACCESS_NET_CONNECT_TCP 訪問許可權,現在可以將 TCP 繫結和連線操作限制為僅一組允許的埠。

裝置 IOCTL (ABI < 5)

在第五個 Landlock ABI 之前,無法拒絕 IOCTL 操作,因此在使用僅支援早期 ABI 的核心時,始終允許 ioctl(2)

從 Landlock ABI 版本 5 開始,可以使用新的 LANDLOCK_ACCESS_FS_IOCTL_DEV 許可權來限制在字元和塊裝置上使用 ioctl(2)

抽象 UNIX 套接字 (ABI < 6)

從 Landlock ABI 版本 6 開始,可以透過將 LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET 設定為 scoped 規則集屬性來限制與抽象 unix(7) 套接字的連線。

訊號 (ABI < 6)

從 Landlock ABI 版本 6 開始,可以透過將 LANDLOCK_SCOPE_SIGNAL 設定為 scoped 規則集屬性來限制 signal(7) 傳送。

日誌記錄 (ABI < 7)

從 Landlock ABI 版本 7 開始,可以透過傳遞給 sys_landlock_restrict_self()LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFFLANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ONLANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF 標誌來控制 Landlock 審計事件的日誌記錄。有關審計的更多詳細資訊,請參見 Landlock: 系統範圍管理

核心支援

構建時配置

Landlock 最初是在 Linux 5.13 中引入的,但必須在構建時使用 CONFIG_SECURITY_LANDLOCK=y 進行配置。Landlock 還必須像其他安全模組一樣在啟動時啟用。預設情況下啟用的安全模組列表由 CONFIG_LSM 設定。然後,核心配置應包含 CONFIG_LSM=landlock,[...],其中 [...] 是執行系統可能需要的其他安全模組的列表(請參閱 CONFIG_LSM 幫助)。

啟動時配置

如果執行的核心在 CONFIG_LSM 中沒有 landlock,那麼我們可以透過在啟動載入器配置中的 核心命令列引數 中新增 lsm=landlock,[...] 來啟用 Landlock。

例如,如果當前的內建配置是

$ zgrep -h "^CONFIG_LSM=" "/boot/config-$(uname -r)" /proc/config.gz 2>/dev/null
CONFIG_LSM="lockdown,yama,integrity,apparmor"

...並且如果 cmdline 也不包含 landlock

$ sed -n 's/.*\(\<lsm=\S\+\).*/\1/p' /proc/cmdline
lsm=lockdown,yama,integrity,apparmor

...我們應該配置啟動載入器以設定一個 cmdline,用 landlock, 字首擴充套件 lsm 列表

lsm=landlock,lockdown,yama,integrity,apparmor

重啟後,我們可以透過檢視核心日誌來檢查 Landlock 是否已啟動並正在執行

# dmesg | grep landlock || journalctl -kb -g landlock
[    0.000000] Command line: [...] lsm=landlock,lockdown,yama,integrity,apparmor
[    0.000000] Kernel command line: [...] lsm=landlock,lockdown,yama,integrity,apparmor
[    0.000000] LSM: initializing lsm=lockdown,capability,landlock,yama,integrity,apparmor
[    0.000000] landlock: Up and running.

核心可能在構建時配置為始終載入 lockdowncapability LSM。 在這種情況下,即使這些 LSM 沒有在啟動載入器中配置,它們也會出現在 LSM: initializing 日誌行的開頭。

網路支援

為了能夠顯式地允許 TCP 操作(例如,新增具有 LANDLOCK_ACCESS_NET_BIND_TCP 的網路規則),核心必須支援 TCP (CONFIG_INET=y)。否則,sys_landlock_add_rule() 會返回 EAFNOSUPPORT 錯誤,可以安全地忽略它,因為這種 TCP 操作已經不可能了。

問題與解答

使用者空間沙箱管理器怎麼樣?

使用使用者空間程序來強制執行對核心資源的限制可能會導致競爭條件或不一致的評估(即 作業系統程式碼和狀態的不正確映象)。

名稱空間和容器怎麼樣?

名稱空間可以幫助建立沙箱,但它們並非為訪問控制而設計,因此缺少此類用例的有用功能(例如,沒有細粒度的限制)。此外,它們的複雜性可能導致安全問題,尤其是在不受信任的程序可以操縱它們時(參見 控制對使用者名稱空間的訪問)。

如何停用 Landlock 審計記錄?

您可能需要按照此處的說明設定過濾器:Landlock: 系統範圍管理

附加文件