
Um interceptador de chamadas de sistema no espaço do kernel e um gerador de falhas aleatório
KRF é um Falhedor Aleatório em Espaço de Kernel.
Atualmente suporta os kernels Linux e FreeBSD.
Injeção de falhas é uma técnica de teste de software que envolve induzir falhas nas funções chamadas por um programa. Se o destinatário da chamada não realizou a verificação e tratamento de erros adequados, essas falhas podem resultar em comportamento não confiável da aplicação ou vulnerabilidades exploráveis.
Diferente dos muitos sistemas de injeção de falhas em espaço de usuário existentes, o KRF executa em espaço de kernel através de um módulo carregado. Isso tem várias vantagens:
LD_PRELOAD para injeção.syscall(3) ou assembly inline.dlsym.Há também várias desvantagens:
cr0. Deve haver
uma maneira independente de arquitetura de fazer isso no Linux, em algum lugar.O KRF reescreve a tabela de chamadas de sistema do Linux ou FreeBSD: quando configurado
via krfctl, o KRF substitui syscalls falháveis por wrappers finos.
Cada wrapper então realiza uma verificação para ver se a chamada deve sofrer falha usando um
sistema de direcionamento configurável capaz de direcionar um personality(2), PID, UID e/ou GID
específicos. Se o processo não deve sofrer falha, a syscall original é invocada.
Finalmente, a chamada direcionada sofre falha através de uma função de falha aleatória. Por exemplo,
uma chamada read(2) pode receber um dos EBADF, EINTR, EIO, e assim por diante.
Você pode ler mais sobre a implementação do KRF em nosso post no blog.
NOTA: Se você tem Vagrant, apenas use o Vagrantfile e vá para as etapas de compilação.
O KRF deve funcionar em qualquer kernel Linux recente (4.15+) com CONFIG_KALLSYMS=1.
Isso inclui o kernel padrão no Ubuntu 18.04 e provavelmente muitas outras distros recentes.
NOTA: Ignore isso se estiver usando Vagrant.
Além de uma toolchain C (GCC é provavelmente necessário para Linux), as únicas dependências do KRF
devem ser libelf, os cabeçalhos do kernel e Ruby (>=2.4, para geração de código).
O GNU Make é necessário em todas as plataformas; FreeBSD adicionalmente requer o BSD Make.
Para sistemas com apt:
sudo apt install gcc make libelf-dev ruby linux-headers-$(uname -r)
git clone https://github.com/trailofbits/krf && cd krf
make -j$(nproc)
sudo make install # Installs module to /lib/modules and utils to /usr/local/bin
sudo make insmod # Loads module
ou, se estiver usando Vagrant:
git clone https://github.com/trailofbits/krf && cd krf
vagrant up linux && vagrant ssh linux
# inside the VM
cd /vagrant
make -j$(nproc)
sudo make install # Installs module to /lib/modules and utils to /usr/local/bin
sudo make insmod # Loads module
ou, para FreeBSD:
git clone https://github.com/trailofbits/krf && cd krf
cd vagrant up freebsd && vagrant ssh freebsd
# inside the VM
cd /vagrant
gmake # NOT make!
gmake install-module # Installs module to /boot/modules/
sudo gmake install-utils # Installs utils to /usr/local/bin
gmake insmod # Loads module
O KRF tem três componentes:
krfx)krfexec)krfctl)krfmesg)Para carregar o módulo de kernel, execute make insmod. Para descarregá-lo, execute make rmmod.
Para o primeiro uso, pode ser útil executar sudo krfmesg em um terminal separado para ver
mensagens registradas pelo krfx.
O KRF começa em um estado neutro: nenhuma syscall será interceptada ou sofrerá falha até que o usuário
especifique algum comportamento via krfctl:
# no induced faults, even with KRF loaded
ls
# tell krf to fault read(2) and write(2) calls
# note that krfctl requires root privileges
sudo krfctl -F 'read,write'
# tell krf to fault any program started by
# krfexec, meaning a personality of 28
sudo krfctl -T personality=28
# may fault!
krfexec ls
# tell krf to fault with a 1/100 (or 1%) probability
# note that this value is represented as a reciprocal
# so e.g. 1 means all faultable syscalls will fault
# and 500 means that on average every 500 syscalls will fault (1/500 or 0.2%)
sudo krfctl -p 100
# tell krf to fault `io` profile (and so i/o related syscalls)
sudo krfctl -P io
# krfexec will pass options correctly as well
krfexec echo -n 'no newline'
# clear the fault specification
sudo krfctl -c
# clear the targeting specification
sudo krfctl -C
# no induced faults, since no syscalls are being faulted
krfexec firefox
NOTA: A maioria dos usuários deve usar krfctl em vez de manipular esses arquivos manualmente.
No FreeBSD, esses mesmos valores são acessíveis através de sysctl krf.whatever em vez de procfs.
/proc/krf/rng_stateEste arquivo permite que um usuário leia e modifique o estado interno do PRNG do KRF.
Por exemplo, cada um dos seguintes atualizará corretamente o estado:
echo "1234" | sudo tee /proc/krf/rng_state
echo "0777" | sudo tee /proc/krf/rng_state
echo "0xFF" | sudo tee /proc/krf/rng_state
O estado é um inteiro sem sinal de 32 bits; tentar alterá-lo além disso falhará.
/proc/krf/targetingEste arquivo permite que um usuário defina os valores usados pelo KRF para direcionamento de syscall.
NOTA: O KRF usa uma personalidade padrão não usada atualmente pelo kernel Linux por padrão. Se você
alterar isso, deve ter cuidado para evitar torná-lo algo com que o Linux se importe. man 2 personality
tem os detalhes.
echo "0 28" | sudo tee /proc/krf/targeting
Uma personalidade de 28 é codificada no krfexec e deve ser definida para que as coisas executadas
por krfexec sofram falha.
/proc/krf/probabilityEste arquivo permite que um usuário leia e escreva a probabilidade de induzir falha para uma determinada syscall falhável.
A probabilidade é representada como um recíproco, por exemplo, 1000 significa que, em média, 0,1% das
syscalls falháveis sofrerão falha.
echo "100000" | sudo tee /proc/krf/probability
/proc/krf/controlEste arquivo controla as syscalls que o KRF falha.
NOTA: A maioria dos usuários deve usar krfctl em vez de interagir com este arquivo diretamente —
o primeiro realizará a tradução de nome para número de syscall automaticamente e fornecerá mensagens de erro
mais claras quando algo der errado.
# replace the syscall in slot 0 (usually SYS_read) with its faulty wrapper
echo "0" | sudo tee /proc/krf/control
Passar qualquer número maior que KRF_NR_SYSCALLS fará com que o KRF limpe toda a tabela de syscalls,
retornando-a ao estado neutro. Como KRF_NR_SYSCALLS não é necessariamente previsível para
versões arbitrárias do kernel Linux, escolher um número grande (como 65535) é aceitável.
Passar um número de syscall válido que não possui um wrapper de injeção de falha fará com que o write(2)
no arquivo falhe com EOPNOTSUPP.
/proc/krf/log_faultsEste arquivo controla se o KRF emite registros de kernel em syscalls com falha. Por padrão, nenhuma mensagem de registro é emitida.
NOTA: A maioria dos usuários deve usar krfctl em vez de interagir com este arquivo diretamente.
# enable fault logging
echo "1" | sudo tee /proc/krf/log_faults
# disable fault logging
echo "0" | sudo tee /proc/krf/log_faults
# read the logging state
cat /proc/krf/log_faults
ENOMEM).
personality(2).Muitos agradecimentos a Andrew Reiter pela portabilidade inicial do KRF para FreeBSD. O trabalho de Andrew foi realizado em nome do Applied Research Group na Veracode.
KRF é licenciado sob os termos da GNU GPLv3.
Veja o arquivo LICENSE para os termos exatos.