LINUX.ORG.RU

out-of-tree v1.0.0 ― инструментарий для разработки и тестирования эксплоитов и модулей ядра Linux

 , , , ,


2

3

Состоялся релиз первой (v1.0.0) версии out-of-tree ― инструментария для разработки и тестирования эксплоитов и модулей ядра Linux.

out-of-tree позволяет автоматизировать некоторые рутинные действия по созданию окружений для отладки модулей ядра и эксплоитов, генерации статистики надежности эксплоитов, а также предоставляет возможность простой интеграции в CI (Continuous Integration).

Каждый модуль ядра либо эксплоит описывается файлом .out-of-tree.toml, где указывается информация о необходимом окружении и (в случае, если это эксплоит) о ограничениях работы при наличии определенных мер безопасности (security mitigations).

Также инструментарий позволяет определять конкретные версии ядра, затронутые уязвимостью (с помощью команды --guess), а также может использоваться для упрощения бинарного поиска конкретного коммита.

Далее список изменений со времен версии v0.2.

Добавлено

  • Реализована возможность ограничивать количество генерируемых (out-of-tree kernel autogen) ядер (на основе описания в .out-of-tree.toml) и запусков проверки (out-of-tree pew) c помощью параметра --max=X.

  • Новая команда genall, позволяющая сгененировать все ядра для определенного дистрибутива и версии.

  • Все логи теперь хранятся в sqlite3 базе данных. Реализованы команды для простых часто необходимых запросов, а также экспорт данных в json и markdown.

  • Реализован подсчет вероятности успешной эксплуатации (на основе предыдущих запусков).

  • Возможность сохранять результаты сборки (новый параметр --dist для команды out-of-tree pew)

  • Поддержка генерации метаданных для ядер, установленных в хостовой системе, а также сборка непосредственно на хосте.

  • Поддержка сторонних ядер.

  • Теперь отладочное окружение (out-of-tree debug) автоматически ищет отладочные символы на хостовой системе.

  • Добавлена возможность управления мерами безопасности (security mitigations) флагами включения/отключения KASLR, SMEP, SMAP и KPTI во время отладки.

  • Добавлен параметр --threads=N для команды запуска тестирования out-of-tree pew, с помощью которого можно указать количество потоков, в которых будет выполняться сборка/запуск и тестирование эксплоитов и модулей ядра.

  • Возможность задать тег, который будет записываться в лог и далее может использоваться для расчета статистики.

  • Добавлена возможность указать версию ядра без использования регулярных выражений.

  • Новая команда pack, используемая для массовых тестов эксплоитов и модулей ядра в поддиректориях.

  • В конфигурации (.out-of-tree.toml) для эксплоита и модуля ядра добавлена возможность отключать KASLR, SMEP, SMAP и KPTI, а также указывать необходимое количество ядер и памяти.

  • Теперь образы (rootfs) загружаются автоматически во время работы kernel autogen. bootstrap больше не нужен.

  • Поддержка ядер CentOS.

Изменения

  • Теперь, если нет образа (rootfs) для нужной версии дистрибутива ― out-of-tree будет пытаться использовать образ наиболее близкой версии. Например, образ Ubuntu 18.04 для Ubuntu 18.10.

  • Теперь тесты для модулей ядра не будут считаться провальными в том случае, если они отсутствуют (нет тестов ― нет ошибок!).

  • Теперь out-of-tree будет возвращать отрицательный код ошибки в том случае, если хотя бы один этап (сборка, запуск или тестирование) на любом из ядер был завершен с ошибкой.

  • Проект перешел на использование Go modules, сборка с GO111MODULE=on теперь предпочтительна.

  • Добавлены тесты по умолчанию.

  • Теперь test.sh будет использован по умолчанию в том случае, если сборка в ${TARGET}_test не реализована в Makefile.

  • Лог ядра более не очищается перед запуском модуля ядра или эксплоита. Некоторые из эксплоитов используют утечку базы ядра в dmesg для обхода KASLR, поэтому очистка может нарушить реализованную логику эксплоита.

  • qemu/kvm теперь использует все возможности хостового процессора.

