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

Linux fsverity_file_open fs-verity Merkle树校验

Linux fsverity_file_open fs-verity Merkle树校验

fs-verity是Linux内核的只读文件完整性保护机制,基于Merkle树实现逐块哈希验证。核心入口是fsverity_file_open,在文件打开时验证完整性元数据并初始化验证上下文。

整体框架位于fs/verity/目录,由open.c、verify.c、measure.c、enable.c等文件组成。fsverity_file_open是文件打开路径的钩子,在__fput之前调用:

int fsverity_file_open(struct inode *inode, struct file *file)
{
struct fsverity_info *vi;
int err;

vi = fsverity_get_info(inode);
if (!vi)
return 0;

err = fsverity_check_digest(inode, vi);
if (err)
return err;

file->f_mode |= FMODE_VERITY;
return 0;
}

fsverity_get_info从inode中获取或构造fsverity_info结构体,包含Merkle树的根哈希和测量数据:

struct fsverity_info *fsverity_get_info(const struct inode *inode)
{
struct fsverity_info *vi;

if (inode->i_verity_info)
return inode->i_verity_info;

vi = fsverity_create_info(inode);
if (IS_ERR(vi))
return NULL;

inode->i_verity_info = vi;
return vi;
}

fsverity_create_info解析verity元数据(存储在文件的扩展属性或特殊块中)并构建Merkle树验证上下文:

struct fsverity_info *fsverity_create_info(const struct inode *inode)
{
struct fsverity_info *vi;
struct fsverity_descriptor *desc;
int ret;

vi = kzalloc(sizeof(*vi), GFP_KERNEL);
if (!vi)
return ERR_PTR(-ENOMEM);

desc = kzalloc(sizeof(*desc) + FS_VERITY_MAX_LEVEL_SIZE, GFP_KERNEL);
if (!desc) {
kfree(vi);
return ERR_PTR(-ENOMEM);
}

ret = inode->i_sb->s_vop->get_verity_descriptor(inode, desc, sizeof(*desc));
if (ret < 0) {
kfree(desc);
kfree(vi);
return ERR_PTR(ret);
}

vi->tree_params.hash_algorithm = desc->hash_algorithm;
vi->tree_params.block_size = le32_to_cpu(desc->log_blocksize) ?: PAGE_SIZE;
vi->data_params = fsverity_init_hash_tree_params(desc, 0);
vi->tree_params = fsverity_init_hash_tree_params(desc, FS_VERITY_HASH_TREE);
vi->level_params = fsverity_init_level_params(desc);

memcpy(vi->root_hash, desc->root_hash, desc->hash_algorithm->digest_size);
kfree(desc);
return vi;
}

Merkle树验证发生在每次page fault时的数据读取路径。核心函数是fsverity_verify_blocks,它验证一个或多个数据块:

bool fsverity_verify_blocks(struct inode *inode, struct page **pages, unsigned int count)
{
struct fsverity_info *vi = inode->i_verity_info;
unsigned int level;
int err;

for (unsigned int i = 0; i < count; i++) {
struct page *page = pages[i];
unsigned long offset = page->index << PAGE_SHIFT;
struct ahash_request *req;
SHA256_CTX ctx;

err = fsverity_verify_level(vi, offset, vi->level_params,
&level, vi->root_hash);
if (err)
return false;

req = ahash_request_alloc(vi->tree_params.hash_alg->tfm, GFP_NOFS);
ahash_request_set_crypt(req, NULL, vi->measurement, 0);
crypto_ahash_init(req);

crypto_ahash_update(req, page, PAGE_SIZE);
crypto_ahash_final(req);

if (crypto_memneq(req->result, vi->measurement, vi->digest_size))
return false;

ahash_request_free(req);
}
return true;
}

实际实现中,fsverity_verify_level从叶节点开始逐层向上验证,直到根节点。每个Merkle树节点的哈希验证函数:

static int fsverity_verify_level(struct inode *inode, unsigned long offset,
struct merkle_tree_params *params,
unsigned int *level, const u8 *root_hash)
{
struct fsverity_blockbuf block;
struct fsverity_hash_alg *alg = params->hash_alg;
u8 digest[FS_VERITY_MAX_DIGEST_SIZE];
int err;

for (*level = params->num_levels; *level > 0; (*level)--) {
unsigned long hash_offset = fsverity_hash_level_offset(params, *level, offset);

err = params->hash_blocks[*level - 1]->read(inode, hash_offset, &block);
if (err)
return err;

if (*level == params->num_levels)
fsverity_compute_hash(alg, block.kaddr, block.len, digest);
else
fsverity_compute_hash(alg, block.kaddr, block.len, digest);

if (crypto_memneq(digest, root_hash, alg->digest_size))
return -EBADMSG;
}
return 0;
}

fs-verity的哈希树参数定义:

struct merkle_tree_params {
struct fsverity_hash_alg *hash_alg;
unsigned int block_size;
unsigned int log_blocksize;
unsigned int num_levels;
struct fsverity_blockbuf *hash_blocks;
unsigned int hashes_per_block;
};

