Методика фаззинг-тестирования ядра

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:

Видео
Слайды
Пример анализа срабатывания Memory leak in drm