prctl函数简介

prctl函数简介

prctl 是 Linux 系统提供的进程控制函数,用于动态修改或查询进程的运行时属性,涵盖权限管理、信号控制、安全策略等场景‌。以下是其核心机制与典型应用:


一、函数原型与头文件

#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
  • 参数说明
    • option:控制选项,决定后续参数的意义(如 PR_SET_NAMEPR_SET_PDEATHSIG 等)‌。
    • arg2~arg5:根据 option 不同而变化的参数,通常为数值或指针‌。
  • 返回值‌:成功返回 0,失败返回 -1 并设置 errno‌。

二、核心功能与选项

1. ‌进程/线程命名
  • PR_SET_NAME:设置进程名(显示在 ps 或 top 中),最大长度 16 字节‌。
    prctl(PR_SET_NAME, "my_process", 0, 0, 0); // 设置进程名
  • PR_GET_NAME:获取当前进程名‌。
2. ‌父进程终止信号控制
  • PR_SET_PDEATHSIG:父进程退出时向子进程发送指定信号(如 SIGKILL)‌。
    prctl(PR_SET_PDEATHSIG, SIGKILL); // 父进程退出时终止子进程
3. ‌安全与权限控制
  • PR_SET_SECCOMP:启用 seccomp 模式,限制进程可调用的系统调用(沙盒安全)‌。
  • PR_SET_NO_NEW_PRIVS:禁止通过 execve 提升权限(如禁用 setuid)‌。
4. ‌核心转储管理
  • PR_SET_DUMPABLE:控制是否允许生成核心转储文件(core dump)‌。
5. ‌能力集管理
  • PR_CAPBSET_READ/PR_CAPBSET_DROP:查询或删除进程的能力(Capabilities)‌。

prctl 提供了三类动态修改进程能力的方式:

  • 删除能力边界集‌(PR_CAPBSET_DROP)→ 限制子进程能力;
  • 提升环境能力‌(PR_CAP_AMBIENT_RAISE)→ 跨 exec 保留能力;
  • 禁用权限提升‌(PR_SET_NO_NEW_PRIVS)→ 阻止 SUID/SGID 提权。
1). ‌删除能力边界集(Bounding Set)
  • 函数原型‌:prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)
  • 作用‌:永久移除进程 Bound 集中的指定能力(cap),禁止后续 execve 执行的子进程重新获取该能力。
  • 权限要求‌:调用进程需具备 CAP_SETPCAP 能力(通常为 root 用户)。
  • 示例‌:
    prctl(PR_CAPBSET_DROP, CAP_NET_RAW, 0, 0, 0);  // 禁止子进程使用原始套接字能力
    
2). ‌提升环境能力(Ambient Capabilities)
  • 函数原型‌:prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)
  • 作用‌:将能力(cap)加入 Ambient 集,使该能力在 execve 后仍保留在子进程中。
  • 权限要求‌:
    • 当前进程的 Permitted 和 Inheritable 集需包含目标能力。
    • 需 Linux 4.3+ 内核支持。
  • 示例‌:
    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0);  // 允许子进程绑定低端口
    
3). ‌禁用权限提升(No New Privileges)
  • 函数原型‌:prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)
  • 作用‌:阻止进程通过 execve 执行 SUID/SGID 程序提升权限,增强安全性。
  • 不可逆性‌:一旦设置无法撤销。
#include <sys/prctl.h>
#include <linux/capability.h>

// 1. 禁用权限提升(防止意外提权)
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);  

// 2. 删除危险能力(如禁止原始套接字)
prctl(PR_CAPBSET_DROP, CAP_NET_RAW, 0, 0, 0); 

// 3. 添加必要环境能力(如允许绑定低端口)
if (prctl(PR_CAPBSET_READ, CAP_NET_BIND_SERVICE, 0, 0, 0) == 1) {
    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0); 
}

三、典型应用场景

  1. 多线程调试
    通过 PR_SET_NAME 区分线程,便于 ps -T 或调试工具识别‌。
  2. 守护进程管理
    结合 PR_SET_PDEATHSIG 确保父进程崩溃时子进程自动终止‌。
  3. 安全沙盒
    使用 PR_SET_SECCOMP 和 PR_SET_NO_NEW_PRIVS 限制进程权限‌。

