Skip to content

第一百六十五章:LSM 框架

渡劫期

涉及内核源码:

林小源离开 SELinux 的城堡,来到一片广阔的骨架森林。这里的树木没有叶子,只有光秃秃的枝干,每一根枝干上都挂着一个钩子。

"这是 LSM,"security.c 老者再次出现,"Linux Security Modules 框架。SELinux、AppArmor、Smack——它们都生长在这副骨架上。"

"骨架?"

"LSM 是内核的安全框架,"老者说,"它在关键操作处插入钩子,让安全模块决定是否允许操作。文件打开、进程发信号、套接字连接——每一个关键操作都有一个钩子。"

林小源走近一棵树,看到枝干上刻着 "security_file_open"。他伸手触摸,感受到一股力量从钩子中传来。

"这就是安全检查的地方?"

"是的,"老者说,"当进程打开文件时,内核调用 security_file_open(),LSM 框架调用所有注册的钩子。如果任何一个钩子拒绝,操作就被阻止。"

"但骨架本身不等于防御。"老者指着没有叶子的枝干,"LSM 框架只提供 hook 和 security blob。真正的安全策略,要由 SELinux、AppArmor、Smack、Landlock 这些模块填进去。没挂模块,骨架只是骨架。"

林小源看到枝干内部有许多空腔,分别连着 inode。"这些空腔是什么?"

"security fields,也叫 blob。"老者说,"不同模块把自己的标签和状态放进去。hook 分两类:一类管理这些字段的分配和释放,一类在 inode permission、file open、task kill 等关键点做访问控制。"

破关试炼

骨架初试

LSM 框架本身提供 hook 和 security blob;真正策略由谁实现?

答对后才能继续滑动和进入下一章。

"有哪些安全模块?"林小源问。

老者指向远方几棵不同的树:"SELinux 实现类型强制,最复杂。AppArmor 基于路径,Ubuntu 默认使用。Smack 简化标记,用于嵌入式系统。TOMOYO 基于路径,日本开发。Yama 限制 ptrace,是最小的模块。"

"它们能共存吗?"

"可以,"老者说,"LSM 框架允许不同模块共存。但通常只启用一个主要模块,其他模块提供补充功能。"

"共存也有顺序。"老者折下一片枯叶,叶脉上浮现出一串名字。"hook 维护在列表里,调用顺序来自 CONFIG_LSM。系统运行时,可以读 /sys/kernel/security/lsm 看当前激活的模块。"

"那 capabilities 呢?"林小源想起上一章的宝石。

"它也和 LSM 有历史渊源。"老者说,"commoncap 是能力逻辑的实现之一,长期被放在安全框架的入口处。别把 capability 当成 LSM 之外的孤岛。"

林小源望着那些不同的树,心中感慨。守护的方式不止一种,每棵树都有自己的活法。

破关试炼

叠挂之试

查看当前启用 LSM 模块列表的 securityfs 路径是什么?

答对后才能继续滑动和进入下一章。

"LSM 的设计哲学是什么?"林小源问。

老者坐在一棵树下,说:"LSM 不实现具体的安全策略,只提供框架。具体策略由 SELinux、AppArmor 等模块实现。这让内核保持灵活——用户可以选择适合自己的安全模块,新的安全模块也可以轻松添加。"

"这就是为什么内核不硬编码安全策略?"

"正是,"老者说,"安全需求因场景而异。服务器需要 SELinux 的严格控制,桌面系统可能只需要 AppArmor 的简单保护。LSM 让这种选择成为可能。"

"还有一条边界。"老者把一卷旧文档递给林小源,封面上写着 outdated。"许多 LSM 文档记录的是框架思想和历史 API,现代内核的具体 hook 细节要回到 security/security.c 和头文件里看。修行最忌拿旧地图当现地形。"

林小源望着那片骨架森林,心中豁然开朗。在这片内核的深处,骨架不是脆弱,而是灵活。安全模块在上面生长,守护着整个系统。

破关试炼

边界之试

LSM 文档里明确提醒部分 API 描述已经怎样,具体 hook 细节应回源码确认?

答对后才能继续滑动和进入下一章。

