
KRF는 Kernelspace Randomized Faulter입니다.
현재 Linux 및 FreeBSD 커널을 지원합니다.
오류 주입(Fault Injection)은 프로그램이 호출하는 함수에 실패("오류")를 유도하는 소프트웨어 테스트 기법입니다. 호출된 함수가 적절한 오류 확인 및 처리를 수행하지 못한 경우, 이러한 오류는 신뢰할 수 없는 애플리케이션 동작이나 악용 가능한 취약점으로 이어질 수 있습니다.
많은 사용자 공간 오류 주입 시스템과 달리, KRF는 로드된 모듈을 통해 커널 공간에서 실행됩니다. 여기에는 몇 가지 장점이 있습니다:
LD_PRELOAD에 의존하지 않기 때문입니다.syscall(3) 또는 인라인 어셈블리를 통해 이루어진 호출에 오류를 주입할 수 있습니다.dlsym을 조작하는 것보다 빠르고 오류가 적을 것입니다.또한 몇 가지 단점이 있습니다:
cr0를 조작하기 때문에 아마 x86(_64)에서만 작동합니다. 아마 리눅스에서 아키텍처 독립적인 방법이 있을 것입니다.KRF는 Linux 또는 FreeBSD 시스템 호출 테이블을 다시 작성합니다: krfctl을 통해 구성되면, KRF는 오류 주입 가능한 시스템 호출을 얇은 래퍼로 대체합니다.
그런 다음 각 래퍼는 특정 personality(2), PID, UID 및/또는 GID를 대상으로 할 수 있는 구성 가능한 대상 지정 시스템을 사용하여 호출에 오류를 주입해야 하는지 확인합니다. 프로세스에 오류를 주입하지 않아야 하는 경우 원래 시스템 호출이 호출됩니다.
마지막으로, 대상이 지정된 호출은 무작위 실패 함수를 통해 오류가 주입됩니다. 예를 들어, read(2) 호출은 EBADF, EINTR, EIO 등 중 하나를 받을 수 있습니다.
KRF의 구현에 대한 자세한 내용은 블로그 게시물에서 확인할 수 있습니다.
참고: Vagrant가 있다면 Vagrantfile을 사용하고 빌드 단계로 건너뛰세요.
KRF는 CONFIG_KALLSYMS=1을 활성화한 모든 최신(4.15+) Linux 커널에서 작동해야 합니다. 여기에는 Ubuntu 18.04의 기본 커널과 아마도 다른 많은 최신 배포판이 포함됩니다.
참고: Vagrant를 사용하는 경우 무시하세요.
C 툴체인(GCC는 Linux에 필요할 수 있음) 외에도 KRF의 유일한 종속성은 libelf, 커널 헤더, Ruby(>=2.4, 코드 생성용)입니다. GNU Make는 모든 플랫폼에서 필요합니다. FreeBSD는 추가로 BSD Make가 필요합니다.
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
또는 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
또는 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
KRF는 세 가지 구성 요소로 이루어져 있습니다:
krfx)krfexec)krfctl)krfmesg)커널 모듈을 로드하려면 make insmod를 실행하세요. 언로드하려면 make rmmod를 실행하세요.
처음 사용 시에는 별도의 터미널에서 sudo krfmesg를 실행하여 krfx에서 기록된 메시지를 확인하는 것이 유용할 수 있습니다.
KRF는 중립 상태로 시작합니다: 사용자가 krfctl을 통해 일부 동작을 지정할 때까지 시스템 호출이 가로채지거나 오류가 주입되지 않습니다.
# 유도된 오류 없음, KRF가 로드된 상태에서도
ls
# krf에 read(2) 및 write(2) 호출에 오류를 주입하도록 지시
# krfctl은 루트 권한이 필요함
sudo krfctl -F 'read,write'
# krf에 krfexec로 시작된 모든 프로그램(즉, personality 28)에 오류를 주입하도록 지시
sudo krfctl -T personality=28
# 오류가 발생할 수 있음!
krfexec ls
# krf에 1/100 (또는 1%) 확률로 오류를 주입하도록 지시
# 이 값은 역수로 표현됨에 유의
# 예: 1은 모든 오류 주입 가능한 시스템 호출에 오류가 발생함을 의미
# 500은 평균적으로 500번의 시스템 호출마다 오류가 발생함을 의미 (1/500 또는 0.2%)
sudo krfctl -p 100
# krf에 `io` 프로필 (I/O 관련 시스템 호출)에 오류를 주입하도록 지시
sudo krfctl -P io
# krfexec는 옵션도 올바르게 전달함
krfexec echo -n 'no newline'
# 오류 지정 해제
sudo krfctl -c
# 대상 지정 해제
sudo krfctl -C
# 오류가 주입되는 시스템 호출이 없으므로 유도된 오류 없음
krfexec firefox
참고: 대부분의 사용자는 이러한 파일을 수동으로 조작하는 대신 krfctl을 사용해야 합니다. FreeBSD에서는 동일한 값을 procfs 대신 sysctl krf.whatever를 통해 접근할 수 있습니다.
/proc/krf/rng_state이 파일을 통해 사용자는 KRF의 PRNG 내부 상태를 읽고 수정할 수 있습니다.
예를 들어, 다음 각각은 상태를 올바르게 업데이트합니다:
echo "1234" | sudo tee /proc/krf/rng_state
echo "0777" | sudo tee /proc/krf/rng_state
echo "0xFF" | sudo tee /proc/krf/rng_state
상태는 32비트 부호 없는 정수이며, 이를 초과하여 변경하려고 하면 실패합니다.
/proc/krf/targeting이 파일을 통해 사용자는 KRF에서 시스템 호출 대상 지정에 사용할 값을 설정할 수 있습니다.
참고: KRF는 기본적으로 현재 Linux 커널에서 기본적으로 사용되지 않는 personality을 사용합니다. 이 값을 변경하는 경우 Linux가 신경 쓰는 값이 되지 않도록 주의해야 합니다. man 2 personality에 자세한 내용이 있습니다.
echo "0 28" | sudo tee /proc/krf/targeting
Personality 28은 krfexec에 하드코딩되어 있으며, krfexec로 실행된 것들에 오류가 주입되도록 하려면 이 값을 설정해야 합니다.
/proc/krf/probability이 파일을 통해 사용자는 주어진 (오류 주입 가능한) 시스템 호출에 대해 오류를 유도할 확률을 읽고 쓸 수 있습니다.
확률은 역수로 표현됩니다. 예를 들어 1000은 평균적으로 오류 주입 가능한 시스템 호출의 0.1%에 오류가 주입됨을 의미합니다.
echo "100000" | sudo tee /proc/krf/probability
/proc/krf/control이 파일은 KRF가 오류를 주입할 시스템 호출을 제어합니다.
참고: 대부분의 사용자는 이 파일과 직접 상호작용하는 대신 krfctl을 사용해야 합니다. krfctl은 시스템 호출 이름을 번호로 자동 변환하고 문제 발생 시 더 명확한 오류 메시지를 제공합니다.
# 슬롯 0 (일반적으로 SYS_read)의 시스템 호출을 오류 래퍼로 교체
echo "0" | sudo tee /proc/krf/control
KRF_NR_SYSCALLS보다 큰 숫자를 전달하면 KRF가 전체 시스템 호출 테이블을 플러시하여 중립 상태로 되돌립니다. KRF_NR_SYSCALLS는 임의의 Linux 커널 버전에 대해 반드시 예측 가능한 것은 아니므로 큰 숫자(예: 65535)를 선택해도 괜찮습니다.
오류 주입 래퍼가 없는 유효한 시스템 호출 번호를 전달하면 파일에 대한 write(2)가 EOPNOTSUPP로 실패합니다.
/proc/krf/log_faults이 파일은 KRF가 오류가 발생한 시스템 호출에 대해 커널 로그를 출력할지 여부를 제어합니다. 기본적으로 로깅 메시지는 출력되지 않습니다.
참고: 대부분의 사용자는 이 파일과 직접 상호작용하는 대신 krfctl을 사용해야 합니다.
# 오류 로깅 활성화
echo "1" | sudo tee /proc/krf/log_faults
# 오류 로깅 비활성화
echo "0" | sudo tee /proc/krf/log_faults
# 로깅 상태 읽기
cat /proc/krf/log_faults
ENOMEM)). 이는 personality(2) 값에 비트를 더 추가하여 가능해야 합니다.KRF의 FreeBSD로의 초기 포트에 대해 Andrew Reiter에게 많은 감사를 드립니다. Andrew의 작업은 Veracode의 응용 연구 그룹(Applied Research Group)을 대신하여 수행되었습니다.
KRF는 GNU GPLv3 조건에 따라 라이선스가 부여됩니다. 정확한 조건은 LICENSE 파일을 참조하십시오.