四、注意事项

  1. 系统依赖性
    prctl 是 Linux 特有调用,其他类 UNIX 系统(如 macOS)可能不支持‌。
  2. 权限要求
    部分选项(如 PR_SET_SECCOMP)需 root 权限或 CAP_SYS_ADMIN 能力‌。
  3. 内核版本差异
    不同内核版本支持的选项可能不同,需参考 man prctl 或内核文档‌。

五、示例代码

以下代码演示设置进程名并监控父进程退出:

#include <sys/prctl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int main() {
    prctl(PR_SET_NAME, "demo_process", 0, 0, 0);  // 设置进程名
    prctl(PR_SET_PDEATHSIG, SIGTERM);            // 父进程退出时接收SIGTERM

    char name;
    prctl(PR_GET_NAME, name);                    // 获取进程名
    printf("Process name: %s\n", name);

    while (1) sleep(1);  // 模拟进程运行
    return 0;
}

prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)

prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)是Linux系统调用中用于安全加固的关键操作,其核心用途如下:


一、核心功能

  1. 权限锁定机制
    通过设置PR_SET_NO_NEW_PRIVS标志为1,禁止当前进程及其子进程通过execve等系统调用获得新权限(如SUID/SGID程序提权或chroot操作)‌。
  2. 安全沙箱基础
    常与seccomp过滤器配合使用,构成容器和沙箱环境的安全底层,防止权限逃逸攻击‌。

二、技术细节

  1. 内核版本依赖
    需Linux内核≥3.5支持,通过修改进程的no_new_privs属性实现‌。
  2. 不可逆操作
    一旦设置,进程生命周期内无法撤销该限制,即使后续调用prctl(PR_SET_NO_NEW_PRIVS, 0)也无效‌。

三、典型应用场景

  1. 容器安全
    Docker等容器运行时默认启用该选项,防止容器内进程通过SUID程序提权‌。
  2. 敏感服务防护
    如Web服务降权后执行外部命令时,避免子进程继承高权限‌。

四、代码示例

以下程序演示如何启用该限制并验证效果:

#include <sys/prctl.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
        perror("prctl failed");
        return 1;
    }
    system("sudo whoami");  // 将执行失败
    return 0;
}

编译运行后,即使以root启动,sudo命令也会因权限限制而失败‌。

prctl(PR_SET_NO_NEW_PRIVS)对哪些操作生效? 

prctl(PR_SET_NO_NEW_PRIVS, 1) 是 Linux 内核提供的一种安全机制,用于限制进程及其子进程的权限提升能力。以下是其生效范围的具体说明:


一、主要限制的操作

  1. 禁止通过 execve 提权

    • 阻止执行 SUID/SGID 程序时继承特权(如 /bin/passwd 等)‌。
    • 禁用文件能力(File Capabilities)的继承,即使二进制文件设置了 CAP_SYS_ADMIN 等能力也无法生效‌。
  2. 限制 chroot 逃逸

    • 防止进程通过 chroot 切换根目录后突破沙箱隔离‌。
  3. 阻断部分用户空间操作

    • 禁止调用 setuid/setgid 等权限修改函数(需结合 seccomp 过滤器进一步限制)‌。

二、不受限制的操作

  1. 直接系统调用提权
    • 若进程已有 CAP_SETUID 能力,仍可通过 setuid(0) 直接提权‌。
  2. 非 execve 的权限变更
    • 如通过 SCM_RIGHTS 传递文件描述符或调用 unshare(CLONE_NEWUSER) 创建命名空间‌。

三、典型应用场景

  1. 容器安全加固
    Docker 等容器运行时默认启用该选项,防止容器内进程通过特权二进制文件逃逸‌。
  2. 沙箱环境构建
    与 seccomp 过滤器配合,限制子进程的系统调用范围(如浏览器沙箱)‌。

四、验证示例

以下代码演示如何检测当前进程是否启用了该限制:

#include <sys/prctl.h>
#include <stdio.h>

int main() {
    if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) {
        printf("NO_NEW_PRIVS is active\n");
    }
    return 0;
}

prctl (PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)

PR_SET_CHILD_SUBREAPER 是 Linux 系统调用 prctl 的一个选项,用于将当前进程设置为“子进程收割者”(subreaper),使其能够接管孤儿进程,避免这些进程被 init 进程(PID 1)直接收养‌。

