---
title: LSM 与访问控制
url: https://doc.liz6.com/linux-kernel/09-security-mechanisms/01-lsm-and-access-control
locale: zh
area: linux-kernel
tags:
- linux-kernel
- 安全机制
date: 2026-06-30
modified: 2026-07-11
description: '覆盖: Linux Security Modules 架构 → SELinux/AppArmor/SMACK → LSM hooks 机制 → BPF LSM → capabilities → keyring → IMA/EVM 内核版本: 2.6 ~ 6.x'
---

# LSM 与访问控制

> 覆盖: Linux Security Modules 架构 → SELinux/AppArmor/SMACK → LSM hooks 机制 → BPF LSM → capabilities → keyring → IMA/EVM
> 内核版本: 2.6 ~ 6.x

## 概述

传统的 Unix DAC (Discretionary Access Control) 只有 owner/group/other 三级权限，无法表达"这个 web 服务器只能读 /var/www，不能碰 /home/user/.ssh"这种细粒度策略。LSM 通过在关键系统调用路径插入 hook，让安全模块可以提供额外的访问控制决策。

目前最大的两个 LSM 是 SELinux（基于 type enforcement 的强制访问控制）和 AppArmor（基于路径匹配的 profile 策略）。

## LSM Hook 架构

```c
// include/linux/lsm_hooks.h
// 200+ hooks 覆盖所有敏感操作:
struct security_hook_heads {
    struct hlist_head file_open;          // open() 最后一步 → security_file_open()
    struct hlist_head inode_create;       // 创建 inode
    struct hlist_head inode_unlink;       // unlink()
    struct hlist_head socket_create;      // socket()
    struct hlist_head socket_bind;        // bind()
    struct hlist_head task_kill;          // kill()
    struct hlist_head sb_mount;           // mount()
    // ... 200+ more
};

// 调用链:
// security_file_open(file) → call_void_hook(file_open, file)
// → 遍历所有注册模块的 hook → 任一返回 error → 拒绝操作
```

### Hook 的插入点

<svg viewBox="0 0 720 400" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="LSM Hook 插入点:open 系统调用触发多模块检查流程">
  <defs>
    <marker id="arrLSM1" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker>
  </defs>
  <rect width="720" height="400" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">LSM Hook 插入点:open() 系统调用路径</text>

  <rect x="210" y="46" width="300" height="32" rx="6" fill="#e2e8f0"/>
  <text x="360" y="67" text-anchor="middle" font-size="12.5" font-weight="600" fill="#334155">open("/etc/shadow", O_RDONLY)</text>
  <line x1="360" y1="78" x2="360" y2="92" stroke="#475569" stroke-width="1.6" marker-end="url(#arrLSM1)"/>

  <rect x="210" y="94" width="300" height="32" rx="6" fill="#e2e8f0"/>
  <text x="360" y="115" text-anchor="middle" font-size="12.5" font-weight="600" fill="#334155">vfs_open() → do_dentry_open()</text>
  <line x1="360" y1="126" x2="360" y2="140" stroke="#475569" stroke-width="1.6" marker-end="url(#arrLSM1)"/>

  <rect x="190" y="142" width="340" height="46" rx="8" fill="#4f46e5"/>
  <text x="360" y="163" text-anchor="middle" font-size="13" font-weight="700" fill="#ffffff">security_file_open(file)</text>
  <text x="360" y="180" text-anchor="middle" font-size="10.5" fill="#e0e7ff">LSM hook 插入点</text>

  <line x1="360" y1="188" x2="210" y2="204" stroke="#475569" stroke-width="1.6" marker-end="url(#arrLSM1)"/>
  <line x1="360" y1="188" x2="530" y2="204" stroke="#475569" stroke-width="1.6" marker-end="url(#arrLSM1)"/>

  <rect x="60" y="206" width="300" height="58" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="210" y="230" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">SELinux: file_has_perm()</text>
  <text x="210" y="250" text-anchor="middle" font-size="11" fill="#4f46e5">检查 type enforcement 规则</text>

  <rect x="380" y="206" width="300" height="58" rx="8" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="530" y="230" text-anchor="middle" font-size="12" font-weight="700" fill="#115e59">AppArmor: aa_file_perm()</text>
  <text x="530" y="250" text-anchor="middle" font-size="11" fill="#0f766e">检查路径 profile</text>

  <line x1="210" y1="264" x2="360" y2="280" stroke="#475569" stroke-width="1.6" marker-end="url(#arrLSM1)"/>
  <line x1="530" y1="264" x2="360" y2="280" stroke="#475569" stroke-width="1.6" marker-end="url(#arrLSM1)"/>

  <rect x="210" y="282" width="300" height="38" rx="8" fill="#dcfce7" stroke="#4ade80"/>
  <text x="360" y="306" text-anchor="middle" font-size="13" font-weight="700" fill="#166534">同时返回 OK → 操作允许</text>

  <rect x="60" y="334" width="600" height="50" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="76" y="356" font-size="12.5" fill="#3730a3">同一个 hook 点上,SELinux 与 AppArmor 各自独立检查同一次 open 调用,</text>
  <text x="76" y="374" font-size="12.5" fill="#3730a3">两个模块都放行,操作才被允许。</text>
