Linux 下 C++ 设置子进程 capability、切换用户、execl调用
2025-08-22 16:03:00,

目录

折腾半天,又是问deepseek又是问朋友,终于解决了。

Linux 有一个能力(capability)机制,相当于是对root权限的细分,你可以把这些权限细分给进程或程序。能力的介绍可以看看这个博客,我就不多说了。

出于安全考虑,我需要给子进程设置能力,同时又要切换到普通用户,再用execl执行别的程序。结果搞半天都没搞定。

关键的地方在于,execl调用可执行文件后的能力,既取决于进程本身,也取决于可执行文件的能力设置。我进行了一些测试,终于是搞定了。以下是一个调用子进程后通过execl执行设定系统时间的程序的例子。设定系统时间需要root权限,或者 CAP_SYS_TIME能力。测试的操作系统为 CentOS 7.6

设定时间的程序

首先,我们执行timedatectl set-ntp false关闭系统自动校时。

然后,写一个设定时间、打印时间然后睡觉的C++程序。

#include <ctime>
#include <iOStream>
#include <sys/time.h>
#include <unistd.h>

// Function to set the system time
void SetSystemTime(const struct tm& newTime) {
    struct timeval tv;
    tv.tv_sec = mktime(const_cast<struct tm*>(&newTime));  // Convert struct tm to time_t
    tv.tv_usec = 0;

    if (settimeofday(&tv, nullptr) != 0) {
        perror("Failed to set system time");
    } else {
        std::cout << "System time successfully updated." << std::endl;
    }
}

void GetSystemTime() {
    time_t now = time(nullptr);
    struct tm* currentTime = localtime(&now);

    std::cout << "Current system time: "
              << (currentTime->tm_year + 1900) << "-"
              << (currentTime->tm_mon + 1) << "-"
              << currentTime->tm_mday << " "
              << currentTime->tm_hour << ":"
              << currentTime->tm_min << ":"
              << currentTime->tm_sec << std::endl;
}

int main() {
    struct tm newTime = {};
    // Set your desired time here
    newTime.tm_year = 2025 - 1900;  // Year since 1900
    newTime.tm_mon = 3 - 1;         // Month (0-11)
    newTime.tm_mday = 9;            // Day of the month
    newTime.tm_hour = 10;           // Hour (0-23)
    newTime.tm_min = 30;            // Minute (0-59)
    newTime.tm_sec = 0;             // Second (0-59)
    SetSystemTime(newTime);
    GetSystemTime();
    sleep(999);
    return 0;
}

编译:

g++ ./setTime.cpp -std=c++11 -o setTime.bin

用sudo运行:

[mario@vbox CPP]$ ./setTime.bin
Failed to set system time: Operation not permitted
Current system time: 2025-3-9 17:1:38
^C
[mario@vbox CPP]$ sudo ./setTime.bin
System time successfully updated.
Current system time: 2025-3-9 10:30:0

运行正确,我们再写一个在子进程中切换用户后设置时间的程序。

子进程切换用户后设置时间

#include <pwd.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdlib>
#include <ctime>
#include <iostream>

// Function to set the system time
void SetSystemTime(const struct tm& newTime) {
    struct timeval tv;
    tv.tv_sec = mktime(const_cast<struct tm*>(&newTime));  // Convert struct tm to time_t
    tv.tv_usec = 0;

    if (settimeofday(&tv, nullptr) != 0) {
        perror("Failed to set system time");
    } else {
        std::cout << "System time successfully updated." << std::endl;
    }
}

void GetSystemTime() {
    time_t now = time(nullptr);
    struct tm* currentTime = localtime(&now);

    std::cout << "Current system time: "
              << (currentTime->tm_year + 1900) << "-"
              << (currentTime->tm_mon + 1) << "-"
              << currentTime->tm_mday << " "
              << currentTime->tm_hour << ":"
              << currentTime->tm_min << ":"
              << currentTime->tm_sec << std::endl;
}

void SetChildCapabilities() {
    cap_t caps;
    cap_value_t cap_list[2];

    // Initialize the capability set
    caps = cap_get_proc();

    // Set the capabilities
    cap_list[0] = CAP_NET_BIND_SERVICE;  // Allow binding to ports < 1024
    cap_list[1] = CAP_SYS_TIME;          // Allow setting system time

    if (cap_set_flag(caps, CAP_PERMITTED, 2, cap_list, CAP_SET) == -1 ||
        cap_set_flag(caps, CAP_EFFECTIVE, 2, cap_list, CAP_SET) == -1 ||
        cap_set_flag(caps, CAP_INHERITABLE, 2, cap_list, CAP_SET) == -1) {
        std::cerr << "Failed to set capabilities.\n";
        exit(EXIT_FAILURE);
    }

    if (cap_set_proc(caps) == -1) {
        std::cerr << "Failed to apply capabilities.\n";
        exit(EXIT_FAILURE);
    }

    cap_free(caps);
}

// Function to preserve capabilities across exec
void PreserveCapabilities() {
    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
        perror("Failed to set PR_SET_KEEPCAPS");
    } else {
        std::cout << "Capabilities will be preserved across exec." << std::endl;
    }
}

void SetParentInhCapabilities() {
    cap_t caps;
    cap_value_t cap_list[2];

    // Initialize the capability set
    caps = cap_get_proc();

    // Set the capabilities
    cap_list[0] = CAP_NET_BIND_SERVICE;  // Allow binding to ports < 1024
    cap_list[1] = CAP_SYS_TIME;          // Allow setting system time

    if (cap_set_flag(caps, CAP_INHERITABLE, 2, cap_list, CAP_SET) == -1) {
        std::cerr << "Failed to set capabilities.\n";
        exit(EXIT_FAILURE);
    }

    if (cap_set_proc(caps) == -1) {
        std::cerr << "Failed to apply capabilities.\n";
        exit(EXIT_FAILURE);
    }

    cap_free(caps);
}

void ChangeUid(uid_t new_uid) {
    if (setuid(new_uid) == -1) {
        std::cerr << "Failed to change UID.\n";
        exit(EXIT_FAILURE);
    }
}

void PrintCapabilities() {
    cap_t caps = cap_get_proc();
    if (caps == nullptr) {
        std::cerr << "Failed to get capabilities.\n";
        exit(EXIT_FAILURE);
    }

    char* cap_text = cap_to_text(caps, nullptr);
    if (cap_text == nullptr) {
        std::cerr << "Failed to convert capabilities to text.\n";
        cap_free(caps);
        exit(EXIT_FAILURE);
    }

    std::cout << "Process capabilities: " << cap_text << std::endl;

    cap_free(caps);
    cap_free(cap_text);
}

int main() {
    // Set capabilities for the parent process
    SetParentInhCapabilities();
    pid_t pid = fork();
    if (pid == -1) {
        std::cerr << "Failed to fork process.\n";
        return EXIT_FAILURE;
    } else if (pid == 0) {
        // Child process
        std::cout << "Child process PID: " << getpid() << std::endl;
        PreserveCapabilities();

        // Set capabilities for the child process
        SetChildCapabilities();
        // Change UID for the child process
        struct passwd* pw = getpwnam("nobody");
        if (pw == nullptr) {
            std::cerr << "Failed to get UID for 'nobody'.\n";
            return EXIT_FAILURE;
        }
        ChangeUid(pw->pw_uid);

        // Set capabilities of the child process
        SetChildCapabilities();

        // Print capabilities in the child process
        PrintCapabilities();

        // Set the new system time
        struct tm newTime = {};

        // Set your desired time here
        newTime.tm_year = 2025 - 1900;  // Year since 1900
        newTime.tm_mon = 3 - 1;         // Month (0-11)
        newTime.tm_mday = 9;            // Day of the month
        newTime.tm_hour = 10;           // Hour (0-23)
        newTime.tm_min = 30;            // Minute (0-59)
        newTime.tm_sec = 0;             // Second (0-59)

        SetSystemTime(newTime);
        GetSystemTime();
        sleep(999);
    } else {
        // Parent process
        std::cout << "Parent process PID: " << getpid() << std::endl;

        // Print capabilities in the parent process
        PrintCapabilities();

        wait(NULL);  // Wait for the child process to finish
    }

    return EXIT_SUCCESS;
}

确认你的系统中有nobody这个用户,否则使用这个命令添加:sudo adduser nobody

运行程序需要安装 libcap-devel.

这个 main 程序的执行结果如下:

[mario@vbox CPP]$ g++ ./main.cpp -std=c++11 -lcap && sudo ./a.out &
[7] 19342
[mario@vbox CPP]$ Parent process PID: 19357
Process capabilities: = cap_net_bind_service,cap_sys_time+eip cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36+ep
Child process PID: 19358
Capabilities will be preserved across exec.
Process capabilities: = cap_net_bind_service,cap_sys_time+eip cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36+p
System time successfully updated.
Current system time: 2025-3-9 10:30:0