功能说明

  1. 作用机制

    • 当父进程退出时,其子进程通常会被 init 进程(PID 1)接管。
    • 若当前进程通过 prctl(PR_SET_CHILD_SUBREAPER, 1) 设置为 subreaper,则其子进程(及后代进程)在父进程退出后会被当前进程接管,而非 init 进程‌。
  2. 典型应用

    • 进程管理框架‌(如 systemd)使用该机制确保孤儿进程不会直接由 init 管理,而是由框架控制‌。
    • 容器运行时‌ 在容器内设置 subreaper,防止容器内进程逃逸到宿主机 init 进程‌。

代码示例

以下代码演示如何设置进程为 subreaper 并验证其行为:


#include <sys/prctl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    // 设置当前进程为 subreaper
    if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0) == -1) {
        perror("prctl");
        return 1;
    }

    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // 子进程逻辑
        printf("Child PID: %d, initial PPID: %d\n", getpid(), getppid());
        sleep(5);  // 等待父进程退出
        printf("Child PID: %d, new PPID: %d (should be subreaper)\n", getpid(), getppid());
        sleep(10);
        return 0;
    } else {
        // 父进程逻辑
        printf("Parent PID: %d, child PID: %d\n", getpid(), pid);
        sleep(2);  // 短暂运行后退出
        printf("Parent exiting...\n");
    }
    return 0;
}

运行后,子进程的父进程会变为当前进程(而非 init),验证 subreaper 机制生效‌。

注意事项

  1. 权限要求‌:调用进程需具备 CAP_SYS_ADMIN 能力(通常需 root 权限)‌。
  2. 层级限制‌:subreaper 仅影响其直接子进程及后代,不影响其他进程树‌。
  3. 与 init 的区别‌:subreaper 是用户态进程,而 init 是内核托管的特殊进程‌。

prctl (PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)

prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) 是 Linux 系统中用于设置进程在父进程退出时接收特定信号的系统调用,常用于父子进程生命周期管理‌。以下是详细解析:


1. 功能说明

  • PR_SET_PDEATHSIG
    该选项允许子进程设置一个信号(如 SIGKILL),当父进程终止时,内核会向子进程发送该信号‌。
    • 参数 SIGKILL 表示父进程退出时强制终止子进程(不可捕获或忽略)‌。
    • 后三个参数(0, 0, 0)为保留参数,必须置零‌。

2. 典型应用场景

  • 守护进程管理‌:确保父进程(如监控进程)退出时,子进程自动终止,避免孤儿进程‌。
  • 安全隔离‌:在沙箱或容器中强制清理关联进程链‌。

3. 代码示例

#include <sys/prctl.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {  // 子进程
        prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);  // 父进程退出时接收SIGKILL
        while (1) {
            sleep(1);
            printf("Child running...\n");
        }
    } else {  // 父进程
        sleep(3);
        printf("Parent exiting...\n");
    }
    return 0;
}

运行结果‌:父进程退出后,子进程立即被终止‌。


4. 注意事项

  • 信号选择‌:若设置为 SIGTERM 等可捕获信号,子进程可通过信号处理器避免退出‌。
  • 线程安全‌:多线程程序中需确保调用时机正确,避免竞争条件‌。
  • 权限限制‌:非特权进程仅能设置自身信号,修改其他进程需 CAP_KILL 能力‌。

此调用适用于需要严格父子进程生命周期的场景(如服务监控、容器初始化)‌。

prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0)

prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) 是 Linux 系统中用于控制进程权限保留的关键系统调用,主要功能是在进程切换用户身份时保持原有的能力集(capabilities)不被内核自动清除‌。以下是详细解析:


1. 核心功能

  • 作用机制
    当进程通过 setuid() 等调用从特权用户(如 root)切换到非特权用户时,默认情况下内核会清空进程的 permitted capabilities 集合。通过 PR_SET_KEEPCAPS 设置为 1,可阻止此行为,保留原有能力‌。
  • 典型场景
    需降权但仍需部分特权能力的守护进程(如网络服务需保留 CAP_NET_ADMIN)‌。

