
리눅스 커널 드라이버용 퍼저
이 저장소에는 difuze를 실행하는 데 필요한 모든 소스(셋업 스크립트 포함)가 포함되어 있습니다.
Ubuntu >= 14.04.5 LTS
readme를 참조하세요.
우리의 논문에서 설명한 대로, difuze에는 인터페이스 복구와 퍼징 엔진의 두 가지 주요 구성 요소가 있습니다.
인터페이스 복구 메커니즘은 LLVM 분석 패스(pass)를 기반으로 합니다. 인터페이스 복구의 각 단계는 개별 패스로 작성되어 있습니다. 인터페이스 복구를 실행하는 방법은 아래 지침을 따르세요.
이 단계에서는 LLVM과 c2xml을 설치합니다.
sudo apt-get install libxml2-dev
sudo pip install lxml
다음으로, 필요한 모든 도구를 다운로드하고 빌드하는 단일 스크립트를 만들었습니다.
cd helper_scripts
python setup_difuze.py --help
usage: setup_difuze.py [-h] [-b TARGET_BRANCH] [-o OUTPUT_FOLDER]
optional arguments:
-h, --help show this help message and exit
-b TARGET_BRANCH Branch (i.e. version) of the LLVM to setup. Default:
release_38 e.g., release_38
-o OUTPUT_FOLDER Folder where everything needs to be setup.
예시:
python setup_difuze.py -o difuze_deps
설정을 완료하려면 로컬 PATH 환경 변수도 수정해야 합니다. 설정 스크립트가 필요한 정확한 변경 사항을 알려줍니다.
이 단계는 설정이 성공적으로 완료되어야 합니다. 모든 것을 빌드하는 단일 스크립트가 있습니다. 마음껏 사용하세요.
cd InterfaceHandlers
./build.sh
이 단계는 빌드가 성공적으로 완료되어야 합니다. 커널 드라이버에서 인터페이스 복구 구성 요소를 실행하려면 먼저 드라이버를 llvm 비트코드로 변환해야 합니다.
먼저 빌드 가능한 커널이 필요합니다. 즉, 일반적인 빌드 설정을 사용하여 커널을 컴파일할 수 있어야 합니다. 예: make.
먼저 make 명령의 출력을 캡처하고, 이 출력에서 정확한 컴파일 명령을 추출합니다.
make 출력 생성bear make <all the options to make>
예시: bear make -j8이렇게 하면 현재 디렉터리에 compile_commands.json 파일이 생성됩니다.
V=1을 전달하고 출력을 파일로 리다이렉트하면 됩니다.
예시:
make V=1 O=out ARCH=arm64 > makeout.txt 2>&1
참고: 다중 프로세스를 사용하지 마세요 즉, -j를 사용하지 마세요. 다중 처리 모드로 실행하면 여러 프로세스가 출력 파일에 쓰려고 시도하므로 출력 파일이 손상됩니다.
이상입니다. 다음 단계에서 우리 스크립트는 생성된 makeout.txt를 가져와 인식된 모든 드라이버에 대해 인터페이스 복구를 실행합니다.
인터페이스 복구의 모든 다양한 단계는 단일 스크립트 helper_scripts/run_all.py로 묶여 있습니다.
실행 방법:
cd helper_scripts
python run_all.py --help
usage: run_all.py [-h] [-l LLVM_BC_OUT] [-a CHIPSET_NUM] [-m MAKEOUT]
[-c COMPJSON] [-g COMPILER_NAME] [-n ARCH_NUM] [-o OUT]
[-k KERNEL_SRC_DIR] [-isclang] [-clangp CLANG_PATH]
[-llvmlinkp LLVMLINK_PATH] [-skb] [-skl] [-skp] [-skP]
[-ske] [-skI] [-ski] [-skv] [-skd] [-f IOCTL_FINDER_OUT]
optional arguments:
-h, --help show this help message and exit
-l LLVM_BC_OUT Destination directory where all the generated bitcode
files should be stored.
-a CHIPSET_NUM Chipset number. Valid chipset numbers are:
1(mediatek)|2(qualcomm)|3(huawei)|4(samsung)
-m MAKEOUT Path to the makeout.txt file.
-c COMPJSON Path to the compile_commands_json generated by Bear.
-g COMPILER_NAME Name of the compiler used in the makeout.txt, This is
needed to filter out compilation commands. Ex: aarch64
-linux-android-gcc
-n ARCH_NUM Destination architecture, 32 bit (1) or 64 bit (2).
-o OUT Path to the out folder. This is the folder, which
could be used as output directory during compiling
some kernels.
-k KERNEL_SRC_DIR Base directory of the kernel sources.
-isclang flag to indicate that clang was used to built the
kernel
-clangp CLANG_PATH Absolute path to the clang binary (if not provided,
the one available in the path will be used)
-llvmlinkp LLVMLINK_PATH
Absolute path to the llvm-link binary (if not
provided, the one available in the path will be used)
-skb Skip LLVM Build (default: not skipped).
-skl Skip Dr Linker (default: not skipped).
-skp Skip Parsing Headers (default: not skipped).
-skP Skip Generating Preprocessed files (default: not
skipped).
-ske Skip Entry point identification (default: not
skipped).
-skI Skip Generate Includes (default: not skipped).
-ski Skip IoctlCmdParser run (default: not skipped).
-skv Skip V4L2 ioctl processing (default: not skipped).
-skd Skip Device name finder (default: not skipped).
-f IOCTL_FINDER_OUT Path to the output folder where the ioctl command
finder output should be stored.
이 스크립트는 인식된 모든 드라이버에 대해 인터페이스 복구를 빌드, 링크 및 실행하므로 상당한 시간(45분~90분) 이 걸릴 수 있습니다.
위 스크립트는 모든 CPU 코어를 활용하기 위해 다중 프로세서 모드로 다음 작업을 수행합니다:
생성된 모든 비트코드 파일은 -l 인수로 제공된 폴더에 저장됩니다.
이 단계는 사용 가능한 코어 수에 따라 상당한 시간이 걸립니다. 이미 이 단계를 수행했다면 -skb를 전달하여 이 단계를 건너뛸 수 있습니다.
이 작업은 링크를 수행하며, 모든 비트코드 파일을 검토하여 링크해야 할 관련 비트코드 파일을 식별하고 이를 (llvm-link를 사용하여) 통합 비트코드 파일로 링크합니다(해당 비트코드 파일 옆에 저장됩니다).
위 단계와 유사하게 -skl을 전달하여 이 단계를 건너뛸 수 있습니다.
이 단계는 헤더 파일에서 엔트리 포인트 선언을 찾아 해당 구성을 LLVM 빌드 디렉터리 아래의 hdr_file_config.txt 파일에 저장합니다.
건너뛰려면: -skp
이 단계는 모든 드라이버 통합 비트코드 파일에서 모든 엔트리 포인트를 식별합니다. 출력은 LLVM 빌드 디렉터리 아래의 entry_point_out.txt 파일에 저장됩니다.
entry_point_out.txt 파일 내용의 예:
IOCTL:msm_lsm_ioctl:/home/difuze/kernels/pixel/msm/sound/soc/msm/qdsp6v2/msm-lsm-client.c:msm_lsm_ioctl.txt:/home/difuze/pixel/llvm_out/sound/soc/msm/qdsp6v2/llvm_link_final/final_to_check.bc
IOCTL:msm_pcm_ioctl:/home/difuze/kernels/pixel/msm/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c:msm_pcm_ioctl.txt:/home/difuze/pixel/llvm_out/sound/soc/msm/qdsp6v2/llvm_link_final/final_to_check.bc
건너뛰려면: -ske
이 단계는 entry_point_out.txt 파일의 모든 엔트리 포인트에 대해 주요 인터페이스 복구 구성 요소(IoctlCmdParser)를 실행합니다. 각 엔트리 포인트의 출력은 -f 옵션으로 제공된 폴더에 저장됩니다.
건너뛰려면: -ski
이제 커널 소스가 있는 시점부터 인터페이스 복구 결과를 얻는 시점까지의 예시를 보여드리겠습니다.
mediatek 커널 33.2.A.3.123.tar.bz2을 업로드했습니다. 먼저 위 파일을 다운로드하고 압축을 풉니다.
위 파일을 ~/mediatek_kernel이라는 폴더에 압축을 풀었다고 가정해 보겠습니다.
Bear를 설치하고 아래 단계를 따르세요:
cd ~/mediatek_kernel
source ./env.sh
cd kernel-3.18
# the following step may not be needed depending on the kernel
mkdir out
make O=out ARCH=arm64 tubads_defconfig
# generating compile_commands.json
bear make -j8 O=out ARCH=arm64
cd <repo_path>/helper_scripts
python run_all.py -l ~/mediatek_kernel/llvm_bitcode_out -a 1 -c ~/mediatek_kernel/kernel-3.18/compile_commands.json -n 2 -o ~/mediatek_kernel/kernel-3.18/out -k ~/mediatek_kernel/kernel-3.18 -f ~/mediatek_kernel/ioctl_finder_out
위 명령은 시간이 꽤 걸립니다(30분~1시간).
먼저 모든 분석 결과는 ~/mediatek_kernel/ioctl_finder_out (-f 옵션에 주어진 인수) 폴더에 저장됩니다. 각 엔트리 포인트에 대해 복구된 인터페이스에 대한 모든 정보를 포함하는 .txt 파일이 생성됩니다.
인터페이스에 대한 정보만 관심 있고 다른 것은 신경 쓰지 않는다면 parse_interface_output.py 스크립트를 사용하는 것이 좋습니다. 이 스크립트는 인터페이스 복구 패스의 복잡한 출력을 깔끔하고 일관된 형식의 멋진 json 파일로 변환합니다.