Merkle树的层级计算公式:每个数据块计算一个哈希值,多个哈希值组成上一级的哈希块。层级数由文件大小和块大小决定:

static unsigned int fsverity_compute_num_levels(unsigned long data_size,
unsigned int block_size)
{
unsigned int num_levels = 0;
unsigned long blocks = data_size / block_size;

while (blocks > 1) {
blocks = DIV_ROUND_UP(blocks, block_size / sizeof(struct fsverity_hash));
num_levels++;
}
return num_levels;
}

文件打开时的最终校验fsverity_check_digest将文件测量值与用户指定的期望值比较:

static int fsverity_check_digest(const struct inode *inode,
struct fsverity_info *vi)
{
struct fsverity_digest *expected = fsverity_get_digest(inode);
int ret;

if (!expected)
return 0;

if (expected->digest_algorithm != vi->tree_params.hash_algorithm) {
ret = -EINVAL;
goto out;
}

if (crypto_memneq(vi->root_hash, expected->digest,
vi->tree_params.hash_algorithm->digest_size))
ret = -EIO;
else
ret = 0;

out:
kfree(expected);
return ret;
}

fs-verity与IMA(Integrity Measurement Architecture)的区别:fs-verity专注于文件内容的运行时验证,基于Merkle树实现O(1)的增量验证成本,每个读操作只验证访问的数据块路径,而非整个文件。DM-verity类似但工作在块设备层,而fs-verity工作在文件系统层,支持ext4和f2fs。

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

相关文章:

  • PySpark ML实战:工业级机器学习流水线构建指南
  • 小米智能手表表盘个性化终极指南:Mi-Create免费创作工具完全解析
  • 移远BC26连接OneNET时,为什么你的数据上传失败?可能是MQTT版本没设对
  • 绍兴报名 CPPM 注册采购经理哪家靠谱?机构选择避坑指南 - 众智商学院课程中心
  • 2026年成都夹胶玻璃选购指南:技术参数、应用场景与本地厂家实测分析 - 优质品牌商家
  • 本体论驱动的AI访问控制:企业Copilot语义防火墙实战
  • 量子与带状共轭:结理论中的代数结构与应用
  • HC-05蓝牙模块AT指令配置避坑指南:从手机连不上到双机配对失败的常见问题排查
  • 肇庆市黄金回收门店推荐 五家靠谱店铺TOP排行榜及联系方式地址电话+白银回收+铂金回收+彩金回收当场结算 - 大熊猫898989
  • 从调零电阻到恒流源:一个老工程师的差动放大电路调试笔记与避坑指南
  • 5V/3.3V混搭系统实战:STM32F030与CS1237的电平转换与SPI通信稳定性全解析
  • 2026年北京黄花梨家具回收市场观察:诚信机构如何选择?附京津冀回收指南 - 优质品牌商家
  • 2026年生态地铺石厂家怎么选?深度解析四川产区技术、交付与售后体系! - 优质品牌商家
  • AD5761R菊花链调试笔记:SPI时序、LDAC用法与数据错位问题排查
  • RABot框架:基于强化学习的社交机器人检测技术
  • Python量化踩坑实录:用Backtrader实现SMA双均线策略,我遇到的3个数据与佣金陷阱
  • SageMaker生产落地的7个死亡检查项与MLOps责任断点
  • 华为eNSP ACL配置避坑指南:从‘全网通’到‘精准控制’,我踩过的那些坑
  • 51单片机RFID门禁系统避坑指南:从LCD初始化失败到继电器误触发的那些事儿
  • 2026年印刷生产管理软件选购指南:从ERP到AI智能体,谁在定义数字工厂? - 优质品牌商家
  • 2026年德州市CPPM考试最新全攻略:科目题型、通过率、备考重点及官方双认证报考机构推荐 - 众智商学院课程中心
  • VMware vCenter 6.7证书管理避坑指南:从自动续订失效到手动修复STS的全流程复盘
  • 如何用Translumo实现Windows实时屏幕翻译:5步掌握游戏外语翻译神器
  • 镇江市黄金回收门店推荐 五家靠谱店铺TOP排行榜及联系方式地址电话+白银回收+铂金回收+彩金回收当场结算 - 大熊猫898989
  • 终极指南:免费在电脑上运行Switch游戏的yuzu模拟器
  • 郑州市黄金回收门店推荐 五家靠谱店铺TOP排行榜及联系方式地址电话+白银回收+铂金回收+彩金回收当场结算 - 大熊猫898989
  • Android 13有线网络踩坑记:设置静态IP后疯狂断网,我是这样定位并修复的
  • ChatGPT自定义指令实战指南:打造专属AI协作人格
  • Formality验证总失败?先别急着改设计,试试这个变量:verification_set_undriven_signals
  • 避开DFT设计中的那些‘坑’:Tessent Scan与ATPG实战避坑指南