2. 使用流程示例

  1. 启用能力保留
    prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);  
    
  2. 切换用户身份
    setuid(non_privileged_uid);  // 降权为普通用户
    
  3. 重新配置能力集
    // 通过 capset() 设置所需能力(如 CAP_NET_ADMIN)
    

3. 注意事项

  • 能力集限制
    仅 permitted 集合会被保留,effective 集合仍会被内核清空,需手动重新激活‌。
  • execve 影响
    执行新程序时会重置 PR_SET_KEEPCAPS 标志为 0,需在 execve 后重新设置‌。
  • 安全风险
    错误保留高权限能力可能导致提权漏洞,需严格审查保留的能力‌。

4. 完整代码示例

以下代码演示如何降权至 AID_SYSTEM 用户同时保留网络管理能力:


#include <sys/prctl.h>
#include <sys/capability.h>
#include <unistd.h>

int main() {
    // 启用能力保留
    prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);

    // 切换用户身份
    setuid(AID_SYSTEM);^^^1^^

    // 重新配置能力集
    struct __user_cap_header_struct header;
    struct __user_cap_data_struct cap;
    header.version = _LINUX_CAPABILITY_VERSION;
    header.pid = 0;
    cap.effective = cap.permitted = (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
    cap.inheritable = 0;
    capset(&header, &cap);

    // 后续特权操作...
    return 0;
}

此代码需链接 libcap 库编译,适用于需要降权但保留特定能力的系统服务‌。

prctl (PR_CAPBSET_DROP, cap, 0, 0, 0)

prctl(PR_CAPBSET_DROP, cap, 0, 0, 0) 是 Linux 系统中用于管理进程能力(Capabilities)的关键函数调用,其功能与参数解析如下:


📌 一、功能说明

  1. 作用
    该调用从进程的 ‌Capability Bounding Set‌ 中永久删除指定的能力(cap),后续通过 execve 执行的子进程将无法重新获取该能力。

    • 典型场景‌:特权进程(如 su 或容器运行时)通过限制子进程的能力集增强安全性。
  2. 与 PR_CAPBSET_READ 的关系

    • PR_CAPBSET_READ 用于检查能力是否在 Bounding Set 中。
    • PR_CAPBSET_DROP 需结合循环使用 PR_CAPBSET_READ 遍历所有能力并逐个删除。

🔧 二、参数详解

参数类型描述示例值
capint要删除的能力编号(如 CAP_NET_RAW 对应值需参考 <linux/capability.h>CAP_CHOWN (0)
arg3~5unsigned long保留参数,必须设为 00

⚙️ 三、使用示例

1. ‌删除单个能力
#include <sys/prctl.h>
#include <linux/capability.h>

prctl(PR_CAPBSET_DROP, CAP_NET_RAW, 0, 0, 0);  // 禁止子进程使用原始套接字能力:ml-citation{ref="1,6" data="citationList"}
2. ‌清空所有能力
for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
    if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
        perror("Failed to drop capability");
    }
}
  • 注意‌:需处理 EINVAL 错误(内核未启用能力支持)。

⚠️ 四、注意事项

  1. 权限要求
    • 调用进程需具备 CAP_SETPCAP 能力(通常为 root 用户)。
  2. 不可逆性
    • 删除的能力无法通过 exec 恢复,仅影响后续子进程。
  3. 内核兼容性
    • 需确认内核编译时启用了 CONFIG_SECURITY_FILE_CAPABILITIES

📚 五、相关能力常量

常见能力定义(部分):

能力名编号功能
CAP_CHOWN0修改文件所有者
CAP_NET_RAW13创建原始套接字(如 ping
CAP_SYS_ADMIN21系统管理操作(如挂载文件系统)

完整列表需参考 <linux/capability.h> 头文件。

prctl (PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)

prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) 是 Linux 系统中用于提升进程环境能力(Ambient Capabilities)的系统调用,其功能与参数解析如下:


📌 一、功能说明

  1. 作用
    将指定的能力(cap)添加到进程的 ‌Ambient Capability Set‌ 中,使该能力在 execve 执行后仍保留在子进程中。

    • 典型场景‌:非特权进程(如容器内应用)需要继承特定能力(如 CAP_NET_BIND_SERVICE)时使用。
  2. 与普通能力的区别

    • Ambient 能力‌:跨越 exec 调用保留,无需依赖文件能力或父进程的 Inheritable 集。
    • 传统能力‌:需通过 CAP_INHERITABLE 和文件能力配合实现类似效果。

