prctl
是 Linux 系统调用,用于对进程的某些特性进行控制和操作。它的主要作用是设置或获取进程的某些特定属性,例如进程名、允许的系统调用行为等。
下面是 prctl
函数的常见用法及其参数说明:
#include <sys/prctl.h>
#include <linux/prctl.h>
常用选项
PR_SET_NAME
和PR_GET_NAME
: 设置或获取进程名。PR_SET_PDEATHSIG
: 当父进程退出时,发送信号给子进程。PR_GET_SECCOMP
和PR_SET_SECCOMP
: 获取或设置进程的 seccomp 模式(用于限制系统调用)。PR_SET_NO_NEW_PRIVS
: 禁止提升权限(例如使用 setuid 程序)。
示例代码
1. 设置和获取进程名
#include <stdio.h>
#include <string.h>
#include <sys/prctl.h>
int main() {
char name[16]; // 进程名最大长度为 16 字节(包括终止符)
// 设置进程名
if (prctl(PR_SET_NAME, "MyProcess", 0, 0, 0) != 0) {
perror("prctl PR_SET_NAME failed");
return 1;
}
// 获取进程名
if (prctl(PR_GET_NAME, name, 0, 0, 0) != 0) {
perror("prctl PR_GET_NAME failed");
return 1;
}
printf("Process name: %s\n", name);
return 0;
}
运行后,使用 ps
命令可以看到进程名已设置为 MyProcess
。
2. 父进程退出时通知子进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <signal.h>
void handle_signal(int sig) {
printf("Received signal: %d\n", sig);
exit(0);
}
int main() {
// 子进程设置:父进程退出时发送 SIGKILL
if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) {
perror("prctl PR_SET_PDEATHSIG failed");
return 1;
}
// 父进程退出时,子进程会收到 SIGKILL 信号
signal(SIGKILL, handle_signal);
printf("Running child process (pid: %d, ppid: %d)\n", getpid(), getppid());
// 模拟长时间运行
while (1) {
sleep(1);
}
return 0;
}
运行此代码时,若父进程退出(通过 kill
或 Ctrl+C
),子进程会自动接收到 SIGKILL
信号并终止。
3. 设置 Seccomp 模式
以下示例设置 seccomp 为只允许 read
和 write
系统调用(限制进程行为):
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
int main() {
// 开启 seccomp 过滤器(仅允许 read 和 write)
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT) == -1) {
perror("prctl PR_SET_SECCOMP failed");
return 1;
}
printf("Seccomp mode enabled.\n");
// 以下操作将被允许
write(STDOUT_FILENO, "Hello, Seccomp!\n", 16);
// 以下操作会导致进程终止(不允许的系统调用)
if (fork() == -1) {
perror("fork failed");
}
return 0;
}
当 prctl
设置为 SECCOMP_MODE_STRICT
时,只允许 read
和 write
系统调用,其他调用(例如 fork
)会被直接阻止并终止程序。
总结
prctl
提供了强大的进程属性管理能力。它常被用于:
- 设置进程名,方便调试和监控;
- 配置 seccomp 来限制进程系统调用,提升安全性;
- 配置父子进程通信行为。
通过结合 prctl
的功能,开发者可以更加精细地控制进程行为。