]> Untitled Git - articles.git/commitdiff
опечатка в названии каталога
authorRince <rince@mail.ru>
Sat, 8 Nov 2025 13:43:54 +0000 (16:43 +0300)
committerRince <rince@mail.ru>
Sat, 8 Nov 2025 13:43:54 +0000 (16:43 +0300)
SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cзованием btrfs/README.md [new symlink]
SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cзованием btrfs/Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs.md [new file with mode: 0644]
SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs/README.md [deleted symlink]
SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs/Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs.md [deleted file]

diff --git a/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cзованием btrfs/README.md b/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cзованием btrfs/README.md
new file mode 120000 (symlink)
index 0000000..6b6c5b4
--- /dev/null
@@ -0,0 +1 @@
+Подготовка окружения для исследуемого процесса с испольнованием btrfs.md
\ No newline at end of file
diff --git a/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cзованием btrfs/Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs.md b/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cзованием btrfs/Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs.md
new file mode 100644 (file)
index 0000000..5a4c820
--- /dev/null
@@ -0,0 +1,264 @@
+# Подготовка окружения для исследуемого процесса с испольнованием btrfs
+
+**Update:** По состоянию на 2025 год, коллеги из БазАльта предложили более совершенный способ переключения между снепшотами, основанный на обращении к соответствующим системным вызовам ядра прямо из кода исследуемой программы, в самом ее начале. Это позволяет реализовать фаззинг со снепшотами каталога данных на основе свободного AFL++. Описание подхода находится [Здесь](https://www.altlinux.org/PostgreSQL16_fuzzing_technique) ([WebArchive](http://web.archive.org/web/20241203093118/https://www.altlinux.org/PostgreSQL16_fuzzing_technique))
+
+
+---
+
+Часто при фаззинге сложных проектов может оказаться, что для нормальной работы каждому экземпляру исследуемой программы нужна собственная директория с данными, которую не плохо бы перед каждым новым прогоном исследуемой программы возвращать в исходное состояние. В данном посте в формате "заметок" я расскажу как мне удалось сделать восстановление окружения при фаззинге postgres'а, используя btrfs под фаззером Crusher.
+
+Для фаззига postgres'а система восстановления контекста чрезвычайно важна. Полноценный postgres не может работать без своего личного хранилища, и при этом меняет его практически на каждый чих. Без возвращения хранилища к исходному состоянию при тестировании, ни о какой воспроизводимости и речи быть не может. Поэтому как только заходит речь о фаззинг-тестировании postgres'а в сборе, необходимо сразу думать о системе восстановления контекста. 
+
+## btrfs -- файловая система со снепшотами
+
+В качестве framework'а для системы восстановления контекста была выбрана файловая система btrfs. Btrfs позволяет эффективно работать со снепшотами на уровне директорий. А именно, позволяет в рамках файловой системы получить клон указанной директории с минимальными затратами. Клонирование происходит на логическом уровне, данные по факту не копируются, и только лишь изменения внесенные в копию или в оригинал занимают дополнительное место на диске. Все это позволяет экономить время и дисковое пространство.
+
+Фаззинг, при его промышленном применении, имеет практический смысл, будучи запущенным во много потоков на многих процессорах. Для каждого инстанса фаззера, а точнее для исследуемой программы запущенной этим фаззером, предполагается создать свой собственный снепшот с уникальным именем, содержащий данные необходимые для запуска исследуемой программы, и возвращать этот снепшот к исходному состоянию перед каждым новым прогоном исследуемой программы, чтобы следы  оставленные в хранилище предыдущими прогонами не оказывали влияния на последующее..  
+
+Мной был написан скрипт `snapshooter.pl` (код приведен в конце поста) реализующий действия  со снепшотами, необходимые для фаззинга. Скрипту первым параметром передается имя команды и далее параметры которые нужны команде для работы.
+
+Ниже приведены команды и их описания:
+
+###### `init MOUNT_POINT IMAGE_FILE IMAGE_SIZE IMAGE_COUNT`
+
+Принимает 4 аргумента: точка монтирования `MOUNT_POINT`, путь к создаваемому образу файловой системы `IMAGE_FILE`, предполагаемый размер одного снепшота `IMAGE_SIZE` и ожидаемое количество снепшотов `IMAGE_COUNT`.
+
+Скрипт отмонтирует то, что было примантировано к точки монтирования, создаст новый образ файловой системы, примонтирует его к точке монтирования, и создаст в файловой системе директорию `_reference`.
+
+В эту директорию следует скопировать "эталонный" снепшот, на базе которого будут строиться снепшоты для всех экземпляров
+
+###### `clone MOUNT_POINT SNAPSHOT_NAME`
+
+Принимает два аргумента: точку монтирования `IMAGE_COUNT` и имя снэпшота `SNAPSHOT_NAME`.
+
+Команда `clone` клонирует эталонный снепшот в директорию `[SNAPSHOT_NAME].base`. Если есть потребность внести какие-то специфичные для инстанса изменения в снепшот, то это следует сделать в этой директории. В дальнейшем перед каждым запуском исследуемой программы рабочий снепшот будет приводится к "базововму" состоянию.
+
+###### `reset MOUNT_POINT SNAPSHOT_NAME`
+
+Принимает два аргумента: точку монтирования `MOUNT_POINT`и имя снэпшота `SNAPSHOT_NAME`.
+
+Команда `reset` удаляет снепшот `SNAPSHOT_NAME`, и создает новый с таким же именем клонируя  базовый снепшот `[SNAPSHOT_NAME].base`. Таким образом происходит восстановление целевого снепшота исходное состояние.
+
+В дальнейшем, для ускорения работы, планируется образ файловой системы со снепшотами перенести с диска в память, но я пока еще не разбирался как это делается.
+
+## Crusher
+
+В Crusher 2.11.0 появились инструменты позволяющие инициировать подготовку, и восстановления окружения для запускаемых процессов. К сожалению для того чтобы задействовать эти инструменты необходимо написание скриптов на языке python (и ни на каком другом), а я этот python не умею, и честно говоря не очень хочу уметь. К счастью коллеги снабдили меня обертками которые позволяют из непонятного питона запускать понятные `.sh` и прочие скрипты. Поэтому конструкция получилась двухсоставная. 
+
+Предложенное решение использует два "хука" предоставляемые крашером. Первый хук дергается при создании нового инстанса фаззера (см. `--configurator-script` в документации), и используется для создания нового снепшота с данными  хранилища, которыми будет пользоваться исследуемая программа. Второй хук дергается перед каждым новым прогоном исследуемой программы (см. `--environment-plugin` в документации), и используется для того чтобы вернуть снепшот с хранилищем в исходное состояние (ибо есть шанс что при предыдущих запусках он мог быть иземенен)  
+
+### Подготовка окружения
+
+Изначальная подготовка окружения осуществляется через скрипт `conf.py`:
+
+```python
+import json
+import os
+import sys
+import traceback
+import subprocess
+
+def transform_options(ops_json):
+    try:
+        jops = json.loads(ops_json)
+        instance_name = jops['configuration']['instance_name']
+        this_dir = os.path.dirname(__file__)
+        script_path = this_dir + '/init_script.sh'
+        pr = subprocess.Popen([script_path, instance_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        pr.wait()
+        assert pr.returncode == 0
+        output = pr.stdout.read()
+        for line in output.split():
+            ls = line.split('=')
+            assert len(ls) == 2
+            var_name = ls[0].strip()
+            var_value = ls[1].strip()
+            os.environ[var_name] = var_value
+        return json.dumps(jops)
+    except Exception as ex:
+        print("EXCEPTION!")
+        traceback.print_exc()
+        return None
+```
+Который в свою очередь вызывает скрипт `init_script.sh`:
+
+```bash
+#!/bin/bash
+
+INSTANCE_NAME=$1
+THIS_DIR=$(dirname $0)
+
+sudo ./snapshooter.pl clone mnt "${INSTANCE_NAME}"  1>&2  || exit 1
+sudo ./snapshooter.pl reset mnt "${INSTANCE_NAME}"  1>&2  || exit 1
+
+echo "PGDATA=${THIS_DIR}/mnt/$INSTANCE_NAME"
+```
+
+Скрипту `init_script.sh` в качестве аргумента передается уникальное имя инстанса фаззера, это имя скрипт использует в качестве имени создаваемого снепшота.  Кроме того на `STDOUT` скрипт выводит пары `NAME=VALUE` переменных окружения которые должны быть установлены при запуске. В нашем случае мы через переменную окружения сообщаем постгресу где находится его хранилище. Вывод скрипта анализируется оберткой  `env.py` и значения переменных окружения передаются фаззеру для последующего применения.
+
+При запуске фаззера необходимо указать расположение скрипта `conf.py` через параметр `--configurator-script `
+
+### Восстановление окружения
+Идея та же, что и с созданием окружения. Питоновская обертка `env.py`:
+
+```python
+import json
+import os
+
+error_msg = '...'
+
+def get_error():
+    return error_msg
+
+instance_name = None
+
+def init(json_options):
+    jops = json.loads(json_options)
+    global instance_name
+    instance_name = jops['configuration']['instance_name']
+    return True
+
+def finish():
+    return True
+
+def setup():
+    this_dir = os.path.dirname(__file__)
+    script_path = this_dir + '/run_script.sh'
+    cmd = script_path + ' ' + instance_name
+    r = os.system(cmd)
+    return r == 0
+
+def teardown():
+    return True
+```
+И `.sh` скрипт выполняющий содержательную работу:
+```bash
+#!/bin/bash
+
+INSTANCE_NAME=$1
+
+sudo ./snapshooter.pl reset mnt "${INSTANCE_NAME}"  1>&2 || exit 1
+```
+В данном случае мы получаем имя инстанса в качестве аргумента и восстанавливаем снепшот с этим именем в исходное состояние.
+
+При запуске фаззинга расположение файла `env.py` указывается через параметр конфигурации `--environment-plugin`
+
+### Запуск фаззинга
+Перед запуском фаззинга мы должны инициализировать хранилище снепшотов, раздать эталонному снепшоту правильные права (постгрес требует чтобы хранилище не было доступно на чтение кому либо кроме постгреса) и заполнить правильными данными. Заранее подготовленный снимок хранилища у меня лежит в директории `etalon`, я его просто копирую. Ну а дальше все достаточно просто.
+
+```bash
+#!/bin/bash
+
+ME=`whoami`
+sudo ./snapshooter.pl init mnt image.img 40000000 10
+sudo chown $ME: mnt/_reference
+chmod 700 mnt/_reference
+
+cp -r etalon/* mnt/_reference
+
+~/crushers/latest/bin_x86-64/fuzz_manager --bitmap-size 300000 --start 4 --eat-cores 1 --dse-cores 0 -i in -o out -T StdIn -F -I StaticNoForkSrv --configurator-script conf.py --environment-plugin env.py -- /home/nataraj/tests/fuzz_psql/pg/bin/postgres --single postgres
+``` 
+
+Таким образом удалось успешно запустить простейший параллельный фаззинг SQL-запросов с восстановлением состояния хранилища к исходному перед каждым запуском. На сам по себе прямой фаззинг SQL-запросов я больших надежд не возлагаю, фаззить в лоб сложные синтаксические конструкции -- малопродуктивно, однако система восстановления контекста в дальнейшем будет применена для фаззинг-исследования функциональности  потенциально приводящей к модификации хранилища postgresql. 
+
+## Приложения
+### snapshooter.pl
+```perl
+#!/usr/bin/perl
+
+use strict;
+
+my $command = shift @ARGV;
+
+die "Укажите команду первым аргументом" unless $command;
+
+if ($command eq "init")
+{
+    my $mount_path = shift @ARGV;
+    my $image_path = shift @ARGV;
+    my $snapshot_size = shift @ARGV;
+    my $snapshots_count = shift @ARGV;
+
+    unless ($image_path && $mount_path && $snapshot_size && $snapshots_count)
+    {
+      die "Команде init нужны 4 параметра: точка монтирования,путь к образу,  размер снэпшота и из кол-во";
+    }
+
+    `mountpoint -q $mount_path`;
+    unless( $?)
+    {
+        print "$mount_path -- примонтирован. Пробуем отмонтировать...\n";
+        `umount $mount_path`;
+    }
+
+    my $min_btrfs_size = 114294784;
+    if ($snapshot_size * $snapshots_count < $min_btrfs_size)
+    {
+        print "Увеличиваем размер образа до минимально возможных $min_btrfs_size байт";
+        $snapshot_size = $min_btrfs_size;
+        $snapshots_count = 1;
+    }
+
+    print "Создаем и форматируем образ...\n";
+    `dd if=/dev/zero of=$image_path count=$snapshots_count bs=$snapshot_size`;
+    `mkfs.btrfs $image_path`;
+
+    print "Монтируем образ...\n";
+    `mkdir -p $mount_path`;
+    `mount $image_path $mount_path`;
+
+    print "Создаем reference снэпшот...\n";
+    `btrfs subvolume create $mount_path/_reference`;
+}
+
+if ($command eq "clone")
+{
+    my $mount_path = shift @ARGV;
+    my $target = shift @ARGV;
+
+    unless ($target)
+    {
+      die "Команде $command нужны 2 параметра: точка монтирования, имя снэпшота";
+    }
+
+    my $name = "$mount_path/$target.base";
+
+    if (-e $name)
+    {
+        die "Снэпшот $name уже существует";
+    }
+    print "Создаю основу для снэпшота $target: $name\n";
+
+    `btrfs subvolume snapshot $mount_path/_reference $name`;
+}
+
+if ($command eq "reset")
+{
+
+    my $mount_path = shift @ARGV;
+    my $target = shift @ARGV;
+
+    unless ($target)
+    {
+      die "Команде $command нужны 2 параметра: точка монтирования, имя снэпшота";
+    }
+    my $name = "$mount_path/$target";
+    unless (-e "$name.base")
+    {
+        die "Не существует основы для снэпшота $target: $name.base";
+    }
+
+    print "Обновляю снэпшот $target: \n";
+
+    if (-e $name)
+    {
+        `rm -r $name`;
+         print "Удаляем старый\n";
+    }
+
+    print "Создаем новый\n";
+
+    `btrfs subvolume snapshot $name.base $name`;
+}
+```
+
diff --git a/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs/README.md b/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs/README.md
deleted file mode 120000 (symlink)
index 6b6c5b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Подготовка окружения для исследуемого процесса с испольнованием btrfs.md
\ No newline at end of file
diff --git a/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs/Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs.md b/SDL/2022-03 Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs/Ð\9fодгоÑ\82овка окÑ\80Ñ\83жениÑ\8f длÑ\8f иÑ\81Ñ\81ледÑ\83емого пÑ\80оÑ\86еÑ\81Ñ\81а Ñ\81 иÑ\81полÑ\8cнованием btrfs.md
deleted file mode 100644 (file)
index 5a4c820..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-# Подготовка окружения для исследуемого процесса с испольнованием btrfs
-
-**Update:** По состоянию на 2025 год, коллеги из БазАльта предложили более совершенный способ переключения между снепшотами, основанный на обращении к соответствующим системным вызовам ядра прямо из кода исследуемой программы, в самом ее начале. Это позволяет реализовать фаззинг со снепшотами каталога данных на основе свободного AFL++. Описание подхода находится [Здесь](https://www.altlinux.org/PostgreSQL16_fuzzing_technique) ([WebArchive](http://web.archive.org/web/20241203093118/https://www.altlinux.org/PostgreSQL16_fuzzing_technique))
-
-
----
-
-Часто при фаззинге сложных проектов может оказаться, что для нормальной работы каждому экземпляру исследуемой программы нужна собственная директория с данными, которую не плохо бы перед каждым новым прогоном исследуемой программы возвращать в исходное состояние. В данном посте в формате "заметок" я расскажу как мне удалось сделать восстановление окружения при фаззинге postgres'а, используя btrfs под фаззером Crusher.
-
-Для фаззига postgres'а система восстановления контекста чрезвычайно важна. Полноценный postgres не может работать без своего личного хранилища, и при этом меняет его практически на каждый чих. Без возвращения хранилища к исходному состоянию при тестировании, ни о какой воспроизводимости и речи быть не может. Поэтому как только заходит речь о фаззинг-тестировании postgres'а в сборе, необходимо сразу думать о системе восстановления контекста. 
-
-## btrfs -- файловая система со снепшотами
-
-В качестве framework'а для системы восстановления контекста была выбрана файловая система btrfs. Btrfs позволяет эффективно работать со снепшотами на уровне директорий. А именно, позволяет в рамках файловой системы получить клон указанной директории с минимальными затратами. Клонирование происходит на логическом уровне, данные по факту не копируются, и только лишь изменения внесенные в копию или в оригинал занимают дополнительное место на диске. Все это позволяет экономить время и дисковое пространство.
-
-Фаззинг, при его промышленном применении, имеет практический смысл, будучи запущенным во много потоков на многих процессорах. Для каждого инстанса фаззера, а точнее для исследуемой программы запущенной этим фаззером, предполагается создать свой собственный снепшот с уникальным именем, содержащий данные необходимые для запуска исследуемой программы, и возвращать этот снепшот к исходному состоянию перед каждым новым прогоном исследуемой программы, чтобы следы  оставленные в хранилище предыдущими прогонами не оказывали влияния на последующее..  
-
-Мной был написан скрипт `snapshooter.pl` (код приведен в конце поста) реализующий действия  со снепшотами, необходимые для фаззинга. Скрипту первым параметром передается имя команды и далее параметры которые нужны команде для работы.
-
-Ниже приведены команды и их описания:
-
-###### `init MOUNT_POINT IMAGE_FILE IMAGE_SIZE IMAGE_COUNT`
-
-Принимает 4 аргумента: точка монтирования `MOUNT_POINT`, путь к создаваемому образу файловой системы `IMAGE_FILE`, предполагаемый размер одного снепшота `IMAGE_SIZE` и ожидаемое количество снепшотов `IMAGE_COUNT`.
-
-Скрипт отмонтирует то, что было примантировано к точки монтирования, создаст новый образ файловой системы, примонтирует его к точке монтирования, и создаст в файловой системе директорию `_reference`.
-
-В эту директорию следует скопировать "эталонный" снепшот, на базе которого будут строиться снепшоты для всех экземпляров
-
-###### `clone MOUNT_POINT SNAPSHOT_NAME`
-
-Принимает два аргумента: точку монтирования `IMAGE_COUNT` и имя снэпшота `SNAPSHOT_NAME`.
-
-Команда `clone` клонирует эталонный снепшот в директорию `[SNAPSHOT_NAME].base`. Если есть потребность внести какие-то специфичные для инстанса изменения в снепшот, то это следует сделать в этой директории. В дальнейшем перед каждым запуском исследуемой программы рабочий снепшот будет приводится к "базововму" состоянию.
-
-###### `reset MOUNT_POINT SNAPSHOT_NAME`
-
-Принимает два аргумента: точку монтирования `MOUNT_POINT`и имя снэпшота `SNAPSHOT_NAME`.
-
-Команда `reset` удаляет снепшот `SNAPSHOT_NAME`, и создает новый с таким же именем клонируя  базовый снепшот `[SNAPSHOT_NAME].base`. Таким образом происходит восстановление целевого снепшота исходное состояние.
-
-В дальнейшем, для ускорения работы, планируется образ файловой системы со снепшотами перенести с диска в память, но я пока еще не разбирался как это делается.
-
-## Crusher
-
-В Crusher 2.11.0 появились инструменты позволяющие инициировать подготовку, и восстановления окружения для запускаемых процессов. К сожалению для того чтобы задействовать эти инструменты необходимо написание скриптов на языке python (и ни на каком другом), а я этот python не умею, и честно говоря не очень хочу уметь. К счастью коллеги снабдили меня обертками которые позволяют из непонятного питона запускать понятные `.sh` и прочие скрипты. Поэтому конструкция получилась двухсоставная. 
-
-Предложенное решение использует два "хука" предоставляемые крашером. Первый хук дергается при создании нового инстанса фаззера (см. `--configurator-script` в документации), и используется для создания нового снепшота с данными  хранилища, которыми будет пользоваться исследуемая программа. Второй хук дергается перед каждым новым прогоном исследуемой программы (см. `--environment-plugin` в документации), и используется для того чтобы вернуть снепшот с хранилищем в исходное состояние (ибо есть шанс что при предыдущих запусках он мог быть иземенен)  
-
-### Подготовка окружения
-
-Изначальная подготовка окружения осуществляется через скрипт `conf.py`:
-
-```python
-import json
-import os
-import sys
-import traceback
-import subprocess
-
-def transform_options(ops_json):
-    try:
-        jops = json.loads(ops_json)
-        instance_name = jops['configuration']['instance_name']
-        this_dir = os.path.dirname(__file__)
-        script_path = this_dir + '/init_script.sh'
-        pr = subprocess.Popen([script_path, instance_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        pr.wait()
-        assert pr.returncode == 0
-        output = pr.stdout.read()
-        for line in output.split():
-            ls = line.split('=')
-            assert len(ls) == 2
-            var_name = ls[0].strip()
-            var_value = ls[1].strip()
-            os.environ[var_name] = var_value
-        return json.dumps(jops)
-    except Exception as ex:
-        print("EXCEPTION!")
-        traceback.print_exc()
-        return None
-```
-Который в свою очередь вызывает скрипт `init_script.sh`:
-
-```bash
-#!/bin/bash
-
-INSTANCE_NAME=$1
-THIS_DIR=$(dirname $0)
-
-sudo ./snapshooter.pl clone mnt "${INSTANCE_NAME}"  1>&2  || exit 1
-sudo ./snapshooter.pl reset mnt "${INSTANCE_NAME}"  1>&2  || exit 1
-
-echo "PGDATA=${THIS_DIR}/mnt/$INSTANCE_NAME"
-```
-
-Скрипту `init_script.sh` в качестве аргумента передается уникальное имя инстанса фаззера, это имя скрипт использует в качестве имени создаваемого снепшота.  Кроме того на `STDOUT` скрипт выводит пары `NAME=VALUE` переменных окружения которые должны быть установлены при запуске. В нашем случае мы через переменную окружения сообщаем постгресу где находится его хранилище. Вывод скрипта анализируется оберткой  `env.py` и значения переменных окружения передаются фаззеру для последующего применения.
-
-При запуске фаззера необходимо указать расположение скрипта `conf.py` через параметр `--configurator-script `
-
-### Восстановление окружения
-Идея та же, что и с созданием окружения. Питоновская обертка `env.py`:
-
-```python
-import json
-import os
-
-error_msg = '...'
-
-def get_error():
-    return error_msg
-
-instance_name = None
-
-def init(json_options):
-    jops = json.loads(json_options)
-    global instance_name
-    instance_name = jops['configuration']['instance_name']
-    return True
-
-def finish():
-    return True
-
-def setup():
-    this_dir = os.path.dirname(__file__)
-    script_path = this_dir + '/run_script.sh'
-    cmd = script_path + ' ' + instance_name
-    r = os.system(cmd)
-    return r == 0
-
-def teardown():
-    return True
-```
-И `.sh` скрипт выполняющий содержательную работу:
-```bash
-#!/bin/bash
-
-INSTANCE_NAME=$1
-
-sudo ./snapshooter.pl reset mnt "${INSTANCE_NAME}"  1>&2 || exit 1
-```
-В данном случае мы получаем имя инстанса в качестве аргумента и восстанавливаем снепшот с этим именем в исходное состояние.
-
-При запуске фаззинга расположение файла `env.py` указывается через параметр конфигурации `--environment-plugin`
-
-### Запуск фаззинга
-Перед запуском фаззинга мы должны инициализировать хранилище снепшотов, раздать эталонному снепшоту правильные права (постгрес требует чтобы хранилище не было доступно на чтение кому либо кроме постгреса) и заполнить правильными данными. Заранее подготовленный снимок хранилища у меня лежит в директории `etalon`, я его просто копирую. Ну а дальше все достаточно просто.
-
-```bash
-#!/bin/bash
-
-ME=`whoami`
-sudo ./snapshooter.pl init mnt image.img 40000000 10
-sudo chown $ME: mnt/_reference
-chmod 700 mnt/_reference
-
-cp -r etalon/* mnt/_reference
-
-~/crushers/latest/bin_x86-64/fuzz_manager --bitmap-size 300000 --start 4 --eat-cores 1 --dse-cores 0 -i in -o out -T StdIn -F -I StaticNoForkSrv --configurator-script conf.py --environment-plugin env.py -- /home/nataraj/tests/fuzz_psql/pg/bin/postgres --single postgres
-``` 
-
-Таким образом удалось успешно запустить простейший параллельный фаззинг SQL-запросов с восстановлением состояния хранилища к исходному перед каждым запуском. На сам по себе прямой фаззинг SQL-запросов я больших надежд не возлагаю, фаззить в лоб сложные синтаксические конструкции -- малопродуктивно, однако система восстановления контекста в дальнейшем будет применена для фаззинг-исследования функциональности  потенциально приводящей к модификации хранилища postgresql. 
-
-## Приложения
-### snapshooter.pl
-```perl
-#!/usr/bin/perl
-
-use strict;
-
-my $command = shift @ARGV;
-
-die "Укажите команду первым аргументом" unless $command;
-
-if ($command eq "init")
-{
-    my $mount_path = shift @ARGV;
-    my $image_path = shift @ARGV;
-    my $snapshot_size = shift @ARGV;
-    my $snapshots_count = shift @ARGV;
-
-    unless ($image_path && $mount_path && $snapshot_size && $snapshots_count)
-    {
-      die "Команде init нужны 4 параметра: точка монтирования,путь к образу,  размер снэпшота и из кол-во";
-    }
-
-    `mountpoint -q $mount_path`;
-    unless( $?)
-    {
-        print "$mount_path -- примонтирован. Пробуем отмонтировать...\n";
-        `umount $mount_path`;
-    }
-
-    my $min_btrfs_size = 114294784;
-    if ($snapshot_size * $snapshots_count < $min_btrfs_size)
-    {
-        print "Увеличиваем размер образа до минимально возможных $min_btrfs_size байт";
-        $snapshot_size = $min_btrfs_size;
-        $snapshots_count = 1;
-    }
-
-    print "Создаем и форматируем образ...\n";
-    `dd if=/dev/zero of=$image_path count=$snapshots_count bs=$snapshot_size`;
-    `mkfs.btrfs $image_path`;
-
-    print "Монтируем образ...\n";
-    `mkdir -p $mount_path`;
-    `mount $image_path $mount_path`;
-
-    print "Создаем reference снэпшот...\n";
-    `btrfs subvolume create $mount_path/_reference`;
-}
-
-if ($command eq "clone")
-{
-    my $mount_path = shift @ARGV;
-    my $target = shift @ARGV;
-
-    unless ($target)
-    {
-      die "Команде $command нужны 2 параметра: точка монтирования, имя снэпшота";
-    }
-
-    my $name = "$mount_path/$target.base";
-
-    if (-e $name)
-    {
-        die "Снэпшот $name уже существует";
-    }
-    print "Создаю основу для снэпшота $target: $name\n";
-
-    `btrfs subvolume snapshot $mount_path/_reference $name`;
-}
-
-if ($command eq "reset")
-{
-
-    my $mount_path = shift @ARGV;
-    my $target = shift @ARGV;
-
-    unless ($target)
-    {
-      die "Команде $command нужны 2 параметра: точка монтирования, имя снэпшота";
-    }
-    my $name = "$mount_path/$target";
-    unless (-e "$name.base")
-    {
-        die "Не существует основы для снэпшота $target: $name.base";
-    }
-
-    print "Обновляю снэпшот $target: \n";
-
-    if (-e $name)
-    {
-        `rm -r $name`;
-         print "Удаляем старый\n";
-    }
-
-    print "Создаем новый\n";
-
-    `btrfs subvolume snapshot $name.base $name`;
-}
-```
-