CodeQL C++ 静态分析:解析 allocation-too-small 与 suspicious-allocation-size 两条尺寸检查查询
静态分析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 查询套件的两条关键缺陷检测规则——cpp/allocation-too-small为指针类型分配的内存不足与cpp/suspicious-allocation-size为指针数组分配的内存不足——展开。你将了解这两条查询各自的判定逻辑、二者如何做到同一分配点不再重复告警以及其背后可模型化的分配函数体系AllocationFunction是如何扩展识别范围的。读完后你可以结合仓库中的源码与测试用例理解这两条 CWE-131/CWE-122 检查从建模到执行的完整机制并学会用同样的方式为自己的库函数建立分配模型。一、变更背景一次针对重叠告警与覆盖面的改进该改进对应仓库中的变更记录 size-check-queries.md原文包含两点cpp/allocation-too-smallNot enough memory allocated for pointer type与cpp/suspicious-allocation-sizeNot enough memory allocated for array of pointer type两条查询得到改进。此前同一处内存分配会同时被两条查询报告改进后不再发生两条查询现在能理解更多的分配函数more allocation functions are now understood by both queries。这两点分别对应报告去重与模型覆盖两个问题。下文结合仓库中的查询源码与模型库逐一给出实现层面的证据。二、查询一cpp/allocation-too-small 的判定逻辑查询源码位于 SizeCheck.ql其元数据声明了问题定位与严重度name Not enough memory allocated for pointer type description Calling malloc, calloc or realloc without allocating enough memory to contain an instance of the type of the pointer may result in a buffer overflow kind problem problem.severity warning security-severity 8.1 precision medium id cpp/allocation-too-small tags reliability security external/cwe/cwe-131 external/cwe/cwe-122其核心判定只有三条predicate baseType(AllocationExpr alloc, Type base) { exists(PointerType pointer | pointer.getBaseType() base and ( exists(AssignExpr assign | assign.getRValue() alloc and assign.getLValue().getType() pointer ) or exists(Variable v | v.getInitializer().getExpr() alloc and v.getType() pointer) ) ) } from AllocationExpr alloc, Type base, int basesize, int allocated where baseType(alloc, base) and allocated alloc.getSizeBytes() and decideOnSize(base, basesize) and alloc.(FunctionCall).getTarget() instanceof AllocationFunction and // exclude new and similar basesize allocated select alloc, Type base.getName() is basesize.toString() bytes, but only allocated.toString() bytes are allocated.可以拆出四个关键点类型关联baseType通过分配表达式的返回值被赋给或用于初始化某个指针变量这条路径把void *分配结果与它实际承载的类型base关联起来尺寸取最小值decideOnSize用min(t.getSize())处理同名类型可能有多尺寸的情况——如果同一名字在不同翻译单元/重载场景下存在多个尺寸用最小的作为比较基准避免漏报排除newalloc.(FunctionCall).getTarget() instanceof AllocationFunction只保留函数调用形态的分配malloc/calloc/realloc等因为new表达式由编译器保证分配尺寸正确无需检查报告条件basesize allocated即分配字节数小于目标类型大小直接提示X 需要 N 字节但只分配了 M 字节。三、查询二cpp/suspicious-allocation-size 的整数倍检查与去重条款第二条查询源码位于 SizeCheck2.ql元数据同样为security-severity 8.1、CWE-131/122但报告条件不同from AllocationExpr alloc, Type base, int basesize, int allocated where baseType(alloc, base) and allocated alloc.getSizeBytes() and decideOnSize(base, basesize) and alloc.(FunctionCall).getTarget() instanceof AllocationFunction and // exclude new and similar // If the codebase has more than one type with the same name, check if any matches not exists(int size | base.getSize() size | size 0 or (allocated / size) * size allocated ) and not basesize allocated and // covered by SizeCheck.ql not memberMayBeVarSize(base.getUnspecifiedType(), _) // exclude variable size types select alloc, Allocated memory ( allocated.toString() bytes) is not a multiple of the size of base.getName() ( basesize.toString() bytes).它的语义是分配字节数不是目标类型大小的整数倍(allocated / size) * size ! allocated同时容忍同名类型存在多个尺寸的情况只要有任何一个尺寸匹配即视为合法。其中一行正是变更记录中不再重复告警这一点的直接实现证据not basesize allocated and // covered by SizeCheck.ql这行注释点明了两条查询的分工basesize allocated分配量不足一个元素的情况归SizeCheck.ql报告SizeCheck2.ql通过not basesize allocated显式排除了这个区间只负责分配量 ≥ 一个元素但不是整数倍的数组型误分配。由此任意一个分配点至多只会命中两条查询中的一条从查询逻辑层面保证了同一分配不会收到两份告警。此外还有一个边界处理not memberMayBeVarSize(base.getUnspecifiedType(), _)排除了含可变长度成员如 C99 柔性数组的变长类型避免对尺寸本身不确定的类型误报。四、更多分配函数被理解背后的模型体系变更记录第二点——两条查询现在能理解更多分配函数——对应的是 CodeQL C 模型库中统一的分配模型两条查询都import semmle.code.cpp.models.Models并都以AllocationExpr/AllocationFunction为分析入口。该模型由接口层与实现层两部分组成。4.1 接口层可继承、可扩展的抽象interfaces/Allocation.qll 定义了四个核心抽象AllocationExpr一次分配表达式malloc调用、new表达式等提供getSizeBytes()固定字节数若可确定、getSizeExpr()getSizeMult()长度表达式与常量乘数、getAllocatedElementType()、requiresDealloc()等钩子AllocationFunction分配函数如malloc提供getSizeArg()尺寸参数下标、getSizeMult()乘数参数下标、getReallocPtrArg()realloc 的原指针参数等钩子HeuristicAllocationExpr/HeuristicAllocationFunction基于启发式函数名、参数形态识别可能的分配用于模型外的兜底extensible predicate allocationFunctionModel(...)外部可扩展模型谓词允许使用者按命名空间 类型 函数名追加自己的分配函数模型并指定尺寸参数、乘数参数、realloc 参数下标以及是否需要释放。4.2 实现层内建覆盖的分配函数清单implementations/Allocation.qll 展示了内建模型的覆盖面这正是更多分配函数被理解的落地位置realloc 家族ReallocAllocationFunctionrealloc(ptr, size)以及 Windows 传统 APILocalReAlloc/GlobalReAlloc/HeapReAlloc、COM 的CoTaskMemRealloc、OpenSSL 的CRYPTO_realloc、GLib 的g_realloc/g_try_realloc无尺寸参数的分配SizelessAllocationFunctionWindows 驱动内存管理中的ExAllocateFromLookasideListEx、MmMapLockedPages系列NetBSD 的pool_get等——它们没有显式尺寸参数因此不会进入尺寸比较new/new[]表达式NewAllocationExpr/NewArrayAllocationExpr直接由getAllocatedType().getSize()得出字节数尺寸天然正确外部模型AllocationFunctionFromModel把allocationFunctionModel谓词中的声明翻译为AllocationFunction子类启发式兜底HeuristicAllocationFunctionByName函数名匹配%alloc%或%Alloc%、返回指针类型、且存在唯一无符号整型参数视为尺寸参数名字匹配%realloc%且存在唯一指针参数时该指针参数被视为 realloc 输入。实现层还有两个对查询结果准确性很关键的细节realloc(ptr, 0)不算分配CallAllocationExprImpl的构造条件中显式排除realloc 目标且尺寸参数为 0的调用因为该调用语义上是释放而非分配sizeof表达式的拆解deconstructSizeExpr把malloc(a * 2 * sizeof(char32_t))这样的实参拆成长度表达式a * 2 乘数 4使getSizeBytes()能还原出真实字节数——这保证了用sizeof计算尺寸的合法写法不会因解析失败而漏报。五、测试用例用仓库中的测试验证行为边界两条查询的测试位于 SizeCheck 测试目录包含test.c、test2.c及对应的.expected期望输出测试文件头部注释说明其关联 CWE-131并约定每个查询只应报告标记为 BAD 的行。test.c覆盖cpp/allocation-too-small的典型场景void bad0(void) { float *fptr malloc(3); // $ Alert[cpp/allocation-too-small] // Too small double *dptr malloc(5); // $ Alert[cpp/allocation-too-small] // Too small } void bad1(void) { float *fptr malloc(sizeof(short)); // $ Alert[cpp/allocation-too-small] double *dptr malloc(sizeof(float)); // $ Alert[cpp/allocation-too-small] }而test2.c覆盖cpp/suspicious-allocation-size的整数倍场景long long *lptr malloc(27); // $ Alert[cpp/suspicious-allocation-size] double *dptr malloc(33); // $ Alert[cpp/suspicious-allocation-size] long long *lptr2 malloc(sizeof(long long)*7/2); // $ Alert[cpp/suspicious-allocation-size] float *fptr2 malloc(24); // GOOD -- An integral multiple期望输出SizeCheck.expected 与 SizeCheck2.expected给出了完整的告警文本例如Type float is 4 bytes, but only 3 bytes are allocated.来自SizeCheck.qlAllocated memory (27 bytes) is not a multiple of the size of long long (8 bytes).来自SizeCheck2.ql值得注意的是两个测试文件的 BAD 行互不重叠malloc(3)之于float只被SizeCheck.ql报告malloc(27)之于long long *只被SizeCheck2.ql报告——这正是不再重复告警这一改进在测试层面的体现。六、实践要点与局限综合查询源码与模型库使用这两条查询时可以把握以下几点适用前提分配结果必须通过赋值或变量初始化与某个具名指针类型关联查询才能把分配与类型对应起来分配尺寸必须是编译期可确定的固定值getSizeBytes()有解运行时动态尺寸不会触发报告new被排除new/new[]的尺寸由语言机制保证两条查询只针对malloc/calloc/realloc类函数调用同名类型取最小尺寸若同一类型名在代码库中尺寸不一致两条查询都以min(t.getSize())为基准宁可保守偏向报告变长类型被排除含 C99 可变长度成员的数组类型不参与整数倍检查扩展覆盖如果你使用的库有自己的分配 API如posix_memalign、g_malloc之类可以通过allocationFunctionModel谓词的外部扩展声明其尺寸参数与 realloc 参数使其纳入AllocationExpr体系也可以依赖实现层的启发式名字含alloc/Alloc、返回指针、唯一无符号整型参数自动覆盖一部分场景。七、小结这次 2020-10-21 的改进从结果上看只是不重复告警 识别更多分配函数两句话但在 SizeCheck2.ql 中一行not basesize allocated的去重条款、在 implementations/Allocation.qll 中分层的分配模型内建清单 外部可扩展谓词 启发式兜底中都有清晰的实现落点。这套查询声明分工、模型负责覆盖的结构也是 CodeQL C 查询套件处理类似可靠性/安全问题的典型范式查询本身保持简洁的类型-尺寸比较识别能力的扩展则集中在可继承、可外部扩展的模型层完成。赞分享静态分析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点击查看免费下载相关推荐Ant Design Steps 迷你尺寸步骤条sizesmall 使用与实现原理全解析Ant Design Steps 迷你尺寸步骤条 sizesmall 使用与实现原理全解析 Steps sizesmall 是 Ant Desi前端UI组件设计系统Win11Debloat终极指南三步实现Windows系统极致优化与深度清理 Win11Debloat终极指南三步实现Windows系统极致优化与深度清理 Win11Debloat 是一个强大而简单的PowerShell脚本工具静态分析SAST应用安全漏洞扫描代码质量Structured3D完整指南如何用3D结构化数据轻松构建智能室内场景Structured3D完整指南如何用3D结构化数据轻松构建智能室内场景 如果你正在寻找一个能够将室内设计从平面图转化为智能3D模型的强大工具那么Struc静态分析SAST应用安全漏洞扫描代码质量上一篇html-anything 社区/配对数据墙模板解析dating-web Skill 的布局设计、frontmatter 约定与加载机制下一篇Facebook的PyRE2: 高性能正则表达式处理库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考