</svg>

---

## SELinux: Type Enforcement

```
核心概念:
  - 一切都有标签 (label): 文件, 进程, socket, ...
    → ls -Z: system_u:object_r:httpd_sys_content_t:s0
  - 策略定义"哪个 source type 可以访问哪个 target type 的哪个 class"
    → 白名单模型: 默认拒绝, 只有明确允许的才放行
  - AVC (Access Vector Cache): 策略查询结果缓存 (性能关键)

SELinux 模式:
  /sys/fs/selinux/enforce
    Enforcing (1): 拒绝 + 日志
    Permissive (0): 允许 + 日志 (调试用)
    Disabled: 完全不加载

标签存储:
  ext4/xfs: xattr security.selinux
  tmpfs/procfs: 运行时生成 (genfscon)
```

## AppArmor: 路径匹配

```
路径 profile 模型:
  安全策略不基于 type，而是基于路径匹配:
    /usr/bin/nginx {
      /var/www/** r,
      /var/log/nginx/* w,
      /run/nginx.pid w,
      /tmp/** rw,
      capability net_bind_service,
    }

  优点:
    - 比 SELinux 直观 (看到路径就知道策略)
    - 策略文件独立 (每个程序一个)
  缺点:
    - 路径可以被绕过 (hardlink, bind mount)
    - 不方便表达复杂的全局约束
```

## SMACK: 简化 Type Enforcement

```
类似 SELinux 但简化了 90%:
  - 只有 label, 没有 role/user/MLS
  - 规则: "subject label access object label"
  - 用于: Tizen (三星), Automotive Grade Linux

内核编译: CONFIG_SECURITY_SMACK
```

## BPF LSM (5.7+)

```c
// 用 BPF 程序实现 LSM hook:
// bpf(BPF_PROG_LOAD, BPF_PROG_TYPE_LSM, ...)
// attach: bpf(BPF_RAW_TRACEPOINT_OPEN, lsm/file_mprotect)

// 相比内核模块的优点:
//   - 不需要编译内核模块
//   - verifier 保证安全性 (不会 panic)
//   - 更容易分发和更新
```

## Capabilities: 拆分 root 特权

```c
// include/uapi/linux/capability.h
// 将 root 的全部能力拆分为细粒度 bit:
CAP_SYS_ADMIN      // 系统管理
CAP_NET_RAW        // raw socket
CAP_NET_BIND_SERVICE  // 绑定 <1024 端口
CAP_SYS_PTRACE     // ptrace 其他进程
CAP_KILL           // 给其他用户的进程发信号
// ... 40+ capabilities

// 容器安全的关键:
//   docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE
//   → 容器内 root 只能绑定端口, 不能加载模块
```

## IMA/EVM: 文件完整性

```
IMA (Integrity Measurement Architecture):
  测量: 每次文件被读取时计算 hash → 记录到 TPM
  Appraisal: 验证文件 hash → 拒绝被篡改的文件

EVM (Extended Verification Module):
  保护文件的元数据 (xattr, mode, owner) 不被篡改
  基于 HMAC (用 TPM 密钥) 或数字签名
```

## 调试

```bash
# SELinux
getenforce
ausearch -m avc --start recent  # 最近的拒绝
sealert -a /var/log/audit/audit.log  # 分析拒绝原因

# AppArmor
aa-status
cat /proc/<pid>/attr/apparmor/current

# capabilities
capsh --print  # 当前 shell 的 capabilities
getpcaps <pid>
```

## 参考

- **源码**: `security/` (lsm, selinux, apparmor, smack, integrity), `include/linux/lsm_hooks.h`
- **内核文档**: `Documentation/admin-guide/LSM/`
- **LWN**: "The LSM hook interface", "BPF LSM"

*关键词: LSM, SELinux, AppArmor, BPF LSM, capabilities, IMA, EVM, type enforcement, AVC*