c
/*
 * LSM (Linux Security Modules) 框架:
 *
 * 设计目标:
 *   允许不同的安全模块共存
 *   不修改内核核心代码
 *   通过钩子函数实现安全策略
 *
 * 钩子函数:
 *   security_file_open — 打开文件时
 *   security_file_read — 读取文件时
 *   security_inode_create — 创建 inode 时
 *   security_task_kill — 发送信号时
 *   security_socket_connect — 连接套接字时
 *   ...
 *
 * 钩子位置:
 *   在内核关键操作处
 *   调用 security_xxx() 函数
 *   LSM 框架调用注册的钩子
 *
 * 安全模块:
 *   SELinux — 类型强制
 *   AppArmor — 路径型
 *   Smack — 简化标记
 *   TOMOYO — 路径型
 *   Yama — ptrace 限制
 */

/* 模拟 LSM 钩子 */
typedef int (*lsm_hook_fn_t)(void *ctx);

struct security_hook_list {
    const char *name;
    lsm_hook_fn_t hook;
};

/* SELinux 的钩子实现 */
int selinux_file_open(void *ctx) {
    printf("  [SELinux] 检查文件打开权限\n");
    /* 检查安全上下文 */
    return 0; /* 允许 */
}

/* AppArmor 的钩子实现 */
int apparmor_file_open(void *ctx) {
    printf("  [AppArmor] 检查文件路径\n");
    /* 检查路径是否在 profile 中 */
    return 0; /* 允许 */
}

/* 模拟钩子调用 */
int security_file_open(void *ctx) {
    printf("LSM 框架: security_file_open 被调用\n");

    /* 调用 SELinux 钩子 */
    selinux_file_open(ctx);

    /* 调用 AppArmor 钩子 */
    apparmor_file_open(ctx);

    return 0;
}

printf("=== LSM 框架 — 安全的骨架 ===\n\n");

printf("LSM 是内核的安全框架:\n\n");

printf("--- 设计目标 ---\n");
printf("1. 允许不同安全模块共存\n");
printf("2. 不修改内核核心代码\n");
printf("3. 通过钩子函数实现策略\n\n");

printf("--- 钩子函数示例 ---\n");
printf("security_file_open\n");
printf("security_file_read\n");
printf("security_inode_create\n");
printf("security_task_kill\n");
printf("security_socket_connect\n");
printf("security_bprm_check\n\n");

printf("--- 模拟钩子调用 ---\n");
security_file_open(NULL);

printf("\n--- LSM 安全模块 ---\n");
printf("SELinux:\n");
printf("  类型强制 (TE)\n");
printf("  最复杂的模块\n\n");
printf("AppArmor:\n");
printf("  路径型\n");
printf("  Ubuntu 默认\n\n");
printf("Smack:\n");
printf("  简化标记\n");
printf("  嵌入式系统\n\n");
printf("TOMOYO:\n");
printf("  路径型\n");
printf("  日本开发\n\n");
printf("Yama:\n");
printf("  ptrace 限制\n");
printf("  最小模块\n\n");

printf("--- 查看当前 LSM ---\n");
printf("cat /sys/kernel/security/lsm\n\n");

printf("--- LSM 的意义 ---\n");
printf("1. 内核不再硬编码安全策略\n");
printf("2. 用户可以选择安全模块\n");
printf("3. 新的安全模块可以轻松添加\n");

道藏笔记

内核启示

LSM 不管具体安全策略,它只搭架子:hook 放在打开文件、发信号、连套接字、检查 inode 权限等关键路径上,security blob 挂在 task、cred、inode、file、socket 等对象上。SELinux、AppArmor、Smack、TOMOYO、Yama、Landlock 等模块在这副骨架上实现自己的策略。

这样设计的好处是灵活:服务器选 SELinux 的严格控制,桌面选 AppArmor 的简单保护,嵌入式选 Smack 的轻量标记。多个模块可以按 CONFIG_LSM 顺序叠挂,/sys/kernel/security/lsm 能看到当前激活列表。注意官方 lsm.rst 已标注部分 API 描述过时,写具体 hook 时要回源码确认。

cat /sys/kernel/security/lsm 能看到当前启用了哪些模块。

LSM 是骨架——安全模块在上面生长。


破关试炼

LSM 之试

LSM 框架允许多个安全模块在内核钩子上做访问决策,本章举的典型模块是哪一个?

答对后才能继续滑动和进入下一章。

以修仙之名,悟内核之道