当前位置: 首页 > news >正文

Linux integrity iint节点与ima_file_mmap测量

Linux integrity iint节点与ima_file_mmap测量

integrity子系统的核心数据结构是struct integrity_iint,它为每个被监控的inode维护完整性元数据。IMA(Integrity Measurement Architecture)在file_mmap钩子中执行文件mmap映射时的完整性测量,确保映射到进程地址空间的可执行文件内容在测量基准上未被篡改。

struct integrity_iint定义在security/integrity/iint.c中,通过inode的iint_cache和rb_tree组织:

```c
struct integrity_iint {
struct rb_node rb_node; /* 红黑树节点,以inode指针排序 */
struct rcu_head rcu; /* RCU回调 */
struct inode *inode; /* 关联的inode指针 */
u64 version; /* inode版本号,检测文件变更 */
unsigned char flags; /* IMA状态标志位 */
enum integrity_status ima_file_status : 4; /* 文件完整性状态 */
enum integrity_status ima_mmap_status : 4; /* mmap完整性状态 */
enum integrity_status ima_bprm_status : 4; /* exec完整性状态 */
enum integrity_status ima_read_status : 4; /* 读取完整性状态 */
enum integrity_status ima_creds_status : 4; /* 凭证完整性状态 */
struct ima_digest_data *ima_hash; /* 文件内容的完整性hash */
};
```

integrity_iint_cache是全局的管理结构,保存所有iint节点的查询树:

```c
static struct rb_root integrity_iint_tree = RB_ROOT;
static DEFINE_SPINLOCK(integrity_iint_lock);
static struct kmem_cache *iint_cache;

struct integrity_iint *integrity_iint_find(struct inode *inode)
{
struct rb_node *n = integrity_iint_tree.rb_node;

/* 以inode指针为key在红黑树中查找 */
while (n) {
struct integrity_iint *iint = rb_entry(n, struct integrity_iint, rb_node);

if (inode < iint->inode)
n = n->rb_left;
else if (inode > iint->inode)
n = n->rb_right;
else
return iint;
}

return NULL;
}
```

ima_file_mmap是IMA在mmap系统调用中执行完整性测量的钩子,注册在security/integrity/ima/ima_main.c中:

```c
int ima_file_mmap(struct file *file, unsigned long prot, unsigned long flags)
{
u32 secid;
int ret;

if (!file)
return 0;

/* 仅检查可执行映射:PROT_EXEC且非PROT_WRITE */
if (!(prot & PROT_EXEC))
return 0;

/* 跳过写回映射(writeback mapping)中的mmap检查 */
if (flags & MAP_SHARED && prot & PROT_WRITE)
return 0;

/* 获取文件的LSM安全ID */
security_task_getsecid(current, &secid);

/* 执行完整性测量策略 */
return process_measurement(file, current_cred(), secid, NULL,
0, MAY_EXEC, MMAP_CHECK);
}
```

process_measurement是IMA测量操作的核心函数,处理所有测量、评估和审计操作:

```c
static int process_measurement(struct file *file, const struct cred *cred,
u32 secid, char *buf, loff_t size,
int mask, enum ima_hooks func)
{
struct inode *inode = file_inode(file);
struct integrity_iint *iint;
int rc = 0;
int action = 0;
u64 pathname = 0;

/* 查找或创建inode对应的iint节点 */
iint = integrity_iint_find(inode);
if (!iint) {
/* 首次访问此inode,分配新的iint */
iint = integrity_iint_insert(inode);
if (!iint)
return -ENOMEM;
}

/* 锁定iint,防止并发测量 */
mutex_lock(&iint->mutex);

/* 检查策略是否要求测量此文件 */
action = ima_get_action(inode, cred, secid, mask, func, &pcr, &template,
&func_retry);

/* 如果inode版本变化,说明文件已被修改,需要重新测量 */
if (action & IMA_MEASURE) {
if (iint->flags & IMA_MEASURED &&
iint->version == inode->i_version)
action &= ~IMA_MEASURE;
}

/* 执行完整性测量 */
if (action & IMA_MEASURE) {
rc = ima_collect_measurement(iint, file, buf, size, hash_algo);
if (rc < 0)
goto out;

/* 将测量结果扩展到TPM PCR并存入IMA测量列表 */
ima_store_measurement(iint, file, pathname, cred, secid,
pcr, template, func);

iint->flags |= IMA_MEASURED;
iint->version = inode->i_version;
}

/* 执行完整性评估(如果策略要求) */
if (action & IMA_APPRAISE) {
rc = ima_appraise_measurement(func, iint, file, pathname,
cred, secid, buf, size);
if (rc == -EACCES)
goto out;
}

out:
mutex_unlock(&iint->mutex);
return rc;
}
```

ima_collect_measurement计算文件内容的hash值并存入iint节点:

```c
int ima_collect_measurement(struct integrity_iint *iint, struct file *file,
void *buf, loff_t size, enum hash_algo algo)
{
struct ima_digest_data *hash;
int result = -ENOMEM;

/* 分配hash数据结构 */
hash = kzalloc(sizeof(*hash) + sizeof(struct ima_field_data), GFP_NOFS);
if (!hash)
return -ENOMEM;

hash->algo = algo;
hash->length = hash_digest_size[algo];

/* 使用内核加密API计算文件内容的hash */
result = kernel_read_file(file, 0, &buf, size, NULL, READING_POLICY);
if (result < 0)
goto out;

result = ima_calc_field_array_hash(hash, file);
if (result < 0)
goto out;

/* 释放旧的hash并替换为新的测量结果 */
kfree(iint->ima_hash);
iint->ima_hash = hash;

out:
return result;
}
```

