capset系统调用及示例

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: 指向头部结构的指针,包含版本和进程ID
  • cap_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;
}
此条目发表在未分类分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注