34. capget – 获取进程能力
函数介绍
capget
系统调用用于获取进程的能力状态信息。能力是一种细粒度的权限控制机制,将传统的超级用户权限分解为独立的权限单元。
函数原型
#include <linux/capability.h>
#include <sys/syscall.h>
#include <unistd.h>
int capget(cap_user_header_t hdrp, cap_user_data_t datap);
功能
获取指定进程的能力集,包括有效能力、允许能力和可继承能力。
参数
cap_user_header_t hdrp
: 指向头部结构的指针,包含版本和进程IDcap_user_data_t datap
: 指向能力数据结构的指针
返回值
- 成功时返回0
- 失败时返回-1,并设置errno
相似函数
capset()
: 设置进程能力prctl()
: 进程控制函数
示例代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/capability.h>
#include <errno.h>
#include <string.h>
// 系统调用包装
static int capget_wrapper(cap_user_header_t hdrp, cap_user_data_t datap) {
return syscall(__NR_capget, hdrp, datap);
}
// 打印能力位图
void print_capabilities(const char *label, __u32 caps) {
printf("%s: 0x%08x (", label, caps);
if (caps == 0) {
printf("none");
} else {
int first = 1;
for (int i = 0; i < 32; i++) {
if (caps & (1 << i)) {
if (!first) printf(" ");
first = 0;
switch (i) {
case 0: printf("CAP_CHOWN"); break;
case 1: printf("CAP_DAC_OVERRIDE"); break;
case 2: printf("CAP_DAC_READ_SEARCH"); break;
case 3: printf("CAP_FOWNER"); break;
case 4: printf("CAP_FSETID"); break;
case 5: printf("CAP_KILL"); break;
case 6: printf("CAP_SETGID"); break;
case 7: printf("CAP_SETUID"); break;
case 8: printf("CAP_SETPCAP"); break;
case 9: printf("CAP_LINUX_IMMUTABLE"); break;
case 10: printf("CAP_NET_BIND_SERVICE"); break;
case 11: printf("CAP_NET_BROADCAST"); break;
case 12: printf("CAP_NET_ADMIN"); break;
case 13: printf("CAP_SYS_MODULE"); break;
case 14: printf("CAP_SYS_RAWIO"); break;
case 15: printf("CAP_SYS_CHROOT"); break;
case 16: printf("CAP_SYS_PTRACE"); break;
case 17: printf("CAP_SYS_PACCT"); break;
case 18: printf("CAP_SYS_ADMIN"); break;
case 19: printf("CAP_SYS_BOOT"); break;
case 20: printf("CAP_SYS_NICE"); break;
case 21: printf("CAP_SYS_RESOURCE"); break;
case 22: printf("CAP_SYS_TIME"); break;
case 23: printf("CAP_SYS_TTY_CONFIG"); break;
case 24: printf("CAP_MKNOD"); break;
case 25: printf("CAP_LEASE"); break;
case 26: printf("CAP_AUDIT_WRITE"); break;
case 27: printf("CAP_AUDIT_CONTROL"); break;
case 28: printf("CAP_SETFCAP"); break;
case 29: printf("CAP_MAC_OVERRIDE"); break;
case 30: printf("CAP_MAC_ADMIN"); break;
case 31: printf("CAP_SYSLOG"); break;
default: printf("CAP_%d", i); break;
}
}
}
}
printf(")\n");
}
int main() {
struct __user_cap_header_struct hdr;
struct __user_cap_data_struct data[2];
printf("=== Capget 函数示例 ===\n");
printf("当前进程 PID: %d\n", getpid());
printf("当前用户 UID: %d\n", getuid());
printf("当前有效 UID: %d\n", geteuid());
// 设置头部信息
hdr.version = _LINUX_CAPABILITY_VERSION_3;
hdr.pid = 0; // 当前进程
// 获取能力信息
if (capget_wrapper(&hdr, data) == -1) {
perror("capget 失败");
exit(EXIT_FAILURE);
}
printf("\n进程能力信息:\n");
printf("能力版本: 0x%08x\n", hdr.version);
printf("进程 PID: %d\n", hdr.pid);
// 显示能力集
printf("\n能力集详情:\n");
print_capabilities("有效能力 (Effective)", data[0].effective);
print_capabilities("允许能力 (Permitted)", data[0].permitted);
print_capabilities("可继承能力 (Inheritable)", data[0].inheritable);
// 分析当前能力状态
printf("\n能力状态分析:\n");
if (geteuid() == 0) {
printf("✓ 当前进程是 root 用户\n");
if (data[0].effective == 0 && data[0].permitted == 0) {
printf(" 但所有能力都被丢弃\n");
} else {
printf(" 拥有完整的 root 能力\n");
}
} else {
printf("✓ 当前进程是非特权用户\n");
if (data[0].effective == 0) {
printf(" 没有有效能力\n");
} else {
printf(" 拥有一些特定能力\n");
}
}
// 错误处理演示
printf("\n错误处理演示:\n");
// 无效版本号
struct __user_cap_header_struct bad_hdr;
bad_hdr.version = 0x12345678;
bad_hdr.pid = 0;
if (capget_wrapper(&bad_hdr, data) == -1) {
if (errno == EINVAL) {
printf("无效版本号错误处理正确: %s\n", strerror(errno));
}
}
// 无效指针
hdr.version = _LINUX_CAPABILITY_VERSION_3;
if (capget_wrapper(&hdr, NULL) == -1) {
if (errno == EFAULT) {
printf("无效指针错误处理正确: %s\n", strerror(errno));
}
}
return 0;
}
35. capset – 设置进程能力
函数介绍
capset
系统调用用于设置调用进程的能力状态。它允许进程修改自己的能力集,但只能降低或保持当前能力,不能提升能力。
函数原型
#include <linux/capability.h>
#include <sys/syscall.h>
#include <unistd.h>
int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
功能
设置调用进程的能力状态,包括有效能力、允许能力和可继承能力。
参数
cap_user_header_t hdrp
: 指向头部结构的指针const cap_user_data_t datap
: 指向能力数据结构的指针
返回值
- 成功时返回0
- 失败时返回-1,并设置errno
相似函数
capget()
: 获取进程能力prctl()
: 进程控制函数
示例代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/capability.h>
#include <errno.h>
#include <string.h>
// 系统调用包装
static int capget_wrapper(cap_user_header_t hdrp, cap_user_data_t datap) {
return syscall(__NR_capget, hdrp, datap);
}
static int capset_wrapper(cap_user_header_t hdrp, const cap_user_data_t datap) {
return syscall(__NR_capset, hdrp, datap);
}
// 检查是否具有特定能力
int has_capability(__u32 caps, int cap) {
return (caps & (1 << cap)) != 0;
}
int main() {
struct __user_cap_header_struct hdr;
struct __user_cap_data_struct data[2];
printf("=== Capset 函数示例 ===\n");
printf("当前进程 PID: %d\n", getpid());
printf("当前用户 UID: %d\n", getuid());
printf("当前有效 UID: %d\n", geteuid());
// 获取当前能力
hdr.version = _LINUX_CAPABILITY_VERSION_3;
hdr.pid = 0;
if (capget_wrapper(&hdr, data) == -1) {
perror("capget 失败");
exit(EXIT_FAILURE);
}
printf("\n修改前的能力状态:\n");
printf(" 有效能力: 0x%08x\n", data[0].effective);
printf(" 允许能力: 0x%08x\n", data[0].permitted);
printf(" 继承能力: 0x%08x\n", data[0].inheritable);
// 演示能力丢弃(只能丢弃,不能增加)
printf("\n能力修改演示:\n");
// 保存原始状态
__u32 original_effective = data[0].effective;
__u32 original_permitted = data[0].permitted;
// 检查是否具有某些能力
if (has_capability(data[0].effective, CAP_CHOWN)) {
printf(" 当前具有 CAP_CHOWN 能力\n");
// 尝试丢弃该能力
data[0].effective &= ~(1 << CAP_CHOWN);
if (capset_wrapper(&hdr, data) == -1) {
printf(" capset 丢弃能力失败: %s\n", strerror(errno));
} else {
printf(" 成功丢弃 CAP_CHOWN 能力\n");
}
} else {
printf(" 当前不具有 CAP_CHOWN 能力\n");
}
// 再次获取能力状态验证
if (capget_wrapper(&hdr, data) == -1) {
perror("重新获取能力失败");
} else {
printf("\n修改后的有效能力: 0x%08x\n", data[0].effective);
// 恢复原始状态
data[0].effective = original_effective;
data[0].permitted = original_permitted;
if (capset_wrapper(&hdr, data) == -1) {
printf("恢复原始状态失败: %s\n", strerror(errno));
} else {
printf("已恢复原始能力状态\n");
}
}
// 错误处理演示
printf("\n错误处理演示:\n");
// 权限不足错误
hdr.version = _LINUX_CAPABILITY_VERSION_3;
hdr.pid = 0;
if (capget_wrapper(&hdr, data) == 0) {
// 尝试设置不允许的能力(会失败)
__u32 temp_effective = data[0].effective;
data[0].effective |= (1 << CAP_SYS_MODULE); // 尝试增加能力
if (capset_wrapper(&hdr, data) == -1) {
if (errno == EPERM) {
printf("权限不足错误处理正确: %s\n", strerror(errno));
printf("说明: 不能通过 capset 提升能力\n");
}
}
// 恢复状态
data[0].effective = temp_effective;
}
// 无效参数错误
hdr.version = 0x12345678; // 无效版本
if (capset_wrapper(&hdr, data) == -1) {
if (errno == EINVAL) {
printf("无效参数错误处理正确: %s\n", strerror(errno));
}
}
// 实际应用场景演示
printf("\n实际应用场景:\n");
printf("1. 网络服务器安全降权:\n");
printf(" - 启动时绑定特权端口(需要 CAP_NET_BIND_SERVICE)\n");
printf(" - 完成绑定后丢弃该能力\n");
printf(" - 切换到非特权用户运行\n\n");
printf("2. 最小权限原则:\n");
printf(" - 只保留执行任务必需的能力\n");
printf(" - 降低被攻击时的安全风险\n\n");
printf("3. 容器安全:\n");
printf(" - 限制容器内进程的能力\n");
printf(" - 防止容器逃逸攻击\n");
return 0;
}