最后两行告诉我们,时间设定成功。

查询也显示Cap设置正常:

[mario@vbox CPP]$ cat /proc/19358/status | grep Cap
CapInh:	0000000002000400
CapPrm:	0000001fffffffff
CapEff:	0000000002000400
CapBnd:	0000001fffffffff
CapAmb:	0000000000000000
[mario@vbox CPP]$ capsh --decode=0000000002000400
0x0000000002000400=cap_net_bind_service,cap_sys_time
[mario@vbox CPP]$ getpcaps 19358
Capabilities for `19358': = cap_net_bind_service,cap_sys_time+eip cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36+p

execl 调用

一直到这里,整个功能实现看上去都很简单,但是为什么之前我调不通呢?真是蛋疼,之前我都是在子进程里用execl拉起别的程序,然后再查询的,结果查询出来CapPrm和CapEff都是0,问题就在这execl里,execl 执行的是一个程序,而最终的cap结果是由进程和这个程序文件本身的cap共同决定的!关于exec,可以参考这个博客

我们使用P代表执行exec前的capabilities,P’代表执行exec后的capabilities,F代表exec执行的文件的capabilities。那么:

P’(Permitted) = (P(Inheritable) & F(Inheritable)) | (F(Permitted) & cap_bset)

P’(Effective) = F(Effective) ? P’(Permitted) : 0

P’(Inheritable) = P(Inheritable)

执行 setcap,设置程序文件本身的cap能力。如下所示,给它设置能力为ie后,用普通用户直接运行是无法获得CAP_SYS_TIME权限的。如果设置成ep,普通用户直接执行也能获得权限。如果设置为e,实测getcap不会输出任何权限。

[mario@vbox CPP]$ sudo setcap CAP_SYS_TIME+ie ./setTime.bin
[mario@vbox CPP]$ getcap ./setTime.bin
./setTime.bin = cap_sys_time+ei
[mario@vbox CPP]$ ./setTime.bin
setTime.bin:
Process capabilities: =
Failed to set system time: Operation not permitted
Current system time: 2025-3-9 18:31:37

最终 main.cpp 代码如下:

#include <pwd.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cstdlib>
#include <iostream>

const cap_value_t cap_list[] = {CAP_SYS_TIME};
const unsigned int cap_list_size = sizeof(cap_list) / sizeof(cap_list[0]);

// Function to set the system time
void SetSystemTime(const struct tm& newTime) {
    struct timeval tv;
    tv.tv_sec = mktime(const_cast<struct tm*>(&newTime));  // Convert struct tm to time_t
    tv.tv_usec = 0;

    if (settimeofday(&tv, nullptr) != 0) {
        perror("Failed to set system time");
    } else {
        std::cout << "System time successfully updated." << std::endl;
    }
}

void GetSystemTime() {
    time_t now = time(nullptr);
    struct tm* currentTime = localtime(&now);

    std::cout << "Current system time: "
              << (currentTime->tm_year + 1900) << "-"
              << (currentTime->tm_mon + 1) << "-"
              << currentTime->tm_mday << " "
              << currentTime->tm_hour << ":"
              << currentTime->tm_min << ":"
              << currentTime->tm_sec << std::endl;
}

void SetChildCapabilities() {
    cap_t caps;
    // Initialize the capability set
    caps = cap_get_proc();

    if (cap_set_flag(caps, CAP_INHERITABLE, cap_list_size, cap_list, CAP_SET) == -1 ||
        cap_set_flag(caps, CAP_PERMITTED, cap_list_size, cap_list, CAP_SET) == -1 ||
        cap_set_flag(caps, CAP_EFFECTIVE, cap_list_size, cap_list, CAP_SET) == -1) {
        std::cerr << "Failed to set capabilities.\n";
        exit(EXIT_FAILURE);
    }

    if (cap_set_proc(caps) == -1) {
        std::cerr << "Failed to apply capabilities.\n";
        exit(EXIT_FAILURE);
    }

    cap_free(caps);
}

// Function to preserve capabilities across exec
void PreserveCapabilities() {
    if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
        perror("Failed to set PR_SET_KEEPCAPS");
    } else {
        std::cout << "Capabilities will be preserved across exec." << std::endl;
    }
}

void SetParentInhCapabilities() {
    cap_t caps;
    // Initialize the capability set
    caps = cap_get_proc();

    if (cap_set_flag(caps, CAP_INHERITABLE, cap_list_size, cap_list, CAP_SET) == -1) {
        std::cerr << "Failed to set capabilities.\n";
        exit(EXIT_FAILURE);
    }

    if (cap_set_proc(caps) == -1) {
        std::cerr << "Failed to apply capabilities.\n";
        exit(EXIT_FAILURE);
    }

    cap_free(caps);
}

void ChangeUid(uid_t new_uid) {
    if (setuid(new_uid) == -1) {
        std::cerr << "Failed to change UID.\n";
        exit(EXIT_FAILURE);
    }
}

void PrintCapabilities() {
    cap_t caps = cap_get_proc();
    if (caps == nullptr) {
        std::cerr << "Failed to get capabilities.\n";
        exit(EXIT_FAILURE);
    }

    char* cap_text = cap_to_text(caps, nullptr);
    if (cap_text == nullptr) {
        std::cerr << "Failed to convert capabilities to text.\n";
        cap_free(caps);
        exit(EXIT_FAILURE);
    }

    std::cout << "Process capabilities: " << cap_text << std::endl;

    cap_free(caps);
    cap_free(cap_text);
}

int main() {
    // Set capabilities for the parent process
    pid_t pid = fork();
    if (pid == -1) {
        std::cerr << "Failed to fork process.\n";
        return EXIT_FAILURE;
    } else if (pid == 0) {
        // Child process
        std::cout << "Child process PID: " << getpid() << std::endl;
        PreserveCapabilities();
        SetParentInhCapabilities();
        // Change UID for the child process
        struct passwd* pw = getpwnam("nobody");
        if (pw == nullptr) {
            std::cerr << "Failed to get UID for 'nobody'.\n";
            return EXIT_FAILURE;
        }

        ChangeUid(pw->pw_uid);

        // Set capabilities of the child process
        SetChildCapabilities();

        // Print capabilities in the child process
        PrintCapabilities();

        // Child process code here
        struct tm newTime = {};

        // Set your desired time here
        newTime.tm_year = 2025 - 1900;  // Year since 1900
        newTime.tm_mon = 2 - 1;         // Month (0-11)
        newTime.tm_mday = 9;            // Day of the month
        newTime.tm_hour = 10;           // Hour (0-23)
        newTime.tm_min = 30;            // Minute (0-59)
        newTime.tm_sec = 0;             // Second (0-59)

        // Set the new system time
        SetSystemTime(newTime);
        GetSystemTime();

        execl("/bin/sh", "sh", "-c", "./setTime.bin", NULL);
    } else {
        // Parent process
        std::cout << "Parent process PID: " << getpid() << std::endl;

        // Print capabilities in the parent process
        PrintCapabilities();

        wait(NULL);  // Wait for the child process to finish
    }

    return EXIT_SUCCESS;
}

最终 setTime.cpp 的代码如下

#include <sys/capability.h>
#include <sys/time.h>
#include <unistd.h>
#include <ctime>
#include <iostream>

// Function to set the system time
void SetSystemTime(const struct tm& newTime) {
    struct timeval tv;
    tv.tv_sec = mktime(const_cast<struct tm*>(&newTime));  // Convert struct tm to time_t
    tv.tv_usec = 0;

    if (settimeofday(&tv, nullptr) != 0) {
        perror("Failed to set system time");
    } else {
        std::cout << "System time successfully updated." << std::endl;
    }
}

void GetSystemTime() {
    time_t now = time(nullptr);
    struct tm* currentTime = localtime(&now);

    std::cout << "Current system time: "
              << (currentTime->tm_year + 1900) << "-"
              << (currentTime->tm_mon + 1) << "-"
              << currentTime->tm_mday << " "
              << currentTime->tm_hour << ":"
              << currentTime->tm_min << ":"
              << currentTime->tm_sec << std::endl;
}

void PrintCapabilities() {
    cap_t caps = cap_get_proc();
    if (caps == nullptr) {
        std::cerr << "Failed to get capabilities.\n";
        exit(EXIT_FAILURE);
    }

    char* cap_text = cap_to_text(caps, nullptr);
    if (cap_text == nullptr) {
        std::cerr << "Failed to convert capabilities to text.\n";
        cap_free(caps);
        exit(EXIT_FAILURE);
    }

    std::cout << "Process capabilities: " << cap_text << std::endl;

    cap_free(caps);
    cap_free(cap_text);
}

int main() {
    std::cout << "setTime.bin:" << std::endl;
    cap_t caps;
    caps = cap_get_proc();
    PrintCapabilities();
    struct tm newTime = {};
    // Set your desired time here
    newTime.tm_year = 2025 - 1900;  // Year since 1900
    newTime.tm_mon = 3 - 1;         // Month (0-11)
    newTime.tm_mday = 9;            // Day of the month
    newTime.tm_hour = 10;           // Hour (0-23)
    newTime.tm_min = 30;            // Minute (0-59)
    newTime.tm_sec = 0;             // Second (0-59)
    SetSystemTime(newTime);
    GetSystemTime();
    sleep(999);
    return 0;
}

setTime.cpp 编译命令为 g++ ./setTime.cpp -std=c++11 -lcap -o ./setTime.bin

最终执行成功,结果如下,第一个 Process capabilities 输出的是root的所有权限,第二个是输出的切换用户后的子进程的权限,倒数第三行是setTime.bin的权限输出。输出显示两次设置时间都成功,一次是调用execl前,一次是execl调用setTime.bin。

[mario@vbox CPP]$ g++ ./main.cpp -std=c++11 -lcap && sudo ./a.out
Parent process PID: 12278
Child process PID: 12279
Process capabilities: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36+ep
Capabilities will be preserved across exec.
Process capabilities: = cap_sys_time+eip cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,35,36+p
System time successfully updated.
Current system time: 2025-2-9 10:30:0
setTime.bin:
Process capabilities: = cap_sys_time+eip
System time successfully updated.
Current system time: 2025-3-9 10:30:0

找不到动态库

至此,cap是设定好了,但我们很快会碰到新问题,设置了setcap的程序是无法使用LD_LIBRARY_PATH 的,因为系统认为这不安全。这就导致程序找不到我们在那个变量里设置的动态库。所以我们还需要在 /etc/ld.so.conf.d 文件夹中添加动态库的路径,然后运行sudo ldconfig更新缓存。这个文件夹下的文件内容就是一行行的路径,如下所示:

g++ ./setTime.cpp -std=c++11 -o setTime.bin
0

更多办法来自deepseek:

方法 1:使用 rpath 硬编码库路径

将库路径直接嵌入可执行文件,绕过对 LD_LIBRARY_PATH 的依赖。

  1. 编译时指定 rpath

    g++ ./setTime.cpp -std=c++11 -o setTime.bin
    1
    • -Wl,-rpath 会将库路径写入可执行文件的元数据。
  2. 修改已有二进制文件(需 patchelf 工具)

    g++ ./setTime.cpp -std=c++11 -o setTime.bin
    2

方法 2:将库路径加入系统配置

将库目录添加到系统信任的路径列表中。

  1. 创建配置文件:

    g++ ./setTime.cpp -std=c++11 -o setTime.bin
    3
  2. 更新动态库缓存:

    g++ ./setTime.cpp -std=c++11 -o setTime.bin
    4

方法 3:将库文件复制到标准目录

将动态库复制到系统默认搜索路径(如 /usr/lib/lib):

g++ ./setTime.cpp -std=c++11 -o setTime.bin
5

最终解决方案 Ambient

其实,给进程和文件都setcap不是最合适的方法。在Linux 4.3内核中新增了一个Ambient属性,具体计算方法是这样的:

P代表进程,F代表进程要用exec执行的文件。

P'(ambient) = (file is privileged) ? 0 : P(ambient)

P'(permitted) = (P(inheritable) & F(inheritable)) | (F(permitted) & P(bounding))) | P'(ambient)

P'(effective) = F(effective) ? P'(permitted) : P'(ambient)

P'(inheritable) = P(inheritable) [i.e., unchanged]

P'(bounding) = P(bounding) [i.e., unchanged]

由此可以看出,如果文件没有设置特权(即没有setcap),如果在进程里设置了ambient能力,那么exec会直接获得这个能力。这样既不用给文件特权,也不会发生找不到LD_LIBRARY_PATH的问题了。

最终 main.cpp 代码如下,关键在新增的 SetAmbientCap 函数:

g++ ./setTime.cpp -std=c++11 -o setTime.bin
6

setTime.cpp不变,编译出的程序不执行setcap.

最终执行结果如下,完美解决问题:

g++ ./setTime.cpp -std=c++11 -o setTime.bin
7