Методика фаззинг-тестирования ядра
1. Принципы работы syzkaller и его компонентов
2. Фаззинг своего ядра: инструкция по настройке и запуску syz-manager
3. Фаззинг своего ядра: инструкция по настройке и запуску syz-hub
4. Фаззинг своего ядра: добавление внешних корпусов
5. Разбор срабатываний syzkaller
Принципы работы syzkaller и его компонентов
Фаззингом называют динамический метод анализа кода, при котором на вход функциям/системным вызовам исследуемого программного обеспечения подаются случайные данные в попытке выявить дефекты.
Для фаззинг-тестирования ядра Linux на системном уровне предлагается использовать инструмент syzkaller. Вводная информация о принципах его работы и составлющих его компонентах представлена здесь.
Возможно использовать две схемы фаззинг-тестирования при помощи syzkaller.
- Cхема простого фаззинга (далее «в режиме
syz-manager») подходит в тех случаях, когда у вас имеется только одна машина, которая занимается фаззингом, или используется несколько машин, но отсутствует необходимость обмена информацией между ними (каждая машина работает со своей специфической конфигурацией, версией ядра и т.д.). В этом случае достаточно настройки толькоsyz-manager. - Cхема фаззинг-фермы (далее «в режиме
syz-hub») подходит, если фаззингом занимается несколько машин с одинаковой конфигурацией. В этом случае помимо установкиsyz-managerрекомендуется дополнительно поставитьsyz-hubи подключить к нему менеджеры для обмена информацией.
Фаззинг своего ядра: инструкция по настройке и запуску в режиме syz-manager
В простейшем случае для запуска фаззинга на своей версии ядра на эмулируемой аппаратуре qemu нужно использовать инструмент syz-manager. syz-manager управляет запуском эмулятора, по ssh копирует фаззинг-программы внутрь эмулируемого окружения и запускает их. Для подготовки syz-manager к работе необходимо выполнить
$ git clone https://git.linuxtesting.ru/pub/scm/tools/lvc/syzkaller.git
$ cd syzkaller
$ apt-get install golang-go
$ make fuzzer manager executor execprog
Далее необходимо подготовить образ виртуальной машины. Для этого можно использовать скрипт create-image.sh:
$ cd syzkaller
$ apt-get install debootstrap
$ ./tools/create-image.sh
В результате выполнения create-image.sh создаются файлы bullseye.img, bullseye.id_rsa, bullseye.id_rsa.pub. Первый представляет собой образ rootfs, созданный на основе дистрибутива Debian с использование инструмента debootstrap. Два последних файла необходимы для доступа в виртуальную машину по ssh. При необходимости можно модифицировать образ, полученный с помощью create-image.sh, или использовать самостоятельно подготовленный образ.
Далее необходимо подготовить и собрать версию ядра Linux для фаззинга, используя рекомендации по настройке конфигурационных опций ядра Linux при проведении фаззинг-тестирования.
После сборки ядра можно запускать фаззинг командой:
$ cd syzkaller
$ apt-get install qemu qemu-system-x86
$ ./bin/syz-manager -config manager.cfg
Где файл конфигурации manager.cfg выглядит следующим образом:
{
"target": "linux/amd64",
"http": "localhost:56741",
"workdir": "/home/lvc/syzkaller/workdir",
"kernel_obj": "/home/lvc/linux-stable",
"image": "/home/lvc/syzkaller/bullseye.img",
"sshkey": "/home/lvc/syzkaller/bullseye.id_rsa",
"syzkaller": "/home/lvc/syzkaller",
"procs": 4,
"type": "qemu",
"vm": {
"count": 3,
"cpu": 2,
"mem": 2048,
"kernel": "/home/lvc/linux-stable/arch/x86/boot/bzImage"
},
"disable_syscalls": ["keyctl", "add_key", "request_key"]
}
Структурно, это json файл со следующими полями:
target— тип ядра и архитектуры,http— адрес и порт для веб панели, на которой отображается покрытие и статус фаззинга,workdir— путь до директории с корпусом и результатами фаззинга,kernel_obj— путь до директории с исходным кодом ядра Linux и артефактами его сборки, необходимыми для отображения покрытия такими, как.config@,vmlinuxи т. д. (если директории с исходными кодами ядра и его сборки не совпадают, можно использовать полеkernel_src, подробнее см. комментарии вpkg/mgrconfig/config.go),image— путь до файла с образом виртуальной машины,sshkey— путь до файла с ключем для доступа внутрь виртуальной машины поssh,syzkaller— путь до директории с исходниками syzkaller, в которой произведена его сборка,procs— количество одновременно запускаемых программ фаззинга внутри виртуальной машины,type— тип фаззинга,vm— блок с описанием виртуальной машины для фаззинга типа qemu,vm.count— количество одновременно работающих виртуальных машин,vm.cpu— количество ядер, выделяемых одной виртуальной машине,vm.mem— размер оперативной памяти, выделяемой одной виртуальной машине,vm.kernel— путь до файла с ядром, на котором выполняется фаззинг,disable_syscalls— список системных вызовов, которые необходимо исключить из фаззинга.
Вместо disable_syscall или в дополнении к нему можно наоборот перечислить системные вызовы для фаззинга. Например, добавить в конфигурацию enable_syscalls и ограничить фаззинг только ioctl системными вызовами драйвера floppy:
"enable_syscalls": [
"syz_open_dev$floppy",
"ioctl$FLOPPY*"
]
Списки системных вызовов можно найти в файлах sys/linux/*.txt. "ioctl$FLOPPY*" в данном случае означает все системные вызовы, описание которых начинается с ioctl$FLOPPY.
После запуска фаззинга в консоли будут отображаться текущий статус фаззинга, найденные ошибки, количество покрытых базовых блоков. По адресу http://localhost:56741 будет доступна веб-панель syzkaller с этой же информацией. Дополнительно в веб-панели можно посмотреть покрытие по исходными кодам, цепочки системных вызовов и все найденные ошибки.
Фаззинг своего ядра: инструкция по настройке и запуску в режиме syz-hub
Если у вас используется несколько экземпляров syz-manger их можно объединить в общую сеть для обмена данными. Для этого используется syz-hub, для запуска которого необходимо выполнить:
$ cd syzkaller
$ make hub
$ ./bin/syz-hub -config hub.cfg
Где файл конфигурации hub.cfg выглядит следующим образом:
{
"http": "1.2.3.4:80",
"rpc": "1.2.3.4:55555",
"workdir": "/syzkaller/workdir",
"clients": [
{"name": "manager1", "key": "6sCFsJVfyFQVhWVKJpKhHcHxpCH0gAxL"},
{"name": "manager2", "key": "FZFSjthHHf8nKm2cqqAcAYKM5a3XM4Ao"},
{"name": "manager3", "key": "fTrIBQCmkEq8NsvQXZiOUyop6uWLBuzf"}
]
}
Структурно, это файл с данными в формате json со следующими полями:
http— адрес и порт для доступа к веб-панели, на которой отображается информация об обмене данными между экземплярамиsyz-managerиsyz-hub,rpc— адрес и порт, по которому экземплярыsyz-managerбудут отправлять запросы для обмена информацией сsyz-hub,workdir— путь до директории в котором будет аккумулироваться общий корпус а также корпуса для каждого экземпляраsyz-manager,clients.name— имя определенного экземпляраsyz-manager,clients.key— ключ, который будет использовать определенный экземплярsyz-managerдля подключения кsyz-hub. Для генерации ключа можно использовать команду:
tr -dc A-Za-z0-9 < /dev/urandom | head -c 32
Для того чтобы syz-manager подключался к syz-hub необходимо дополнить его конфигурацию:
{
"target": "linux/amd64",
"name": "manager1",
"hub_client": "manager1",
"hub_addr": "1.2.3.4:55555",
"hub_key": "6sCFsJVfyFQVhWVKJpKhHcHxpCH0gAxL",
"hub_domain": "5.10",
...
}
Где:
hub_client— имя экземпляра менеджера, используя которое менеджер подключается кsyz-hub, должно совпадать с одним из значений полейclients.nameв конфигеsyz-hub,hub_addr— адрес и порт, по которому экземплярsyz-managerотправляет запросы для обмена информацией сsyz-hub, должны совпадать со значениями поляrpcв конфигеsyz-hub,hub_key— ключ, с которым экземплярsyz-managerподключается кsyz-hub, соответствует полюclients.keyв конфигеsyz-hub,hub_domain— домен, в котором экземплярsyz-managerподключается кsyz-hub, в рамках одного домена экземплярыsyz-managerобмениваются информацией,name— имя экземпляраsyz-manager, которое отображается в веб-панелиsyz-hub, должно начинаться с подстроки, совпадающей со значением поляhub_client.
Экземпляры syz-manager обмениваются информацией только в рамках одного домена, заданного значением поля hub_domain. После перезапуска syz-manager обрабатывает локальный корпус после чего подключается к syz-hub для обмена информацией.
Фаззинг своего ядра: добавление внешних корпусов
В процессе фаззинга syzkaller измеряет покрытие и строит корпус входных значений, который позволяет покрыть как можно больше базовых блоков в ядре. Корпус сохраняется в файле corpus.db рабочей директории ~/syzkaller/workdir/corpus.db. Эта база входных значений относительно переносима и может подходить под другие ядра. Корпус фаззинга Центра исследований безопасности системного ПО доступен для Партнёров по ссылке. Скачанный файл необходимо расшифровать и поместить в рабочий каталог workdir. При старте фаззинга syz-manager автоматически загрузит его и отфильтрует значения, неподходящие под актуальное ядро.
Если у вас уже есть собственный файл corpus.db, то добавление в него данных из другого файла corpus.db можно сделать разными способами.
Если используется только syz-manager, то можно в ваш файл corpus.db добавить данные из другого corpus.db при помощи syz-db
$ cd syzkaller
$ make db
$ ./bin/syz-db merge main-corpus.db additional-1-corpus.db additional-2-corpus.db ...
На выходе, все данные из файлов [additional-1-corpus.db, additional-2-corpus.db, ...] будут добавлены в main-corpus.db
Если используется syz-hub, то данные из внешнего файла corpus.db можно добавить в него, откуда они попадут в экземпляры syz-manager, подключенные в соответствующем домене. Для этого необходимо выполнить:
$ cd syzkaller
$ make hubtool
$ syz-hubtool -addr=localhost:55555 -key=6sCFsJVfyFQVhWVKJpKhHcHxpCH0gAxL -client=manager1 -manager=manager1-import-corpus -hub_domain=5.10 -chunks=true -chunksize=90000 -corpus=corpus_ispras.db -new_manager=false
Где:
-addr— адрес и порт для HTTP-запросов вsyz-hub, можно взять из соответствующих полей конфигурацииsyz-hubилиsyz-manager-key— ключsyz-manager, от имени которого будет производится загрузка, можно взять из соответствующих полей конфигурацииsyz-hubилиsyz-manager-client— имя , от имени которого будет производится загрузка, можно взять из соответствующих полей конфигурацииsyz-hubилиsyz-manager-manager— отображаемое вsyz-hubимяsyz-manager, должно начинаться с подстроки, совпадающей со значением аргумента-client-hub_domain— домен, в который загружается корпус, в дальнейшем данные будут передаваться в экземплярыsyz-manager, подключенные в этом домене-chunks— флаг (по умолчаниюfalse), указывает нужно ли производить загрузку по частям-chunksize— если указан-chunks true, указывает количество элементов в разовой загрузке (загрузка происходит раз в 10 минут, пока не будет загружен весь файл)-corpus— путь до файлаcorpus.db, который необходимо загрузить-new_manager— флаг (по умолчаниюtrue), еслиtrue, то при загрузке нового корпуса удаляется вся информация о предыдущем загруженном корпусе, еслиfalse, то при загрузке нового корпуса информация добавляется к ранее загруженному корпусу (аккумулируется)
Разбор срабатываний syzkaller
Запись вебинара, посвящённого вопросам обработки срабатываний syzkaller: