From 8d3bc23687d3cb6a19ce8fe5acddf94f8bd67bc2 Mon Sep 17 00:00:00 2001 From: RenFengJiang <1111> Date: Fri, 19 Jan 2024 18:08:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9AC++=E5=9C=A8?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E5=8A=A0=E8=BD=BD=E5=BA=93=E5=89=8D=E5=AF=B9?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=95=B0=E6=8D=AE=E8=BF=9B=E8=A1=8C=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cxx/rules/checkers/DLLVerifyChecker.java | 157 ++++++++++++++++++ .../rules/checkers/DLLVerifyCheckerTest.java | 35 ++++ .../cxx/rules/checkers/DLLVerifyChecker.cc | 57 +++++++ 3 files changed, 249 insertions(+) create mode 100644 sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java create mode 100644 sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java create mode 100644 sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc diff --git a/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java new file mode 100644 index 0000000..add7916 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/main/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.sonar.cxx.sslr.api.AstNode; +import com.sonar.cxx.sslr.api.Grammar; +import org.sonar.check.Priority; +import org.sonar.check.Rule; +import org.sonar.cxx.parser.CxxGrammarImpl; +import org.sonar.cxx.squidbridge.annotations.ActivatedByDefault; +import org.sonar.cxx.squidbridge.annotations.SqaleConstantRemediation; +import org.sonar.cxx.squidbridge.checks.SquidCheck; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * TODO DLLVerifyChecker + * + * @author RenFengJiang + * @date 2024/1/19 + */ +@Rule(key = "DLLVerifyChecker", name = "在动态加载库前对输入数据进行验证", description = "检测代码调用动态库时,判断为动态库传参的类型与动态库要求是否一致", priority = Priority.INFO, tags = {"28suo"}) +@ActivatedByDefault +@SqaleConstantRemediation("5min") +public class DLLVerifyChecker extends SquidCheck { + + private static String name = "在动态加载库前对输入数据进行验证"; + @Override + public void init() { + // 指定当前访问器需要访问的节点类型,functionBody(函数)主体节点 + this.subscribeTo( + CxxGrammarImpl.functionBody + ); + } + + /** + * 访问AST节点 + * + * @param node 要处理的AST节点,该节点类型为通过subscribeTo方法订阅的类型 + */ + @Override + public void visitNode(@Nonnull AstNode node) { + Map map = ifParam(node); + List simps = node.getDescendants(CxxGrammarImpl.simpleDeclaration); + for(AstNode simp :simps){ + //判断动态加载库类型 + if("HINSTANCE".equals(simp.getTokenValue())){ + loadParam(map,simp); + }else if ("void".equals(simp.getTokenValue())){ + openParam(map,simp); + } + } + } + + //判断是否是dlopen格式的动态加载库 + public void openParam(Map map,AstNode simp){ + //获取方法名 + List descendants = simp.getDescendants(CxxGrammarImpl.postfixExpression); + if(descendants != null){ + for(AstNode desc : descendants){ + //判断是否式动态加载库 + if("dlopen".equals(desc.getTokenValue())){ + //获取其中的参数列表 + AstNode firstDescendant = desc.getFirstDescendant(CxxGrammarImpl.additiveExpression); + if(firstDescendant != null){ + List children = firstDescendant.getChildren(); + for(AstNode dren : children){ + //获取参数并进行判断是否是传入的参数 + if("IDENTIFIER".equals(dren.getName())){ + if(map.containsKey(dren.getTokenValue())){ + //判断参数是否进行过校验 + Integer integer = map.get(dren.getTokenValue()); + //判断参数校验是否在使用之前 + if(dren.getTokenLine() > integer){ + getContext().createLineViolation(this,name,dren); + } + }else { + getContext().createLineViolation(this,name,dren); + } + } + } + }else { + getContext().createLineViolation(this,name,desc); + } + } + } + } + } + + //对LoadLibrary格式的动态加载库进行校验 + public void loadParam(Map map,AstNode simp){ + //获取方法名 + AstNode firstDescendant = simp.getFirstDescendant(CxxGrammarImpl.postfixExpression); + if(firstDescendant != null){ + if("LoadLibrary".equals(firstDescendant.getTokenValue())){ + //获取其中的参数列表 + List descendants = firstDescendant.getDescendants(CxxGrammarImpl.expressionList); + if(descendants != null){ + for (AstNode desc : descendants){ + //判断参数是否进行过校验 + if (map.containsKey(desc.getTokenValue())){ + //判断参数校验是否在使用之前 + int tokenLine = map.get(desc.getTokenValue()); + if(desc.getTokenLine() > tokenLine){ + getContext().createLineViolation(this,name,desc); + break; + } + }else { + getContext().createLineViolation(this,name,desc); + break; + } + } + }else { + getContext().createLineViolation(this,name,firstDescendant); + } + } + } + } + + //获取if判断中的参数 + public static Map ifParam(AstNode node){ + Map map = new HashMap<>(); + //选择节点语句 + List nodeDescendants = node.getDescendants(CxxGrammarImpl.selectionStatement); + for (AstNode astNode:nodeDescendants) { + //判断节点是不是if节点 + if("if".equals(astNode.getToken().getValue())){ + //获取其中的参数 + List astNodeList = astNode.getDescendants(CxxGrammarImpl.expressionList); + astNodeList.addAll(astNode.getDescendants(CxxGrammarImpl.condition)); + for (AstNode expr:astNodeList) { + map.put(expr.getTokenValue(),expr.getTokenLine()); + } + //判断第二种情况获取到if里面的参数 + if(astNodeList.size() == 0){ + List astNodes = astNode.getDescendants(CxxGrammarImpl.relationalExpression); + for (AstNode as:astNodes) { + List children = as.getChildren(); + for (AstNode chil:children) { + map.put(chil.getTokenValue(),chil.getTokenLine()); + } + } + } + } + } + return map; + } + +} diff --git a/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java new file mode 100644 index 0000000..74388d6 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/java/com/keyware/sonar/cxx/rules/checkers/DLLVerifyCheckerTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 - 2024. KeyWare.Co.Ltd All rights reserved. + * 项目名称:信息安全性设计准则检查插件 + * 项目描述:用于检查源代码的安全性设计准则的Sonarqube插件 + * 版权说明:本软件属北京关键科技股份有限公司所有,在未获得北京关键科技股份有限公司正式授权情况下,任何企业和个人,不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。 + */ + +package com.keyware.sonar.cxx.rules.checkers; + +import com.keyware.sonar.cxx.CxxFileTesterHelper; +import org.junit.jupiter.api.Test; +import org.sonar.cxx.CxxAstScanner; +import org.sonar.cxx.squidbridge.api.SourceFile; +import org.sonar.cxx.squidbridge.checks.CheckMessagesVerifier; + +import java.io.IOException; + +/** + * TODO DLLVerifyCheckerTest + * + * @author RenFengJiang + * @date 2024/1/19 + */ +public class DLLVerifyCheckerTest { + @Test + public void checkTest() throws IOException { + var checker = new DLLVerifyChecker(); + var tester = CxxFileTesterHelper.create("DLLVerifyChecker.cc"); + SourceFile file = CxxAstScanner.scanSingleInputFile(tester.asInputFile(), checker); + CheckMessagesVerifier.verify(file.getCheckMessages()) + .next().atLine(13).withMessage("在动态加载库前对输入数据进行验证") + .next().atLine(36).withMessage("在动态加载库前对输入数据进行验证") + .noMore(); + } +} diff --git a/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc new file mode 100644 index 0000000..8676653 --- /dev/null +++ b/sonar-keyware-plugins-cxx/src/test/resources/com/keyware/sonar/cxx/rules/checkers/DLLVerifyChecker.cc @@ -0,0 +1,57 @@ +#include +#ifdef _WIN32 + #include +#else + #include +#endif +int main() +{ + + std::String a = "your_dll.dll"; + if(a != "a"){ + } + HINSTANCE hInsts = LoadLibrary(a);//error + //加载dll +// HINSTANCE hInst = LoadLibrary("your_dll.dll"); + if (hInst == NULL) { + std::cout << "无法加载库" << std::endl; + return -1; + } + //获取函数 + typedef void (*FuncType)(); + FuncType func = (FuncType)GetProcAddress(hInst, "函数名称"); + if (func == NULL) { + std::cout << "无法获取函数" << std::endl; + return -1; + } + //调用函数 + func(); + //卸载dll + FreeLibrary(hInst); + + std::String b = "c"; + //加载so库 + if(b != "a"){ + } + void *handle = dlopen(b, RTLD_LAZY);//error + if (!handle) { + std::cerr << "无法打开库:" << dlerror() << '\n'; + return 1; + } + //获取函数 + typedef void (*FuncType)(); + dlerror(); + FuncType func = (FuncType)dlsym(handle, "函数名称"); + const char *dlsym_error = dlerror(); + if (dlsym_error) { + std::cerr << "无法加载符号 '函数名称':" << dlsym_error << '\n'; + dlclose(handle); + return 1; + } + //调用函数 + func(); + //关闭库文件 + dlclose(handle); +#endif + return 0; +} \ No newline at end of file