프로세스가 Linux에서 새 파일 설명자를 열지 못하도록하지만 소켓을 통해 파일 설명자를 수신 할 수 있습니다.


9

현재 소켓 쌍, 포크를 설정 한 다음이 소켓 쌍을 사용하여 통신하는 부모 프로세스가있는 프로젝트를 진행하고 있습니다. 자식은 파일 (또는 다른 파일 설명자 기반 리소스)을 열려면 항상 부모에게 가서 리소스를 요청 fd하고 소켓 쌍을 통해 전송 해야합니다 . 또한 자식이 파일 설명자를 자체적으로 열지 못하게하고 싶습니다.

나는 setrlimit자식이 새 파일 설명자를 열지 못하게 막았 지만 초기 소켓 연결을 통해 전송 된 모든 파일 설명자를 무효화하는 것처럼 보입니다. Linux에서 단일 프로세스가 파일을 열고 파일 설명자를 다른 프로세스로 보내고 다른 프로세스가 파일 설명자를 자체적으로 열도록 허용하지 않고 사용할 수 있도록하는 방법이 있습니까?

내 유스 케이스의 경우 포크 후 적용 할 수 있고 모든 파일 설명자 (파일뿐만 아니라 소켓, 소켓 쌍 등)에 적용되는 한 커널 구성, 시스템 호출 등이 될 수 있습니다.


1
seccomp에 관심이있을 수 있습니다.
user253751

답변:


6

여기에있는 것은 정확히 seccomp 의 사용 사례입니다 .

seccomp를 사용하면 다양한 방식으로 syscall을 필터링 할 수 있습니다. 당신이이 상황에서하고 싶은 직후 인 fork()설치, seccomp사용을 허용하지 필터 open(2), openat(2), socket(2)(등을). 이를 위해 다음을 수행 할 수 있습니다.

  1. 먼저 seccomp_init(3)기본 동작 인을 사용하여 seccomp 컨텍스트를 작성하십시오 SCMP_ACT_ALLOW.
  2. 그런 다음 seccomp_rule_add(3)거부하려는 각 syscall을 사용하여 컨텍스트에 규칙을 추가하십시오 . SCMP_ACT_KILLsyscall을 시도하거나 syscall이 SCMP_ACT_ERRNO(val)지정된 errno값 또는 action매뉴얼 페이지에 정의 된 다른 값을 리턴하지 못하도록 프로세스를 종료 하는 데 사용할 수 있습니다 .
  3. 컨텍스트를 사용하여로드하십시오 seccomp_load(3).

계속하기 전에 주의를 이와 같은 블랙리스트 접근 방식은 일반적으로 화이트리스트 방식보다 약한이다. 명시 적으로 허용되지 않아서 필터를 무시할 수있는 모든 syscall을 허용 합니다 . 실행하려는 자식 프로세스가 필터를 피하려고 악의적으로 시도한다고 생각되거나 자식이 어떤 syscall을 필요로하는지 이미 알고 있다면 화이트리스트 접근 방식이 더 좋으며 위와 반대의 작업을 수행해야합니다. 기본 동작으로 필터를 만들고로 SCMP_ACT_KILL필요한 syscall을 허용합니다 SCMP_ACT_ALLOW. 코드 측면에서 차이는 최소화됩니다 (허용 목록이 더 길지만 단계는 동일 함).

위의 예는 다음과 같습니다 ( exit(-1)단순히하기 위해 오류가 발생했을 때 하고 있습니다 ).

#include <stdlib.h>
#include <seccomp.h>

static void secure(void) {
    int err;
    scmp_filter_ctx ctx;

    int blacklist[] = {
        SCMP_SYS(open),
        SCMP_SYS(openat),
        SCMP_SYS(creat),
        SCMP_SYS(socket),
        SCMP_SYS(open_by_handle_at),
        // ... possibly more ...
    };

    // Create a new seccomp context, allowing every syscall by default.
    ctx = seccomp_init(SCMP_ACT_ALLOW);
    if (ctx == NULL)
        exit(-1);

    /* Now add a filter for each syscall that you want to disallow.
       In this case, we'll use SCMP_ACT_KILL to kill the process if it
       attempts to execute the specified syscall. */

    for (unsigned i = 0; i < sizeof(blacklist) / sizeof(blacklist[0]); i++) {
        err = seccomp_rule_add(ctx, SCMP_ACT_KILL, blacklist[i], 0);
        if (err)
            exit(-1);
    }

    // Load the context making it effective.
    err = seccomp_load(ctx);
    if (err)
        exit(-1);
}

이제 프로그램에서 위 함수를 호출하여 다음과 같이 seccomp 필터를 바로 다음에 적용 할 수 있습니다 fork().

child_pid = fork();
if (child_pid == -1)
    exit(-1);

if (child_pid == 0) {
    secure();

    // Child code here...

    exit(0);
} else {
    // Parent code here...
}

seccomp에 대한 몇 가지 중요한 참고 사항 :

  • 일단 적용된 seccomp 필터는 프로세스에 의해 제거되거나 변경 될 수 없습니다.
  • 경우 fork(2)또는 clone(2)필터에 의해 허용되는, 자식 프로세스는 동일한 필터에 의해 제한됩니다.
  • 경우 execve(2)허용되는 기존 필터에 대한 호출을 통해 유지됩니다 execve(2).
  • 경우 prctl(2)콜이 허용되는 프로세스가 더욱 필터를 적용 할 수 있습니다.

2
샌드 박스에 대한 블랙리스트? 일반적으로 나쁜 생각입니다. 대신 화이트리스트를 원합니다.
중복 제거기

@Deduplicator 알고 있지만 화이트리스트 접근 방식은 새 파일 설명자를 여는 것을 허용하지 않기 때문에 OP의 상황에 잘 적용되지 않습니다. 마지막에 메모를 추가하겠습니다.
마르코 보 넬리

답변 주셔서 감사합니다, 그것이 내가 필요한 것입니다. 허용 목록은 원래 의도 한 응용 프로그램에 실제로 더 좋습니다. 파일 디스크립터를 여는 것보다 제한해야 할 것이 더 많다는 것을 생각하지 않았습니다.
jklmnn

맞아요. 나는 socket(2)또한을 만들 수 있다는 것을 잊어 버렸 fd으므로 차단해야합니다. 하위 프로세스를 알고 있으면 화이트리스트 방식이 더 좋습니다.
마르코 보 넬리

@MarcoBonelli 화이트리스트가 확실히 좋습니다. 즉석, creat(), dup(), 및 dup2()리눅스 시스템 호출을 돌려 파일 설명이다. 블랙리스트를 둘러싼 많은 방법이 있습니다 ...
Andrew Henle
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.