Удалено

  • Фабрика ядер убрана полностью в связи с реализацией генерации ядер на основе инкрементально дополняемых Dockerfile.

  • bootstrap более ничего не делает. Команда будет удалена в следующем релизе.

Исправлено

  • На macOS более не требуется GNU coreutils для работы.

  • Временные файлы перенесены в ~/.out-of-tree/tmp/ из-за ошибок монтирования внутри docker на некоторых системах.

>>> Документация

>>> CHANGELOG

>>> Подробности

Deleted

Проверено: Dimez ()

Теперь тесты для модулей ядра не будут считаться провальными в том случае, если они отсутствуют (нет тестов ― нет ошибок!).

Прагматично

kto_tama ★★★★★ ()

mask := «4[.]4[.]0-(1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|47|48|49|50|51|52|53|54|55|56|57|58|59|60|61|62|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116)-.*»

Уахаха)

Писец сколько в этом го бойлерплейта, безотносительно вышеуказанного регекспа.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Это не они такие, это ты их не туда суёшь.

Для пакетов ядра нет общей схемы именования версий (например, у Ubuntu пакет ядра «3.13.0-113-generic», у CentOS ― «3.10.0-123.1.2.el7.x86_64», а в некоторых случаях, внезапно ― версии и вообще может не быть), поэтому нужно было сделать возможность указывать в .out-of-tree.toml нужную версию вне зависимости от того, правильно ли я распарсил конкретную версию в каком-то из дистрибутивов.

Если использовать не регулярные выражения для этого, то тогда что?

Deleted ()
Ответ на: комментарий от Deleted

Если использовать не регулярные выражения для этого, то тогда что?

Я бы парсер на каком-нибудь parsec накидал. Работы на 5 минут и код куда вменяемее выходит. Но, я так понимаю, для голанга аналога parsec не сделали.

P.S. goparsec таки есть, но выглядит так, что мои глаза закровоточили.

hateyoufeel ★★★★★ ()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Я бы парсер на каком-нибудь parsec накидал. Работы на 5 минут и код куда вменяемее выходит. Но, я так понимаю, для голанга аналога parsec не сделали.

Есть goparsec, не знаю насколько он полный аналог, но пишут, что где-то в production используют.

Deleted ()
Ответ на: комментарий от Deleted

Естьь goparsec, не знаю насколько он полный аналог, но пишут, что где-то в production используют.

Выглядит он как лютая срань. Я не уверен, что хотел бы такой код вообще видеть.

hateyoufeel ★★★★★ ()
Ответ на: комментарий от Deleted

Если использовать не регулярные выражения для этого, то тогда что?

Тебе же где-то в другой теме писали, что регекспами вытаскиваешь части (версия,мажор,минор и другие интересные части), и над этими частями городишь свою логику на «родном» языке: сравнения, в том числе лексикографические, диапазоны и др.

Набросок (недоперл)

# Собираем/генерируем регулярное выражение. А что так можно было?!
reVersion = '(\d+)' # можно именованные группы '(?<version>\d+)'
reMajor = '(\d+)' # '(?<major>\d+)'
reMinor = '(\d+)' # сам догадаешься
reCustom = '(.*)'
re="$reVersion[.]$reMajor[.]$reMinot(-$reCustom)?" # (?<version>\d+)[.](?<major>\d+)[.](?<major>\d+)(-(.*))?
# проверяем и вытаскиваем (именованные) части
linux_version =~ m/$re/ 
# можно вытаскивать по индексам, можно - по именам
version = $1
# или
version = $+{version}
...

minorRange = [0..111] # берем из конфига
if ( $minor `in` $minorRange ) { ... }
# можно более сложную логику
if ( $minor = 10 && custom = 'gentoo' ) { ... }
anonymous ()
Ответ на: комментарий от Deleted

