在Linux内核安全领域,eBPF(extended Berkeley Packet Filter)技术已经成为系统可观测性和网络功能扩展的核心组件。随着eBPF在生产环境中的广泛应用,其安全性问题日益凸显。Hornet作为Linux安全模块(LSM)的一种实现,为eBPF程序提供了签名验证机制,本文将深入剖析其实现原理与技术细节。
Hornet签名功能的核心目标是为eBPF程序提供完整性保护,确保只有经过授权的代码能够在内核中执行。其设计采用了分层验证架构:
与传统的bpftool签名方案相比,Hornet针对加载器模式(use_loader)进行了特殊优化,使得签名验证能够适应动态加载场景。
Hornet签名功能基于以下关键技术构建:
这种技术组合在保证安全性的同时,也兼顾了与现有Linux安全体系的兼容性。
签名生成是整个过程的第一步,使用专门的gen_sig工具完成:
bash复制# 生成签名命令示例
scripts/hornet/gen_sig -data insn -cert signer.crt -key signer.key --add-hash data -out sign
参数说明:
-data insn:指定对.skel.h中的opts_insn部分(加载器指令)进行签名--add-hash data:为.skel.h中的opts_data部分(用户BPF信息map)生成哈希-cert和-key:指定签名证书和私钥生成签名后,需要将其集成到BPF程序的骨架文件中:
bash复制bpftool gen skeleton -L bpf_prog.o > bpf_prog.skel.h
c复制static const char opts_sig[] __attribute__((__aligned__(8))) = \
"......生成的签名内容......";
// 在结构体初始化中添加签名信息
opts.signature = (void *)opts_sig;
opts.signature_sz = sizeof(opts_sig) - 1;
这种设计使得签名成为程序加载过程的一个固有部分,而不是后期附加的安全措施。
当用户空间程序通过bpf系统调用加载BPF程序时,内核中的验证流程如下:
bpf(BPF_PROG_LOAD)系统调用security_bpf_prog_load()hornet_check_program()函数被调用内核首先解析PKCS#7格式的签名:
c复制msg = pkcs7_parse_message(sig, attr->signature_size);
这一步骤将签名数据转换为内核可以处理的结构体,同时验证签名的基本格式是否正确。
内核使用预置的密钥环验证签名证书的合法性:
c复制if (validate_pkcs7_trust(msg, VERIFY_USE_SECONDARY_KEYRING)) {
err = LSM_INT_VERDICT_PARTIALSIG;
goto out;
}
此验证确保签名是由受信任的证书颁发机构颁发的,防止伪造签名。
从签名中提取用户态添加的哈希数据:
c复制err = asn1_ber_decoder(&hornet_decoder, ctx, authattrs, authattrs_len);
这一过程使用ASN.1解码器解析签名中的扩展属性,获取用户态计算的哈希值。
最后,内核将提取的哈希与实际的map数据进行比对:
c复制err = hornet_verify_hashes(&maps, ctx);
验证函数会:
Hornet签名实现存在一个重要的安全限制——TOCTOU攻击风险。具体表现为:
BPF_PROG_LOAD阶段BPF_PROG_TEST_RUN阶段这种时间差可能导致验证通过的签名最终执行的是被篡改的代码。
当前实现通过以下方式缓解安全风险:
BPF_MAP_FREEZE使map变为只读然而,这些措施并不能完全消除TOCTOU风险,这是设计上的固有局限。
gen_sig工具的核心功能实现主要包括:
关键代码片段:
c复制set = MAP_SET_new();
set->maps = sk_HORNET_MAP_new_null();
for (i = 0; i < hash_count; i++) {
sha256(hashes[i].file, hash_buffer, &hash_len);
add_hash(set, hash_buffer, hash_len, i);
}
oid = OBJ_txt2obj("2.25.316487325684022475439036912669789383960", 1);
der_len = ASN1_item_i2d((ASN1_VALUE *)set, &der, ASN1_ITEM_rptr(MAP_SET));
CMS_signed_add1_attr_by_OBJ(si, oid, V_ASN1_SEQUENCE, der, der_len);
在内核验证侧,有几个性能优化点:
这些优化对于减少签名验证带来的性能开销至关重要。
在实际部署Hornet签名功能时,需要注意以下要点:
证书管理:
开发流程:
运行时监控:
Hornet签名与bpftool的签名功能(-S选项)在实现上有许多相似之处,但也存在关键差异:
| 特性 | Hornet签名 | bpftool签名 |
|---|---|---|
| 验证时机 | LSM钩子阶段 | 加载器执行阶段 |
| 目标对象 | 加载器指令 | 完整BPF程序 |
| TOCTOU防护 | 较弱 | 较强 |
| 集成复杂度 | 需要内核支持 | 用户空间实现 |
| 性能影响 | 较小 | 较大 |
选择方案时,应根据具体的安全需求和使用场景进行权衡。
基于当前实现的安全限制和性能考量,可能的改进方向包括:
增强TOCTOU防护:
性能优化:
功能扩展:
这些改进将使Hornet签名功能更加强大和灵活。
在实际部署Hornet签名功能时,我们总结了以下经验:
版本兼容性问题:
调试技巧:
dmesg查看内核验证日志bpftool prog show检查程序签名状态常见错误处理:
这些经验可以帮助开发者更快地排查和解决签名相关问题。