현재 나는 다음을 읽으면서 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";
}