
DR.CHECKER : Uma Ferramenta de Detecção de Vulnerabilidades Soundy para Drivers do Kernel Linux

Este repositório contém todas as fontes, incluindo scripts de configuração. Agora com uma UI incrível para visualizar os avisos junto com os arquivos de fonte correspondentes.
Ubuntu >= 14.04.5 LTS
16 Fev 2018:
Consulte o documento Uso do Docker para detalhes sobre como usar o DR.CHECKER em um contêiner docker pré-construído.
Nossa implementação é baseada em LLVM, especificamente LLVM 3.8. Também precisamos de ferramentas como c2xml para analisar cabeçalhos.
Primeiro, certifique-se de ter cmake (usado pelos scripts de configuração/construção) e libxml (necessário para c2xml):
sudo apt-get install cmake libxml2-dev
Em seguida, criamos um único script que baixa e constrói todas as ferramentas necessárias.
cd helper_scripts
python setup_drchecker.py --help
usage: setup_drchecker.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.
Exemplo:
python setup_drchecker.py -o drchecker_deps
Para completar a configuração, você também precisa de modificações na variável de ambiente PATH local. O script de configuração fornecerá as alterações exatas que você precisa fazer.
Isso depende da conclusão bem-sucedida da Configuração. Temos um único script que constrói tudo, fique à vontade.
cd llvm_analysis
./build.sh
Isso depende da conclusão bem-sucedida da Construção. Para executar o DR.CHECKER em drivers do kernel, precisamos primeiro convertê-los para bitcode LLVM.
Primeiro, precisamos ter um kernel que possa ser construído. Isso significa que você deve ser capaz de compilar o kernel usando a configuração de construção regular, ou seja, make.
Primeiro capturamos a saída do comando make e, a partir dessa saída, extraímos o comando de compilação exato.
make (ou makeout.txt)Basta passar V=1 e redirecionar a saída para o arquivo.
Exemplo:
make V=1 O=out ARCH=arm64 > makeout.txt 2>&1
NOTA: NÃO USE MÚLTIPLOS PROCESSOS, ou seja, -j. Executar no modo multiprocessamento bagunçará o arquivo de saída, pois vários processos tentam escrever nele.
É isso. O DR.CHECKER cuidará disso daqui para frente.
Há várias etapas para executar a análise do DR.CHECKER, todas essas etapas estão encapsuladas em um único script helper_scripts/runner_scripts/run_all.py
Como executar:
python run_all.py --help
usage: run_all.py [-h] [-l LLVM_BC_OUT] [-a CHIPSET_NUM] [-m MAKEOUT] [-g COMPILER_NAME] [-n ARCH_NUM] [-o OUT] [-k KERNEL_SRC_DIR] [-skb] [-skl] [-skp] [-ske] [-ski] [-f SOUNDY_ANALYSIS_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.
-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. (Note: Not all kernels needs a separate out folder)
-k KERNEL_SRC_DIR Base directory of the kernel sources.
-skb Skip LLVM Build (default: not skipped).
-skl Skip Dr Linker (default: not skipped).
-skp Skip Parsing Headers (default: not skipped).
-ske Skip Entry point identification (default: not skipped).
-ski Skip Soundy Analysis (default: not skipped).
-f SOUNDY_ANALYSIS_OUT Path to the output folder where the soundy analysis output should be stored.
O script constrói, vincula e executa o DR.CHECKER em todos os drivers, portanto, pode levar um tempo considerável (45 min - 90 min). Se você quiser executar o DR.CHECKER manualmente em drivers individuais, consulte autônomo
O script acima executa as seguintes tarefas no modo multiprocessador para utilizar todos os núcleos da CPU:
Todos os arquivos de bitcode gerados serão colocados na pasta fornecida ao argumento -l.
Esta etapa leva um tempo considerável, dependendo do número de núcleos que você possui.
Portanto, se você já tiver feito essa etapa, pode pulá-la passando -skb.
Isso realiza a vinculação, percorre todos os arquivos de bitcode, identifica os arquivos de bitcode relacionados que precisam ser vinculados e os vincula (usando llvm-link) em um arquivo de bitcode consolidado (que será armazenado junto com o arquivo de bitcode correspondente).
Assim como na etapa acima, você pode pular esta etapa passando -skl.
Esta etapa procura declarações de pontos de entrada nos arquivos de cabeçalho e armazena sua configuração no arquivo: hdr_file_config.txt no diretório de construção do LLVM.
Para pular: -skp
Esta etapa identifica todos os pontos de entrada em todos os arquivos de bitcode consolidados do driver.
A saída será armazenada no arquivo: entry_point_out.txt no diretório de construção do LLVM.
Exemplo de conteúdo do arquivo entry_point_out.txt:
FileRead:hidraw_read:/home/drchecker/33.2.A.3.123/llvm_bc_out/drivers/hid/llvm_link_final/final_to_check.bc
FileWrite:hidraw_write:/home/drchecker/33.2.A.3.123/llvm_bc_out/drivers/hid/llvm_link_final/final_to_check.bc
IOCTL:hidraw_ioctl:/home/drchecker/33.2.A.3.123/llvm_bc_out/drivers/hid/llvm_link_final/final_to_check.bc
Para pular: -ske
Esta etapa executará o DR.CHECKER em todos os pontos de entrada no arquivo entry_point_out.txt. A saída para cada ponto de entrada será armazenada na pasta fornecida pela opção -f.
Para pular: -ski
Agora, mostraremos um exemplo do ponto em que você tem as fontes do kernel até o ponto de obter avisos de vulnerabilidade.
Carregamos um kernel mediatek 33.2.A.3.123.tar.bz2. Primeiro, baixe e extraia o arquivo acima.
Digamos que você extraiu o arquivo acima em uma pasta chamada: ~/mediatek_kernel
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
# this following command copies all the compilation commands to makeout.txt
make V=1 -j8 O=out ARCH=arm64 > makeout.txt 2>&1
cd <repo_path>/helper_scripts/runner_scripts
python run_all.py -l ~/mediatek_kernel/llvm_bitcode_out -a 1 -m ~/mediatek_kernel/kernel-3.18/makeout.txt -g aarch64-linux-android-gcc -n 2 -o ~/mediatek_kernel/kernel-3.18/out -k ~/mediatek_kernel/kernel-3.18 -f ~/mediatek_kernel/dr_checker_out
O comando acima leva um tempo considerável (30 min - 1h).
Primeiro, todos os resultados da análise estarão na pasta: ~/mediatek_kernel/dr_checker_out (argumento fornecido à opção -f), para cada ponto de entrada será criado um arquivo .json que contém todos os avisos no formato JSON. Esses arquivos json contêm avisos organizados por contextos.
Segundo, a pasta ~/mediatek_kernel/dr_checker_out/instr_warnings (em relação ao argumento fornecido à opção -f) contém avisos organizados por localização da instrução.
Esses avisos podem ser analisados usando nosso Visualizador.
Finalmente, um resumo de todos os avisos para cada ponto de entrada, organizados pelo tipo, será gravado no arquivo CSV de saída: ~/mediatek_kernel/dr_checker_out/warnings_stats.csv (em relação ao argumento fornecido à opção -f).
-gPara fornecer o valor para a opção -g, você precisa saber o nome do binário *-gcc usado para compilar o kernel.
Uma maneira fácil de saber isso seria usar grep para gcc em makeout.txt e você verá comandos do compilador a partir dos quais pode descobrir o nome do binário *-gcc.
Para nosso exemplo acima, se você executar grep gcc makeout.txt para a compilação de exemplo, verá muitas linhas como abaixo:
aarch64-linux-android-gcc -Wp,-MD,fs/jbd2/.transaction.o.d -nostdinc -isystem ...
Portanto, o valor para -g deve ser aarch64-linux-android-gcc.
Se o kernel a ser construído for de 32 bits, o binário provavelmente será arm-eabi-gcc
-aDependendo do tipo de chipset, você precisa fornecer o número correspondente.
-oEste é o caminho da pasta fornecida à opção O= no comando make durante a compilação do kernel.
Nem todos os kernels precisam de um caminho de saída separado. Você pode compilar o kernel sem fornecer uma opção O; nesse caso, você NÃO DEVE fornecer valor para essa opção ao executar run_all.py.
Fornecemos uma interface web para visualizar todos os avisos. Consulte Visualização.
Você pode desabilitar um ou mais verificadores de vulnerabilidade descomentando as linhas #define DISABLE_* correspondentes em BugDetectorDriver.cpp
Para sua conveniência, também fornecemos um script para pós-processar os resultados. Confira.
Divirta-se!!