刷新selinux标签的内核接口

在 Linux 内核中,刷新 SELinux 标签(Security Context)的核心接口是 setxattr() 系统调用,通过操作扩展属性(Extended Attributes)实现。以下是关键细节:

1. 底层机制:扩展属性 (xattr)

  • SELinux 标签存储在文件的 security.selinux 扩展属性中。
  • 刷新标签本质是修改该属性:
    1
    setfattr -n security.selinux -v "new_context" /path/to/file

2. 用户空间工具的内核调用

  • restorecon 工具(最常用):
    • 调用 selabel_lookup(3) 库函数,根据策略规则(file_contexts)计算正确标签。
    • 通过 setxattr() 将新标签写入 security.selinux 属性。
  • setfiles 工具
    • 直接解析策略文件并调用 setxattr() 批量修改标签。

3. 关键内核接口

  • 系统调用
    1
    int setxattr(const char *path, const char *name, const void *value, size_t size, int flags);
    • name 设为 "security.selinux"
    • value 是新的 SELinux 上下文字符串(如 "system_u:object_r:httpd_sys_content_t:s0")。
  • 内核处理流程
    • setxattr()security_inode_setxattr() → SELinux 钩子函数(如 selinux_inode_setxattr())。
    • 内核验证权限后更新文件标签。

4. 强制刷新文件系统标签

  • 用户空间工具(如 restorecon -Rv /)递归遍历文件系统:
    • 对每个文件匹配策略规则 → 调用 setxattr() 更新标签。
  • 伪代码示例
    1
    2
    const char *new_context = "system_u:object_r:default_t:s0";
    setxattr("/path/to/file", "security.selinux", new_context, strlen(new_context), 0);

5. 特殊场景接口

  • **lsetxattr()/fsetxattr()**:修改符号链接本身或已打开文件的标签。
  • **/proc/pid/attr/current**:动态修改进程的 SELinux 上下文(需策略允许)。

6. 内核开发接口(模块层)

  • SELinux LSM 提供的函数(需内核编程):
    1
    2
    int security_sid_to_context(struct selinux_state *state, u32 sid, char **context);
    int security_context_to_sid(struct selinux_state *state, const char *context, u32 *sid, gfp_t gfp);

操作示例

1
2
3
4
5
6
7
8
# 查看当前标签
ls -Z /path/to/file

# 使用 restorecon 刷新(用户空间工具)
restorecon -v /path/to/file

# 直接调用 setxattr 修改(底层)
setfattr -n security.selinux -v "system_u:object_r:etc_t:s0" /path/to/file

总结

层级 接口/工具 作用
用户空间 restorecon/setfiles 根据策略批量刷新标签
系统调用 setxattr() 修改文件的 security.selinux 属性
内核 LSM SELinux 钩子函数 验证并应用标签变更
进程上下文 /proc/pid/attr/* 动态修改进程标签

刷新标签的核心是通过 setxattr() 更新文件的扩展属性,用户空间工具(如 restorecon)封装了策略匹配和递归遍历逻辑,简化操作。

内核Selinux维测

在 Linux 内核中维护和调试 SELinux 需要深入理解其核心组件和调试接口。以下是关键的内核级 SELinux 维测指南:


一、核心调试接口

1. 内核日志输出

  • pr_info()/pr_warn()
    SELinux 模块在 security/selinux/ 目录的代码中大量使用内核打印函数
    1
    2
    3
    // 示例:avc.c 中的访问向量缓存调试
    pr_info("SELinux: avc: denied { %s } for pid=%d comm=%s scontext=%s tcontext=%s tclass=%s\n",
    avc_audit_perm, pid, comm, scontext, tcontext, tclass_name);
  • 动态日志级别控制
    通过 selinux_enforcing 等参数调整日志级别:
    1
    echo 8 > /proc/sys/kernel/printk  # 开启所有级别日志

2. Sysfs 调试接口

  • /sys/fs/selinux 关键节点:
    1
    2
    3
    cat /sys/fs/selinux/avc/cache_stats  # 查看AVC缓存统计
    cat /sys/fs/selinux/policy # 查看当前加载的二进制策略
    echo 1 > /sys/fs/selinux/disable # 紧急禁用SELinux(需内核配置支持)

3. Procfs 接口

  • 进程级上下文调试
    1
    2
    cat /proc/self/attr/current  # 查看当前进程上下文
    cat /proc/$PID/attr/current # 查看任意进程上下文
  • 强制进程上下文切换
    1
    echo "system_u:system_r:init_t:s0" > /proc/self/attr/current

二、内核级调试工具

1. AVC 审计日志分析

  • 内核通过 netlink 发送 AVC 消息到用户空间
  • 直接查看原始 AVC 记录
    1
    2
    auditctl -m avc  # 实时捕获AVC拒绝事件
    ausearch -m avc -ts today # 查询历史记录

2. 动态策略重载调试

  • 策略加载内核路径security_load_policy() 函数
  • 调试技巧:
    1
    2
    # 加载策略时开启内核调试
    echo "file selinuxfs.c +p" > /sys/kernel/debug/dynamic_debug/control

3. 内存状态检查

  • SID 映射表调试
    1
    2
    3
    // 检查安全标识符(SID)映射
    struct sidtab *sidtab = &selinux_state.ss->sidtab;
    sidtab_hash_stats(sidtab); // 输出哈希表统计

三、高级内核调试技术

1. Kprobe 动态跟踪

1
2
3
4
# 跟踪avc_has_perm()函数调用
echo 'p:avc_probe avc_has_perm perm=%di scontext=+0(%si):string tcontext=+0(%dx):string' > /sys/kernel/debug/tracing/kprobe_events
echo 1 > /sys/kernel/debug/tracing/events/kprobes/avc_probe/enable
cat /sys/kernel/debug/tracing/trace_pipe

2. Ftrace 函数流跟踪

1
2
3
4
# 跟踪SELinux决策流程
echo function > /sys/kernel/debug/tracing/current_tracer
echo selinux_* > /sys/kernel/debug/tracing/set_ftrace_filter
cat /sys/kernel/debug/tracing/trace

3. 内存损坏调试

  • 当策略引擎崩溃时使用 KASAN
    1
    2
    # 内核启动参数添加
    kasan=on kmemleak=on
  • 检查 SELinux 专用内存分配器:
    1
    security/selinux/ss/policydb.c 中的 policydb_alloc()

四、关键故障场景处理

1. 策略加载失败

  • 内核日志关键字
    • "SELinux: policy capability __CAP__ not allowed"
    • "SELinux: unable to read policy version %d"
  • 调试方法
    1
    2
    dmesg | grep -E "SELinux: (error|fail)"  # 提取加载错误
    checkpolicy -d -M /sys/fs/selinux/policy # 反编译策略分析

2. 权限检查死锁

  • 典型症状:系统卡在 avc_has_perm_noaudit()
  • 调试步骤
    1
    2
    echo l > /proc/sysrq-trigger  # 输出所有CPU回溯
    cat /proc/$(pidof systemd)/stack # 检查关键进程堆栈

3. 标签内存泄漏

  • 检测工具
    1
    2
    grep -r "selinux:" /proc/slabinfo  # 查看SELinux对象计数
    echo 1 > /sys/fs/selinux/avc/cache_stats # 重置AVC缓存统计

五、内核开发调试接口

1. LSM Hook 调试

1
2
3
4
5
6
// 示例:inode_permission LSM hook
int selinux_inode_permission(struct inode *inode, int mask) {
if (mask & MAY_WRITE)
pr_debug("SELinux: Write attempt to ino=%lu\n", inode->i_ino);
return avc_has_perm(...);
}

2. 强制上下文校验

1
2
3
4
5
// 安全服务器调试函数
void selinux_ss_debug(struct selinux_state *state) {
printk(KERN_DEBUG "Policy vers=%d\n", state->policy->vers);
sidtab_dump(state->ss->sidtab);
}

调试流程图

1
2
3
4
5
6
7
8
9
10
11
graph TD
A[故障现象] --> B{日志分析}
B -->|AVC Denied| C[权限缺失]
B -->|Kernel Panic| D[内存损坏]
B -->|Hang| E[死锁检测]
C --> F[audit2allow生成规则]
D --> G[KASAN检测]
E --> H[SysRq+堆栈回溯]
F --> I[策略重编译]
G --> J[修复内存操作]
H --> K[调整锁顺序]

关键内核文件

文件路径 功能
security/selinux/avc.c 访问向量缓存实现
security/selinux/ss/services.c 策略加载和决策引擎
security/selinux/hooks.c LSM Hook 实现
security/selinux/include/security.h 核心数据结构定义

通过结合内核日志、动态调试和内存分析工具,可快速定位 SELinux 在内核层的复杂问题。在紧急情况下,可通过 selinux=0 内核启动参数完全禁用 SELinux。