Писец сколько в этом го бойлерплейта, безотносительно вышеуказанного регекспа.

Он еще на раст хотел переписать. Представь, еще сколько бойлерплейта было бы, чтобы «обмануть» всякие боров-чекеры.

anonymous ()
Ответ на: комментарий от anonymous

«А что так можно было?!»

Если бы ты внимательно прочитал новость, то понял бы, что вариант с генерацией регулярного выражения на основе указанной в конфиге версии и был реализован.

Deleted ()
Ответ на: комментарий от Deleted

вариант с генерацией регулярного выражения

:) Кто во что горазд. Кто-то пытается генерить (тьюринг-полные) циклы на регулярках. Кто-то генерит регулярки для того, чтобы просто вытащить термы-символы, над которыми городит сложную (тьюринг-полую) логику.

anonymous ()
Ответ на: комментарий от Deleted

Это же просто автоматизация. Выбор Го здесь ничем не продиктован, кроме твоего желания его изучить. Достоинства го, вроде горутин, чего там ещё, нэйтив, здесь побоку. Зато выразительности не хватает: туча бойлерплейта и закатывания солнц вручную.

anonymous ()
Ответ на: комментарий от Deleted

Почему ты так решил? Я уже знал Go на момент начала проекта.

Предположил из за того, что

Достоинства го, вроде горутин, чего там ещё, нэйтив, здесь побоку. Зато выразительности не хватает: туча бойлерплейта и закатывания солнц вручную.

Так что или так, или выбрал короткий путь: тот который знаешь.

Неважно. Цимес в том, что Го для «клея» так себе подходит. Но всё познаётся в сравнении, конечно.

Я бы самоубился, если б пришлось для автоматизации писать такой бойлерплейт:

// Start qemu process
func (q *QemuSystem) Start() (err error) {
	q.cmd = exec.Command("qemu-system-"+string(q.arch),
		// TODO
		"-snapshot",
		"-nographic")

	if q.pipe.stdin, err = q.cmd.StdinPipe(); err != nil {
		return
	}

	if q.pipe.stdout, err = q.cmd.StdoutPipe(); err != nil {
		return
	}

	if q.pipe.stderr, err = q.cmd.StderrPipe(); err != nil {
		return
	}

	err = q.cmd.Start()
	if err != nil {
		return
	}

	go func() {
		q.Stdout, _ = readUntilEOF(q.pipe.stdout)
		q.Stderr, _ = readUntilEOF(q.pipe.stderr)
		q.exitErr = q.cmd.Wait()
		q.died = true
	}()

	time.Sleep(time.Second / 10) // wait for immediately die

	if q.died {
		err = errors.New("qemu died immediately: " + q.Stderr)
	}

	return
}

Даже IDE не спасла бы.

Deleted ()
Последнее исправление: Deleted (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

удивительно, но там никто даже похожего на правильное решение не написал; неужели лор так измельчал за последние несколько лет?

вот регекс до 116 если без учета ведущих нулей:

/^ 11[0-6] | 10\d | \d{1,2} $/x

# www_linux_org_ru

anonymous ()

Для защиты от бяки написанной с помощью сабжа:

CONFIG_GRKERNSEC_IO=y. (https://en.m.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options)

--- Enable loadable module support (https://wiki.gentoo.org/wiki/Signed_kernel_module_support)
[*]   Module signature verification
[*]     Require modules to be validly signed
[*]     Automatically sign all modules
      Which hash algorithm should modules be signed with? (Sign modules with SHA-512) --->

IMA/EVM крыптографически верифицирует все начиная с init, включая все подгружаемые модули ядра (https://sourceforge.net/p/linux-ima/wiki/Home/)

GRUB крыптографичеси верифицирует кроме своих модулей и настроек, так же и ядро Линукс, инитрамфс и модули ядра Линукс которые в нём находятся (https://www.gnu.org/software/grub/manual/grub/grub.html#Using-digital-signatures)

anonymous ()