ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

CodeQL C 提取器:函数指针类型的 IL 提取与 cil_type_annotation 修复解析

CodeQL C 提取器:函数指针类型的 IL 提取与 cil_type_annotation 修复解析 静态分析SAST应用安全漏洞扫描代码质量【免费下载链接】codeqlCodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security项目地址https://gitcode.com/gh_mirrors/co/codeql点击查看免费下载本文以 CodeQL 仓库中 2021-01-25-Function-pointer-cil.md 这条变更记录为主线深入解析 C# 提取器如何从 IL程序集元数据中提取 C# 9 函数指针类型FunctionPointerType以及pinned、by-reference类型注解cil_type_annotation提取修复的实现原理。读完本文你将理解 CodeQL 如何在 TRAP 数据层面表达函数指针、其调用约定如何编码、QL 侧提供了哪些查询 API以及这条变更记录在 dbscheme 演进中的位置。一、变更记录原文解读这条发布于 2021-01-25 的变更记录面向lgtm, codescanning两个平台正文极短只有两项内容函数指针类型FunctionPointerType从 IL 中提取pinned与by-reference类型注解cil_type_annotation的提取得到修复。紧邻的前一条变更记录 2021-01-19-Function-pointer.md 宣布了函数指针类型FunctionPointerType和函数指针调用FunctionPointerCall被提取两者合起来勾勒出 CodeQL 对 C# 9 函数指针特性的完整支持链路先支持从源码Roslyn 语法树提取再补齐从 IL编译产物元数据提取的能力。“从 IL 提取”的含义需要明确CodeQL 的 C# 提取器不仅要处理有源码的工程还要处理通过 NuGet 等途径引入的、只有编译产物的依赖程序集。这条变更记录意味着即便函数指针类型只出现在已编译的程序集元数据中源码不可见提取器也能正确地为其生成 TRAP 数据从而让查询可以跨源码与依赖库进行统一分析。二、C# 9 函数指针语法与 IL 背景C# 9 引入了delegate*语法允许直接使用函数指针而不经过委托对象的堆分配。典型写法delegate*int, void p; // 函数指针类型 delegate* unmanaged[Cdecl]int, int q; // 带非托管调用约定的函数指针在编译后的 IL/CLI 元数据中这类类型对应ELEMENT_TYPE_FNPTR修饰符其签名携带返回类型、参数类型以及调用约定calling convention。CodeQL 提取器要做的就是把这种 IL 层面的类型结构忠实地还原为 TRAP 表中的实体供 QL 查询使用。三、提取器实现FunctionPointerType 实体类函数指针类型的提取实体位于 csharp/extractor/Semmle.Extraction.CSharp/Entities/Types/FunctionPointerType.cs它继承自泛型基类TypeIFunctionPointerTypeSymbol直接以 Roslyn 的符号接口IFunctionPointerTypeSymbol为输入。该文件揭示了三个关键实现细节1. TRAP ID 的生成WriteIdpublic override void WriteId(EscapingTextWriter trapFile) { Symbol.BuildTypeId(Context, trapFile, Symbol, constructUnderlyingTupleType: false); trapFile.Write(;functionpointertype); }函数指针类型的 ID 由类型符号自身的类型 ID 加上固定后缀;functionpointertype构成保证与普通委托类型区分。BuildTypeId方法定义于 csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs其中对TypeKind.FunctionPointer分支的处理SymbolExtensions.cs#L128-L134表明函数指针的 ID 依赖其参数类型与返回类型的 ID——只要某个参数或返回类型发生变化函数指针的 ID 就随之变化这保证了 TRAP 数据的引用完整性。2. 调用约定的编码PopulatetrapFile.function_pointer_calling_conventions(this, (int)Symbol.Signature.CallingConvention); foreach (var (conv, i) in Symbol.Signature.UnmanagedCallingConventionTypes.Select((nt, i) (Create(Context, nt), i))) { trapFile.has_unmanaged_calling_conventions(this, i, conv.TypeRef); }调用约定被编码为整数写入function_pointer_calling_conventions表如果声明了unmanaged调用约定如Cdecl、Stdcall、Thiscall、Fastcall等则每个约定类型按索引写入has_unmanaged_calling_conventions表。QL 侧通过CallingConvention类族csharp/ql/lib/semmle/code/csharp/Type.qll 中的UnmanagedCallingConvention等将这些整数解码为可读的约定名称。3. 实体工厂模式文件末尾的FunctionPointerTypeFactory采用CachedEntityFactory缓存工厂模式创建实体避免同一符号被重复提取成多个 TRAP 实体。四、dbscheme 层面的数据模型函数指针相关结构在 csharp/ql/lib/semmlecode.csharp.dbscheme 中有完整定义类型分类| 33 function_pointer_type第 493 行将函数指针类型纳入统一的类型标识体系返回类型表function_pointer_return_type(function_pointer_type ref, ...)第 541 行起调用约定表function_pointer_calling_conventions(int id: function_pointer_type ref, ...)与has_unmanaged_calling_conventions(...)第 690、696 行起可参数化类型parameterizable callable | delegate_type | indexer | function_pointer_type | extension_type第 911 行意味着函数指针可以像委托一样承载参数列表getParameter(i)调用表达式| 129 function_pointer_invocation_expr第 1189 行与local_function_invocation_expr等并列用于表示对函数指针的间接调用类型注解宿主has_type_annotation assignable | type_parameter | callable | expr | delegate_type | generic | function_pointer_type第 604 行函数指针类型被纳入可携带类型注解如可空性注解的实体集合。五、QL 查询 APIFunctionPointerType 与 FunctionPointerCallQL 库侧FunctionPointerType类定义于 csharp/ql/lib/semmle/code/csharp/Type.qll继承Type与Parameterizable文档注释示例为delegate*int, void。它暴露了以下查询谓词谓词作用getReturnType()获取函数指针的返回类型getCallingConvention()获取调用约定解码为CallingConventiongetUnmanagedCallingConvention(int i)/getAnUnmanagedCallingConvention()获取第i个/任意非托管调用约定类型getAnnotatedReturnType()获取带注解可空性等的返回类型此外对函数指针的调用通过FunctionPointerCall建模FunctionPointerInvocationExpr在 csharp/ql/lib/semmle/code/csharp/Expr.qll或相邻库模块中与局部函数调用等并列配合 csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs 中的提取逻辑使用。六、测试用例验证仓库提供了针对性的库测试 csharp/ql/test/library-tests/csharp9/FunctionPointer.ql包含五个查询谓词覆盖了本节提到的全部核心 APIquery predicate type(FunctionPointerType fpt, string returnType, string callingConvention) { fpt.getAnnotatedReturnType().toString() returnType and fpt.getCallingConvention().toString() callingConvention } query predicate unmanagedCallingConvention(FunctionPointerType fpt, int i, string callingConvention) { fpt.getUnmanagedCallingConvention(i).toString() callingConvention } query predicate parameter(FunctionPointerType fpt, int i, Parameter p, string t) { fpt.getParameter(i) p and p.getAnnotatedType().toString() t } query predicate invocation(FunctionPointerCall fpc) { any() } query predicate casts(ImplicitCast cast, FunctionPointerType fromType, FunctionPointerType toType) { cast.getSourceType() fromType and cast.getTargetType() toType }这套测试印证了函数指针类型的返回类型、调用约定、非托管调用约定、参数列表、间接调用表达式以及隐式转换如方法组到函数指针的转换都能被正确提取和查询。测试位于csharp9目录下与 C# 9 语言版本对应。七、cil_type_annotation 修复pinned 与 by-reference变更记录的第二项内容是“修复pinned与by-reference的cil_type_annotation类型提取”。cil_type_annotation是早期 dbscheme 中用于记录 IL 类型注解修饰符的表在 csharp/ql/lib/upgrades/ 目录下多个历史版本的 dbscheme 中仍能看到它的痕迹当前版本的 dbscheme 中该表已演进为通用的type_annotation(int id: has_type_annotation ref, int annotation: int ref)csharp/ql/lib/semmlecode.csharp.dbscheme。从 IL 语义看pinned是 IL 中的ELEMENT_TYPE_PINNED修饰符用于fixed语句固定托管对象的指针场景by-reference对应ELEMENT_TYPE_BYREF即按引用传递的ref/out/in参数修饰。这两类注解此前在从 IL程序集元数据提取类型时存在缺失或错误修复后得以与源码提取保持一致。提取端生成注解的代码可见于 csharp/extractor/Semmle.Extraction.CSharp/Entities/Base/Entity.cs实体根据符号特性向 TRAP 写入type_annotation(this, Kinds.TypeAnnotation.Out / Ref / ReadonlyRef)等注解LocalVariable.cs 与 Method.cs 也分别对局部变量与方法参数写入Ref/ReadonlyRef注解。QL 侧的消费逻辑集中在 csharp/ql/lib/semmle/code/csharp/AnnotatedType.qllelementTypeAnnotations谓词第 224-245 行统一了可赋值元素、可调用元素、表达式、委托类型与函数指针类型的注解解析getElementTypeFlags将各注解位累加为位掩码供可空性与ref语义分析使用。八、dbscheme 演进与升级降级路径函数指针特性引入 dbscheme 后配套的数据库升级upgrade与降级downgrade脚本同步更新。仓库在 csharp/downgrades/ 与 csharp/ql/lib/upgrades/ 中保留了多个历史 dbscheme 快照例如19b8cc3e...、66044cfa...等目录下的升级脚本其中old.dbscheme与semmlecode.csharp.dbscheme的对照体现了function_pointer_type、cil_type_annotation等表随版本迭代的变迁。这意味着既有的 CodeQL 数据库旧 schema在升级到包含函数指针支持的新版本后能够自动完成数据迁移历史分析结果不会因 schema 变更而失效。九、总结从变更记录看2021-01-25 的这条记录补齐了函数指针类型在 IL依赖程序集元数据层面的提取并修复了pinned/by-reference类型注解的提取从实现看FunctionPointerType.cs 以IFunctionPointerTypeSymbol为输入将调用约定与返回类型写入 TRAPdbscheme 提供了function_pointer_type、function_pointer_calling_conventions、function_pointer_invocation_expr等表结构从查询侧看Type.qll 的FunctionPointerType类与FunctionPointerCall共同构成对函数指针声明、调用与转换的完整建模从验证看FunctionPointer.ql 覆盖了返回类型、调用约定、非托管约定、参数与调用表达式五类场景从注解修复看cil_type_annotation演进为type_annotation表AnnotatedType.qll 统一解析源码与 IL 两路的类型注解使pinned、by-reference语义在查询中保持一致。对于编写安全查询的开发者这意味着针对delegate*函数指针的调用点追踪如污点分析中的间接调用展开、调用约定相关的平台差异检测以及fixed指针与ref参数的注解分析在 CodeQL 的 C# 库中均有完整的数据与 API 支撑无需自行解析 IL。赞分享静态分析SAST应用安全漏洞扫描代码质量【免费下载链接】codeqlCodeQL: the libraries and queries that power security researchers around the world, as well as code scanning in GitHub Advanced Security项目地址https://gitcode.com/gh_mirrors/co/codeql点击查看免费下载相关推荐CodeQL C 提取器对函数指针的支持FunctionPointerType 与 FunctionPointerCall 的实现与查询实战CodeQL C 提取器对函数指针的支持 FunctionPointerType 与 FunctionPointerCall 的实现与查询实战 导读 C 9.静态分析SAST应用安全漏洞扫描代码质量CodeQL C 提取器对隐式基类构造函数调用的建模与实现解析CodeQL C 提取器对隐式基类构造函数调用的建模与实现解析 本文围绕 CodeQL 仓库中 C 提取器的一项具体能力展开将 C 构造函数中 隐式的基类构造静态分析SAST应用安全漏洞扫描代码质量CodeQL C 提取器修复隐式尺寸多维数组长度的逐维推断CodeQL C 提取器修复隐式尺寸多维数组长度的逐维推断 本文基于 csharp/old change notes/2020 08 26 implicit静态分析SAST应用安全漏洞扫描代码质量上一篇SpacetimeDB Views 完全指南只读视图函数、订阅与性能调优下一篇使用 Semantic Kernel Python 在 Azure AI Studio 上跑通 MMLU 多模型基准评测创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表