본 글에서는 codeql에서 제공하는 기본 CodeQL 쿼리 파일이 아닌 우리가 직접 CodeQL 쿼리 파일을 작성해보고 실행시키는 방법을 서술하려 한다. Python을 기준으로 작성되었으나 Non-compiled 언어라면 어떤 언어든 가능하다. 언제쯤 MSBuild를 사용한 C++ CodeQL DB 구축에 성공할 지 모르겠다..
#환경
현재 시스템에 세팅된 CodeQL 설정은 아래와 같다.
- Working Dir: ~\Documents\CodeQL
- CodeQL CLI: ~\Documents\CodeQL\codeql-cli (version 2.6.0)
- CodeQL Lib: ~\Documents\CodeQL\codeql-repo (https://github.com/github/codeql)
#테스트용 Python 소스 코드
Python 코드는 ~\Documents\CodeQL\CodeQLPythonTest 폴더에 저장된다. 각 .py 파일 코드는 아래와 같다.
- main.py
# main.py
from CodeQLTest import CodeQLTest
def sum(a: int, b: int) -> int:
return a + b
c = CodeQLTest('CodeQL')
c.printMsg()
c.showMsg()
sum(1, 2)
- CodeQLTest.py
# CodeQLTest.py
class CodeQLTest:
def __init__(self, msg: str):
self.msg = msg
def printMsg(self):
print(self.msg)
def showMsg(self):
from tkinter import messagebox
messagebox.showinfo(title="CodeQLTest", message=self.msg)
#CodeQL Database 만들기
Python 소스 코드 작성이 끝나면 Python CodeQL Database를 생성한다.
> codeql database create codeql-db\CodeQLPythonTest`
--language=python `
--source-root=.\CodeQLPythonTest
Successfully created database at <Database path>라고 나타나면 데이터베이스가 잘 만들어진 것이다.
#CodeQL 쿼리 작성하기
codeql-repo는 기본적으로 제공하는 CodeQL 쿼리 파일 외에도 여러 라이브러리 파일들이 들어있다. 예제 코드에서 "import python" 등이 codeql-repo가 제공하는 CodeQL 라이브러리다. 하지만 이를 사용하기 위해서는 이 라이브러리와 같은 경로에 있어야 한다.
- CodeQL Python 라이브러리 경로: ~\Documents\CodeQL\codeql-repo\python\ql\src
어느 언어든 CodeQL이 지원하는 언어라면 모두 저 경로에 라이브러리 파일들이 존재한다. 중간에 python만 원하는 언어로 바꾸면 된다. cpp, java, javascript 등.
위 경로에 findSumFunc.ql을 만들고 아래와 같이 작성한다.
- findSumFunc.ql 경로: ~\Documents\CodeQL\codeql-repo\python\ql\src\findSumFunc.ql
/**
* @kind problem
* @id py/findSumFunc
* @name findSumFunc
* @description none
* @problem.severity warning
* @precision high
*/
import python
from Function f
where
f.getName() = "sum"
select f, "FIND!!!"
위 형태가 .ql 파일의 가장 기본적인 형태라고 보면 된다. /**/로 감싸진 영역은 주석이지만 동시에 CodeQL 쿼리 메타데이터를 담고 있기도 하다. 메타데이터에 대한 자세한 설명은 여기를 참고하면 된다.
위 .ql 파일은 sum이라는 이름의 함수를 찾아 Alert 하기 위한 쿼리다. @kind의 problem은 Alert Query를 의미한다. @id는 쿼리 파일을 Classifying하기 위한 문자열 값이며, @name은 쿼리를 구별하는 Label이다. @kind와 @id는 반드시 필요한 메타데이터다. 둘 중 하나라도 없으면 쿼리 파일은 실행되지 않는다. @name과 @description은 쿼리 결과 파일에 나타나지만 없으면 빈 문자열로 나타나기 때문에 쿼리 실행에 영향을 주진 않는다.
클래스를 찾는 쿼리는 아래와 같이 작성하면 된다.
- findCodeQLTestClass.ql 경로: ~\Documents\CodeQL\codeql-repo\python\ql\src\findCodeQLTestClass.ql
/**
* @kind problem
* @id py/findCodeQLTestClass
* @name findCodeQLTestClass
* @description none
* @problem.severity warning
* @precision high
*/
import python
from Class c
where
c.getQualifiedName() = "CodeQLTest"
select c, "FIND!!!"
#CodeQL 쿼리 실행하기
이제 실행해보자. 먼저 findSumFunc.ql 쿼리를 실행하는 방법은 아래와 같다.
> codeql database analyze .\codeql-db\CodeQLPythonTest\ `
.\codeql-repo\python\ql\src\findSumFunc.ql `
--format=csv `
--output=findSumFunction.csv
codeql-repo\python\ql\src\findSumFunc.ql를 실행시키고 그 결과를 csv 형식으로 findSumFunction.csv에 저장하라는 의미다. 위 쿼리를 실행하면 별다른 에러메시지 없이 codeql이 종료되고, findSumFunction.csv가 생성된다.
findSumFunction.csv 결과를 보면 main.py의 3번째 줄에 sum 함수가 정의되어 있다는 걸 알 수 있다.
다음으로 findCodeQLTestClass.ql을 실행해보자.
> codeql database analyze .\codeql-db\CodeQLPythonTest\ `
.\codeql-repo\python\ql\src\findCodeQLTestClass.ql `
--format=csv `
--output=findCodeQLTestClass.csv
findCodeQLTestClass.ql을 실행하면 findCodeQLTestClass.csv가 생성된다. 결과를 해석해보면 CodeQLTest.py 파일의 2번째 줄에 CodeQLTest 클래스가 정의되어 있다는 걸 알 수 있다.
#결론
이상으로 CodeQL CLI 구성부터 .ql 쿼리 파일 실행 방법, 그리고 .ql 쿼리 파일 작성 방법까지 알아봤다. 다음 포스팅부턴 CodeQL 쿼리문을 응용하는 데에 집중해보려 한다.
'CodeQL' 카테고리의 다른 글
#2 CodeQL - CodeQL CLI 구성 (0) | 2021.07.28 |
---|---|
#3 CodeQL - 기본 제공 Javascript QL 사용하기 (0) | 2021.06.22 |
#1 CodeQL - Hello, CodeQL (0) | 2021.06.12 |