CodeQL

#4 CodeQL - 쿼리 파일 작성해서 실행하기

geunyeong 2021. 9. 8. 22:34

본 글에서는 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