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包裝器(這可能會根據其維護者的突發奇想和假設而刪除或添加功能,弄亂環境變量,來源初始化腳本,以及其他有趣的事情)。使用 justexecv*(2)代替system(3)會消除所有這些虛假的併發症。

其次,你應該深入了解「期間能力的轉變execve()」部分。capabilities(7)線上幫助頁。我不打算在這裡複製貼上它,但它基本上可以歸結為:功能不會透過 execve() 繼承,除非它們被加入到周圍的執行緒(進程)的,並且不能將它們添加到那裡,除非它們已經在執行緒(進程)的可繼承集中。 (檔案元資料中的「可繼承」功能只是一個面具,限制線程的那些)。

因此,為了擁有繼承的能力,execve()你應該A)將它們從允許的可繼承的設定(你可以用capset(2)系統調用 [1]) 和b)將它們添加到周圍的設定(你可以用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 函式庫;這個例子的部分內容是從我為舊版的 android 編寫的 hack 中刪除的,其中沒有 libcap,缺少許多標頭定義。將其轉換為使用 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";
}

相關內容