SECCOMP_MODE_FILTER를 호출하기 전에 no_new_privs를 설정해야 하는 이유는 무엇입니까?

SECCOMP_MODE_FILTER를 호출하기 전에 no_new_privs를 설정해야 하는 이유는 무엇입니까?

존재하다매뉴얼 페이지나는 다음 줄을 읽었습니다.

실제로 시스템 호출을 하지 않고 0을 반환하는 대신 호출자의 사용자 ID를 0이 아닌 값으로 설정하기 위해 setuid(2)를 사용하려고 시도합니다.

나는 그들이 무슨 말을 하려는지 이해하지 못합니다. 누구든지 나에게 이것을 설명해 줄 수 있습니까?

감사해요.

답변1

먼저 seccomp(2)맨페이지에서 다음 단락을 참고하세요.

SECCOMP_RET_ERRNO

이 값을 사용하면 필터 반환 값의 SECCOMP_RET_DATA 부분이 시스템 호출을 실행하지 않고 errno 값으로 사용자 공간에 전달됩니다.

따라서 seccomp 필터는 커널을뛰어 넘다대신 실제 시스템 호출이 실행됩니다.어떤 값을 반환도착하다~인 척하다시스템 호출이 실행되어 지정된 결과가 생성되었습니다. 이것은 또한 다룬다성공적인결과, 반환 값이 0으로 설정된 경우.

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)시스템 호출이 0을 반환했음을 알 수 있습니다(즉, "실행"이 성공했습니다) ./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 필터의 기능을 이해했습니다. 귀하의 질문에서 인용한 구절의 요점에 더 가까이 다가가 보겠습니다. 두 가지를 생각해 보세요:

  • 권한이 없는 프로세스는 일부 커널 메커니즘을 사용하여 권한을 높일 수 있습니다.
  • 이 메커니즘을 사용하여 권한을 부여하는 몇 가지 도구가 있습니다.일시적으로제한된 수의 작업에만 사용할 수 있습니다.

전형적인 예는 SUID 소유 바이너리 sudo(8)인 유틸리티 입니다. root권한이 없는 프로세스의 컨텍스트에서 이를 실행하면 호출 프로세스에 전체 수퍼유저 권한(샌드박스 및 컨테이너와 같은 일부 특수한 경우 제외)이 부여된 다음 파일을 sudo(8)검사하여 /etc/sudoers호출 사용자가 요청된 작업을 수행할 수 있는지 확인합니다. 그렇다면 sudo(8)실행은 계속되고, 그렇지 않으면 실행이 거부됩니다. 또한 sudo(8)임의의 사용자를 대신하여 실행할 수 있습니다.요청된 작업을 수행하기 전에 적절한 자격 증명을 설정하십시오..

예를 들어 /etc/sudoers파일에 다음 레코드가 포함되어 있다고 가정합니다.

testuser ALL=(anotheruser) NOPASSWD: /bin/bash

사용자는 다음 명령을 사용하여 자신을 대신하여 셸을 실행할 testuser수 있습니다 .anotheruser

sudo -u anotheruser -i /bin/bash

이제 주제에 더 가까워졌습니다. testuser--소유 프로세스에 seccomp 필터가 설치되어 실제로 실행하지 않고 커널을 setuid(2)롤백 한 다음 sudo -u anotheruser -i /bin/bash? 글쎄, 우리는 다음을 볼 수 있습니다:

  • 커널은 sudo(8)바이너리에서 SUID 비트를 확인하고 호출 프로세스의 권한을 적절하게 높입니다.
  • sudo(8)실행 이 허용되는지 확인 /etc/sudoers하세요 .testuser/bin/bashanotheruser
  • 그런 다음 프로세스의 자격 증명에 대한 적절한 변경 사항을 sudo(8)호출 하고 해당 권한을 "다운그레이드"합니다.setuid(2)
  • 사용자가 설치한 seccomp 필터는 "다운그레이드"가 완료된 것처럼 자동으로 성공을 보고합니다.
  • sudo(8)이제 프로세스가 실행을 나타내고 anotheruser계속 실행된다는 것을 신뢰하십시오 /bin/bash.
  • setuid(2)필터에 의해 건너뛰어 실제로 실행되지 않았기 때문에 실제로 슈퍼 사용자 권한으로 실행했습니다 !

setuid(2)따라서 권한이 없는 사용자가 seccomp 필터를 설치하도록 허용하면 해당 사용자가 호출을 트래핑하여 권한 있는 자격 증명을 "하이재킹"할 수도 있습니다.일시적으로높은 권한으로 실행되므로 맨페이지에 제한 사항이 지정되어 있습니다.

호출 스레드의 사용자 네임스페이스에 CAP_SYS_ADMIN 기능이 있거나 스레드의 no_new_privs 비트가 설정되어 있어야 합니다.

이 문장의 첫 번째 부분의 의미는 분명합니다. CAP_SYS_ADMIN프로세스에 많은 수의 권한을 부여하는 능력이므로 이를 소유한 프로세스가 시스템에 혼란을 일으킬 만큼 강력하다고 가정해도 안전합니다. 두 번째 부분은 어떻습니까?

no_new_privs비트는 프로세스의 속성이며, 설정된 경우 커널에 알려줍니다.아니요SUID 비트와 같은 권한 상승 메커니즘을 사용하면(그러므로 이와 같은 호출은 sudo(8)전혀 작동하지 않음) 이 비트가 설정된 권한 없는 프로세스가 seccomp 필터를 사용하도록 허용하는 것이 안전합니다. 해당 프로세스가 일시적으로라도 권한을 상승시키는 것은 불가능합니다. 따라서 이러한 권한을 "강탈"할 수 있는 방법은 없습니다.

관련 정보