C/C++에서 system() 호출의 상속 가능한 함수

C/C++에서 system() 호출의 상속 가능한 함수

현재 나는 다음을 읽으면서 Linux의 기능을 이해하려고 노력하고 있습니다.http://man7.org/linux/man-pages/man7/capability.7.html

다음 기능을 사용하여 작은 C++ 응용 프로그램을 만들었습니다.CAP_DAC_READ_SEARCH+eip

이 기능은 앱에 적합합니다. 하지만 내 system()안에 전화기가 있어

system("cat /dev/mtdX > targetFile");

이 호출의 기능을 어떻게 상속받을 수 있나요?

편집하다:

나는 이것이 +에 의해 구동 system()된다는 것을 알고 있습니다 . 문서에는 하위 프로세스가 상위 프로세스와 동일한 기능을 갖는다고 언급되어 있습니다. 그런데 왜 읽는 능력은 유전되지 않습니까?fork()execl()fork()

답변1

우선, system(3)제안한 것과 다를 system(3)뿐만 아니라 fork+exec신호 구성 변경, 하위 프로세스 대기 및 /bin/sh래퍼로 사용하는 것과 관련된 다소 복잡한 작업입니다(환경에 따라 다를 수 있음). 관리자의 변덕과 가정) 기능을 제거하거나 추가하고, 환경 변수를 엉망으로 만들고, 소스 초기화 스크립트 및 기타 재미있는 일을 합니다. execv*(2)대신에 just를 사용하면 system(3)이러한 모든 허위 합병증이 제거됩니다.

둘째, '기간별 역량 변화' 섹션을 자세히 살펴봐야 합니다 execve().capabilities(7)맨페이지. 여기에 복사하여 붙여넣지는 않겠지만 기본적으로 다음과 같이 요약됩니다.함수는 다음에 추가되지 않는 한 execve()를 통해 상속되지 않습니다.주변놓다스레드(프로세스)의 상속 가능한 집합에 이미 있지 않으면 거기에 추가할 수 없습니다.철사. (파일 메타데이터의 "상속 가능" 기능은마스크, 스레드를 제한하는 것).

execve()그러므로 상속받은 능력을 갖기 위해서는ㅏ)그것들을 제거하세요허용된도착하다상속 가능한설정 (당신은 사용할 수 있습니다capset(2)시스템 호출[1]) 및비)에 추가하세요주변설정 (당신은 사용할 수 있습니다prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE)).

함께 넣어보세요:

$ cat capexec.c
#include <sys/prctl.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/capability.h>
#include <err.h>
int main(int ac, char **av){
        static char *dav[] = { "/bin/bash", 0 };

        struct __user_cap_header_struct hs;
        struct __user_cap_data_struct ds[2];
        hs.version = 0x20080522; /*_LINUX_CAPABILITY_VERSION_3;*/
        hs.pid = getpid();
        if(syscall(SYS_capget, &hs, ds)) err(1, "capget");
        ds[0].inheritable = ds[0].permitted;
        if(syscall(SYS_capset, &hs, ds)) err(1, "capset");

        if(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0)) err(1, "prctl(pr_cap_ambient_raise)");

        av = ac < 2 ? dav : av + 1;
        execvp(*av, av);
        err(1, "execvp %s", *av);
}
$ cc -Wall capexec.c -o capexec

   # as root
# setcap cap_dac_read_search+ip /tmp/capexec

$ ./capexec dd if=/dev/sda of=/dev/null count=1
1+0 records in
1+0 records out
512 bytes copied, 0.000299173 s, 1.7 MB/s

[1] 문서에서는 libcap 라이브러리 사용을 권장합니다. 이 예제의 일부는 libcap이 없고 많은 헤더 정의가 누락된 이전 버전의 Android용으로 작성한 해킹에서 제거되었습니다. libcap 래퍼를 사용하도록 이를 변환하는 것은 독자의 연습 과제로 남겨집니다.

답변2

@mosvy에게 감사드립니다. libcap을 사용하여 그의 솔루션을 구현했는데 예상대로 작동하는 것 같습니다.

void inheritCapabilities()
{
    cap_t caps;
    caps = cap_get_proc();
    if (caps == NULL)
        throw "Failed to load capabilities";
    printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
    cap_value_t cap_list[1];
    cap_list[0] = CAP_DAC_READ_SEARCH;
    if (cap_set_flag(caps, CAP_INHERITABLE, 1, cap_list, CAP_SET) == -1)
        throw "Failed to set inheritable";
    printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
    if (cap_set_proc(caps) == -1)
        throw "Failed to set proc";
    printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));
    caps = cap_get_proc();
    if (caps == NULL)
        throw "Failed to load capabilities";
    printf("DEBUG: Loaded Capabilities: %s\n", cap_to_text(caps, NULL));

    if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_DAC_READ_SEARCH, 0, 0) == -1)
        throw "Failed to pr_cap_ambient_raise!    Error: " + errno;
}

main() {
    inheritCapabilities();

    char *catargv[5];
    catargv[0] = (char *)"cmd";
    catargv[1] = (char *)"arg1";
    catargv[2] = (char *)"arg2";
    catargv[3] = (char *)"arg3";
    catargv[4] = NULL;

    if (execvp(catargv[0], catargv) == -1)
        throw "Failed! command";
}

관련 정보