ima_store_measurement将测量结果添加到PCR扩展和IMA测量列表,供远程证明使用:

```c
void ima_store_measurement(struct integrity_iint *iint, struct file *file,
const unsigned char *filename,
struct evm_ima_xattr_data *xattr_value,
int violation, struct ima_template_desc *template_desc)
{
static const char op[] = "add_template_measure";
static const char audit_cause[] = "missing_template";
struct ima_template_entry *entry;
int violation = 0;
int result;

/* 创建模板条目,包含文件元数据和hash */
result = ima_alloc_init_template(iint, file, filename, xattr_value,
template_desc, &entry);
if (result < 0)
return;

/* 扩展TPM PCR */
result = ima_extend_pcr(entry, iint->ima_hash->algo);
if (result)
goto out;

/* 将测量加入全局测量列表 */
result = ima_add_template_entry(entry, violation, op, file, audit_cause);

out:
if (result)
ima_free_template_entry(entry);
}
```

integrity_iint_insert在红黑树中插入新的iint节点:

```c
struct integrity_iint *integrity_iint_insert(struct inode *inode)
{
struct integrity_iint *iint;
struct rb_node **p, *parent = NULL;

iint = kmem_cache_alloc(iint_cache, GFP_NOFS);
if (!iint)
return NULL;

memset(iint, 0, sizeof(*iint));
iint->inode = inode;
mutex_init(&iint->mutex);

spin_lock(&integrity_iint_lock);
p = &integrity_iint_tree.rb_node;
while (*p) {
struct integrity_iint *test = rb_entry(*p, struct integrity_iint, rb_node);
parent = *p;
if (inode < test->inode)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&iint->rb_node, parent, p);
rb_insert_color(&iint->rb_node, &integrity_iint_tree);
spin_unlock(&integrity_iint_lock);

return iint;
}
```

IMA的测量策略通过内核启动参数ima_policy或/sys/kernel/security/ima/policy接口动态加载。策略规则定义哪些文件需要被测量,例如"measure func=MMAP_CHECK mask=MAY_EXEC"规则指示对所有mmap可执行映射的文件执行测量。每次文件映射时ima_file_mmap触发process_measurement,对照策略规则决定是否需要执行hash测量并扩展TPM PCR,确保运行时可执行文件的完整性可追溯。

http://www.jsqmd.com/news/1003888/

相关文章:

  • 2026杭州美院附中考前班评测:四家机构核心维度对比 - 优质品牌商家
  • 临汾千鸿黄金回收盘点 2026六家正规店避坑 - 余生黄金回收
  • 保姆级教程:在Yolov5s中手把手集成CARAFE上采样算子(附完整代码与避坑指南)
  • FigmaCN终极指南:免费解锁中文版Figma的3种快速方法
  • 别再手动调API了!用GPT-3.5-turbo-16k的函数调用,5分钟搞定天气查询机器人
  • 2026年618优麦云/卖家精灵/达人精灵 折扣码限时优惠礼遇​ - 李先生sir
  • MYSQL RR 解决“脏读+不可重复读“和“幻读“的本质区别
  • 如何免费实现7种音频格式高效转换:FlicFlac专业解决方案指南
  • 2026南通全媒体运营TOP榜单:短视频策划拍摄/账号运营/话题打造/达人联动/信息流投放/微信公众号及视频号内容运营与活动策划一站式优选 - 品牌发掘
  • 2026年 厦门连接线/端子线/电子线/排线/跳线/USB连接线/插头线厂家推荐:精准传输与耐用工艺之选 - 品牌发掘
  • 2026年 江西凉亭厂家推荐榜单:六角/八角/双层/四角凉亭,古韵匠心与户外园林精品之选 - 品牌发掘
  • Linux inode_permission inode权限检查与acl处理
  • 别再找旧脚本了!MMdetection 3.X 版本官方工具一键生成PR曲线图(附完整配置流程)
  • 2026年C语言找工作难吗?普通人还能找到好工作吗?
  • 兰州黄金回收实测 余生珍宝六店行情解析 - 余生黄金回收
  • C盘存储爆红,哪些文件类型可以安全删除?一张清单分三档
  • CVI工程中直接调用自定义DLL的实操资源包(含双项目源码与一键构建脚本)
  • Python生产级API设计:可观测、可演进、可防御的请求生命周期治理
  • TMS320F28335四层小板:6×8cm带USB供电、JTAG下载、复位键和全引脚标注
  • 六盘水珍宝黄金回收测评 2026买金避坑指南 - 余生黄金回收
  • 浙江大学LaTeX论文模板:5分钟快速生成专业毕业论文的终极指南
  • 避开回收套路荆州六大黄金门店测评 - 余生黄金回收
  • 2026年英文降AIGC率指南:别盲目同义词替换!5种降AI高效方法实测(附工具测评) - 降AI实验室
  • C盘大文件怎么搬到D盘或其他分区?从定位到迁移的完整操作
  • 别再只会录宏了!WPS JS宏实战:用filter和箭头函数5分钟搞定数据清洗
  • Spring Boot 文件上传大小限制配置全解析
  • 从英国到葡萄牙,这群欧洲青年为何把目光投向中国开源?
  • 寄行李大件什么物流最省钱?用“寄半折”比价立省一半 - 快递物流资讯
  • 2026甘孜州权威认证贵金属回收 TOP5+黄金回收白银回收铂金回收门店地址电话推荐
  • Logisim 2.7.1 手把手:从零搭建一个支持13种运算的32位MIPS ALU(附完整电路图)