第一百七十四章:完整性度量
渡劫期涉及内核源码:
一
审计回廊之外,林小源来到一座白色的塔楼前。塔楼的表面光滑如镜,没有任何装饰——但仔细看去,镜面上浮现出一串串哈希值,像指纹一样密密麻麻地覆盖着每一块砖石。
一个全身裹在白色长袍中的修士从塔楼中走出,长袍上绣着 "IMA" 三个字母。
"Integrity Measurement Architecture,"修士的声音平静而坚定,"我不关心谁能访问什么——那是 SELinux 的事。我只关心一件事:文件有没有被篡改。"
林小源伸手触碰塔楼的砖石。每一块砖石上都刻着一个 SHA256 哈希值——那是文件在某个时刻的数字指纹。
"每次文件被执行或被访问,"IMA 修士说,"我都会计算它的哈希,记录到 TPM 的度量日志中。如果文件被修改——哪怕只改了一个字节——哈希就对不上了。"
"这和审计有什么区别?"
"审计记录'谁做了什么',我记录'文件是否完整'。审计是事后追溯,我是实时验证。"
"更准确地说,度量列表不是一张普通账本。"IMA 修士指向塔底,"TCG 运行时 IMA 会维护 executables 和敏感文件的 hash 列表,策略还可以受 LSM 数据约束。度量结果可以放进不同模板,不只是文件名和摘要,也能带 inode UID/GID、LSM label、签名、xattr 等字段。"
白塔初试
IMA 度量列表可以通过模板扩展,除摘要和文件名外还能记录哪类安全标签信息?
/*
* IMA (Integrity Measurement Architecture):
*
* 功能:
* 度量 — 计算文件哈希,记录到 TPM
* 评估 — 验证文件是否被篡改
* 审计 — 记录完整性事件
*
* IMA 策略:
* measure — 度量文件哈希
* appraise — 验证文件完整性
* audit — 记录事件
*
* 策略规则:
* measure func=FILE_MMAP mask=MAY_EXEC
* appraise func=BPRM_CHECK
*
* EVM (Extended Verification Module):
* 保护文件元数据
* 验证 security xattr
* 防止权限提升
*
* dm-verity:
* 块设备完整性
* 保护整个文件系统
* 用于 Android Verified Boot
*/
/* 模拟完整性度量 */
struct integrity_record {
char file[128];
char hash[65]; /* SHA256 */
int status; /* 0=unknown, 1=valid, 2=invalid */
};
struct ima_log {
struct integrity_record records[10];
int count;
};
void ima_measure(struct ima_log *log, const char *file, const char *hash) {
if (log->count >= 10) return;
strncpy(log->records[log->count].file, file, 127);
strncpy(log->records[log->count].hash, hash, 64);
log->records[log->count].status = 1; /* valid */
log->count++;
}
int ima_appraise(struct ima_log *log, const char *file, const char *hash) {
for (int i = 0; i < log->count; i++) {
if (strcmp(log->records[i].file, file) == 0) {
if (strcmp(log->records[i].hash, hash) == 0)
return 1; /* 完整 */
return 0; /* 被篡改 */
}
}
return -1; /* 未度量 */
}
void print_record(struct integrity_record *r) {
printf(" 文件: %s\n", r->file);
printf(" 哈希: %s\n", r->hash);
printf(" 状态: %s\n",
r->status == 1 ? "有效" : r->status == 2 ? "无效" : "未知");
}
printf("=== 完整性度量 — 防止篡改 ===\n\n");
printf("IMA/EVM 确保文件完整性:\n\n");
/* 创建 IMA 日志 */
struct ima_log log = { .count = 0 };
/* 度量文件 */
ima_measure(&log, "/usr/bin/cat",
"abc123def456789012345678901234567890123456789012345678901234abcd");
ima_measure(&log, "/usr/bin/ls",
"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef");
printf("--- IMA 度量日志 ---\n");
for (int i = 0; i < log.count; i++) {
print_record(&log.records[i]);
printf("\n");
}
printf("--- 完整性验证 ---\n");
/* 验证文件 */
int r1 = ima_appraise(&log, "/usr/bin/cat",
"abc123def456789012345678901234567890123456789012345678901234abcd");
printf("/usr/bin/cat: %s\n", r1 == 1 ? "完整" : "被篡改");
int r2 = ima_appraise(&log, "/usr/bin/ls",
"0000000000000000000000000000000000000000000000000000000000000000");
printf("/usr/bin/ls: %s\n", r2 == 1 ? "完整" : "被篡改");
printf("\n--- IMA 策略 ---\n");
printf("measure:\n");
printf(" 计算文件哈希\n");
printf(" 记录到 TPM\n\n");
printf("appraise:\n");
printf(" 验证文件完整性\n");
printf(" 拒绝被篡改的文件\n\n");
printf("audit:\n");
printf(" 记录完整性事件\n\n");
printf("--- EVM ---\n");
printf("Extended Verification Module:\n");
printf(" 保护文件元数据\n");
printf(" 验证 security xattr\n");
printf(" 防止权限提升\n\n");
printf("--- dm-verity ---\n");
printf("块设备完整性:\n");
printf(" 保护整个文件系统\n");
printf(" 使用 Merkle 树\n");
printf(" Android Verified Boot\n\n");
printf("--- 查看 IMA ---\n");
printf("cat /sys/kernel/security/ima/policy\n");
printf("cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements\n");#include <stdio.h>
#include <string.h>
/*
* IMA (Integrity Measurement Architecture):
*
* 功能:
* 度量 — 计算文件哈希,记录到 TPM
* 评估 — 验证文件是否被篡改
* 审计 — 记录完整性事件
*
* IMA 策略:
* measure — 度量文件哈希
* appraise — 验证文件完整性
* audit — 记录事件
*
* 策略规则:
* measure func=FILE_MMAP mask=MAY_EXEC
* appraise func=BPRM_CHECK
*
* EVM (Extended Verification Module):
* 保护文件元数据
* 验证 security xattr
* 防止权限提升
*
* dm-verity:
* 块设备完整性
* 保护整个文件系统
* 用于 Android Verified Boot
*/
/* 模拟完整性度量 */
struct integrity_record {
char file[128];
char hash[65]; /* SHA256 */
int status; /* 0=unknown, 1=valid, 2=invalid */
};
struct ima_log {
struct integrity_record records[10];
int count;
};
void ima_measure(struct ima_log *log, const char *file, const char *hash) {
if (log->count >= 10) return;
strncpy(log->records[log->count].file, file, 127);
strncpy(log->records[log->count].hash, hash, 64);
log->records[log->count].status = 1; /* valid */
log->count++;
}
int ima_appraise(struct ima_log *log, const char *file, const char *hash) {
for (int i = 0; i < log->count; i++) {
if (strcmp(log->records[i].file, file) == 0) {
if (strcmp(log->records[i].hash, hash) == 0)
return 1; /* 完整 */
return 0; /* 被篡改 */
}
}
return -1; /* 未度量 */
}
void print_record(struct integrity_record *r) {
printf(" 文件: %s\n", r->file);
printf(" 哈希: %s\n", r->hash);
printf(" 状态: %s\n",
r->status == 1 ? "有效" : r->status == 2 ? "无效" : "未知");
}
int main() {
printf("=== 完整性度量 — 防止篡改 ===\n\n");
printf("IMA/EVM 确保文件完整性:\n\n");
/* 创建 IMA 日志 */
struct ima_log log = { .count = 0 };
/* 度量文件 */
ima_measure(&log, "/usr/bin/cat",
"abc123def456789012345678901234567890123456789012345678901234abcd");
ima_measure(&log, "/usr/bin/ls",
"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef");
printf("--- IMA 度量日志 ---\n");
for (int i = 0; i < log.count; i++) {
print_record(&log.records[i]);
printf("\n");
}
printf("--- 完整性验证 ---\n");
/* 验证文件 */
int r1 = ima_appraise(&log, "/usr/bin/cat",
"abc123def456789012345678901234567890123456789012345678901234abcd");
printf("/usr/bin/cat: %s\n", r1 == 1 ? "完整" : "被篡改");
int r2 = ima_appraise(&log, "/usr/bin/ls",
"0000000000000000000000000000000000000000000000000000000000000000");
printf("/usr/bin/ls: %s\n", r2 == 1 ? "完整" : "被篡改");
printf("\n--- IMA 策略 ---\n");
printf("measure:\n");
printf(" 计算文件哈希\n");
printf(" 记录到 TPM\n\n");
printf("appraise:\n");
printf(" 验证文件完整性\n");
printf(" 拒绝被篡改的文件\n\n");
printf("audit:\n");
printf(" 记录完整性事件\n\n");
printf("--- EVM ---\n");
printf("Extended Verification Module:\n");
printf(" 保护文件元数据\n");
printf(" 验证 security xattr\n");
printf(" 防止权限提升\n\n");
printf("--- dm-verity ---\n");
printf("块设备完整性:\n");
printf(" 保护整个文件系统\n");
printf(" 使用 Merkle 树\n");
printf(" Android Verified Boot\n\n");
printf("--- 查看 IMA ---\n");
printf("cat /sys/kernel/security/ima/policy\n");
printf("cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements\n");
return 0;
}二
塔楼内部,林小源看到两个并排的房间。左边写着 "measure",右边写着 "appraise"。
"度量和评估,"IMA 修士推开左边的门,"度量是被动的——计算哈希,记录到 TPM 日志。文件照样执行,只是多了一条记录。"他推开右边的门,"评估是主动的——验证哈希是否匹配。如果文件被篡改,直接拒绝执行。"
林小源走进右边的房间,看到一面巨大的验证墙。每个文件执行前都要经过这面墙——墙上的哈希比对引擎会将当前文件的哈希与记录的哈希进行比较。
"不匹配就拒绝?"
"对。被篡改的文件无法执行。这就是 appraise 策略——最严格的完整性保护。"
"但你们不只做 IMA 对吧?"
IMA 修士点了点头,指向塔楼更高处:"EVM——Extended Verification Module。IMA 保护文件内容,EVM 保护文件的元数据。SELinux 的标签、文件的权限位——这些元数据如果被篡改,攻击者就能绕过访问控制。EVM 用 HMAC 签名保护这些元数据。"
"策略也不是只写 measure 和 appraise。"修士展开一卷白绢,"动作有 measure、dont_measure、appraise、dont_appraise、audit、dont_audit、hash、dont_hash。条件可以看 func=BPRM_CHECK、FILE_MMAP、MODULE_CHECK、FIRMWARE_CHECK、KEY_CHECK,也可以看 uid、euid、文件所有者、文件系统 UUID,甚至看 SELinux 的 subj/obj 标签。"
"默认策略呢?"
"会度量可执行文件、可执行 mmap、root 读取的文件、模块和固件;appraisal 则可以要求 root 拥有的文件通过完整性检查。策略写入 securityfs 的 ima/policy,关闭文件后生效。"
策略之试
IMA policy 中用于检查程序执行路径的 func 名称是什么?
三
塔楼的最高层,林小源透过窗户看到了远处的 Android 设备。设备的系统分区被一层金色的光网覆盖——那是 dm-verity 的 Merkle 树。
"块设备级别的完整性,"IMA 修士站在他身旁,"dm-verity 保护整个文件系统。每一个数据块都有一个哈希,哈希组成 Merkle 树,树根存在启动分区中。启动时验证整棵树——任何一块数据被篡改,树根就不匹配。"
林小源看着那棵巨大的 Merkle 树在阳光下闪烁。叶子节点是数据块的哈希,中间节点是子节点哈希的哈希,根节点是最终的信任锚。
"Android Verified Boot,"他说,"所以 Android 设备如果系统被篡改,就无法启动。"
"这就是信任链,"IMA 修士说,"从硬件信任根开始,经过 bootloader、内核、initramfs、文件系统——每一层都验证下一层。任何一环断裂,整个链条崩溃。"
"还有一个容易混淆的地方。"修士补充道,"IMA 更偏运行时度量和本地 appraisal;dm-verity 是块设备级别的只读完整性验证。它们可以同在一条信任链上,但检查粒度和位置不同。IMA 还能度量 keyring 里的 key,比如只度量 .builtin_trusted_keys 或 .ima keyring。"
林小源转身走下塔楼。每一步都踩在刻满哈希值的砖石上,那些数字指纹像无数只眼睛,注视着每一个经过的文件。完整性不是一道门,而是一张网——从文件内容到元数据,从内存到磁盘,无所不包。
链根之试
dm-verity 使用哪种哈希树来保护块设备完整性?
道藏笔记
内核启示
审计记录"谁做了什么",IMA 记录"文件有没有被改"。IMA 做度量、appraisal、audit/hash 等动作;策略可以按 BPRM_CHECK、FILE_MMAP、MODULE_CHECK、FIRMWARE_CHECK、KEY_CHECK,也可以按 uid、文件所有者、文件系统、LSM 标签等条件生效。模板还能把摘要、文件名、签名、xattr、inode UID/GID、LSM label 等信息放进 measurement list。
光保文件内容还不够,EVM 保护文件元数据和 security xattr。再往底层走,dm-verity 保护整个块设备,每个数据块一个哈希组成 Merkle 树。IMA 偏运行时度量和本地 appraisal,dm-verity 偏块设备只读完整性验证;二者可以共同服务可信启动和运行时信任链。
完整性度量是克星——篡改无处遁形。
完整性度量之试
完整性度量一章中,计算文件哈希并记录到 TPM 度量日志的架构缩写是什么?