프로세스가 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.