%20%ED%98%B8%EC%B6%9C%EC%97%90%20%EB%8C%80%ED%95%B4%20%EC%83%81%EC%86%8D%20%EA%B0%80%EB%8A%A5%ED%95%9C%20%EA%B8%B0%EB%8A%A5.png)
현재 나는 다음을 읽으면서 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)
입니다. 초기화 스크립트 및 기타 재미있는 것들). 대신에 just를 사용하면 모든 허위 합병증을 해결할 수 있습니다.fork+exec
/bin/sh
execv*(2)
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용으로 작성한 해킹으로 인해 canibalized되었습니다. 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";
}