🔧 二、参数详解

参数类型描述示例值
PR_CAP_AMBIENTint固定操作码,表示操作环境能力集PR_CAP_AMBIENT (47)
PR_CAP_AMBIENT_RAISEint子操作码,表示提升能力到 Ambient 集PR_CAP_AMBIENT_RAISE (1)
capint能力编号(需参考 <linux/capability.h>CAP_NET_RAW (13)
arg4~5unsigned long保留参数,必须设为 00

⚙️ 三、使用示例

1. ‌提升单个环境能力
#include <sys/prctl.h>
#include <linux/capability.h>

if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0) == -1) {
    perror("Failed to raise ambient capability");
}
  • 权限要求‌:
    • 当前进程的 Permitted 和 Inheritable 集需包含目标能力。
    • 若内核启用 SECURE_NO_CAP_AMBIENT_RAISE 安全位,操作将失败。
2. ‌完整流程(检查+提升)
if (prctl(PR_CAPBSET_READ, CAP_NET_BIND_SERVICE, 0, 0, 0) == 1) {
    prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0);
}

⚠️ 四、注意事项

  1. 内核版本
    • 需 Linux 4.3+ 内核支持 Ambient 能力。
  2. 安全限制
    • 禁止通过 Ambient 能力提升超过 Permitted 集的范围。
  3. 错误处理
    • 返回 -1 时需检查 errno(如 EPERM 表示权限不足)。

📚 五、相关能力操作对比

操作类型函数调用作用范围
提升 Ambient 能力prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE)跨越 exec 保留
删除 Bounding Set 能力prctl(PR_CAPBSET_DROP)永久禁止子进程获取
检查能力是否在 Bounding Setprctl(PR_CAPBSET_READ)验证能力状态

prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sock_fprog)

prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &sock_fprog) 是 Linux 系统中用于启用 ‌Seccomp BPF 过滤模式‌ 的系统调用,其功能与参数解析如下:


📌 一、功能说明

  1. 作用
    通过 Berkeley Packet Filter (BPF) 规则限制进程可调用的系统调用,实现细粒度的安全沙箱。

    • 典型场景‌:容器运行时、安全敏感应用(如浏览器沙箱)限制不可信代码的系统调用权限。
  2. 与严格模式的区别

    • Filter 模式‌:自定义允许/禁止的系统调用列表(通过 BPF 规则)。
    • 严格模式‌(SECCOMP_MODE_STRICT):仅允许 read/write/exit/sigreturn 四个系统调用。

🔧 二、参数详解

参数类型描述示例值
PR_SET_SECCOMPint固定操作码,表示启用 Seccomp 过滤PR_SET_SECCOMP (22)
SECCOMP_MODE_FILTERint子操作码,表示使用 BPF 过滤模式SECCOMP_MODE_FILTER (2)
&sock_fprogstruct sock_fprog*指向 BPF 规则结构的指针,定义允许的系统调用需预先通过 prctl 或 seccomp 库配置

⚙️ 三、使用流程

1. ‌配置 BPF 规则

需定义 sock_fprog 结构体,包含 BPF 指令数组(通常通过 libseccomp 库生成):

struct sock_filter filter[] = {
    BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
    BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
    BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
};
struct sock_fprog prog = {
    .len = sizeof(filter) / sizeof(filter[0]),
    .filter = filter,
};
2. ‌启用 Seccomp 过滤
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);  // 禁止权限提升(必需)
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog); 

⚠️ 四、注意事项

  1. 权限要求
    • 需先调用 PR_SET_NO_NEW_PRIVS 防止后续 execve 提权。
  2. 内核版本
    • Linux 3.5+ 支持 SECCOMP_MODE_FILTER
  3. 错误处理
    • 返回 -1 时检查 errno(如 EINVAL 表示内核未启用 Seccomp)。

📚 五、相关扩展

  • libseccomp 库‌:简化 BPF 规则生成(推荐替代原生调用)。
  • seccomp(2) 系统调用‌:Linux 3.17+ 提供更灵活的接口。

通过合理配置 BPF 规则,可实现从黑名单到白名单的多级安全策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值