HighLoad++ 2017
Зал «Рио-де-Жанейро», 8 ноября, 10:00
Тезисы:
http://www.highload.ru/2017/abstracts/2975.html
Все мы слышали про изменение кода ядра Linux на лету (kernel live patching). Но кто-нибудь проводит подобные фокусы в user space? Оказалось, что да. Мы тоже попробовали.
И получилось.
Длинная дорога технологии Userspace Live Patching в жизнь:
Что такое Live Patching
1) Изменение части логики процесса.
2) Сохранение состояния процесса.
3) Делать 1+2 БЕЗОПАСНО.
...
2. Обзор
➢ Что такое “Live Patching”?
➢ Для чего это нужно?
➢ Состояние процесса
➢ Что мы можем патчить?
➢ Когда патч может быть приложен?
➢ Структура бинарного патча
➢ Динамические библиотеки
➢ Символы ELF
➢ Приложение патча
➢ Создание патча
2
3. Что такое “Live Patching”?
➢ Замена части “логики” в процессе
➢ Сохраняя состояние процесса
➢ Делая это безопасно
3
4. Для чего это нужно?
➢ Уменьшение времени простоя из-за критических уязвимостей за счёт:
➢Отсутствия рестарта сервисов
➢Нет необходимости в миграции
➢ Примеры утилит для live patching:
➢Kpatch, Kgraft, Ksplice для ядра
➢Pannus, Ksplice, LibCare для юзерспейса
4
5. Состояние процесса
➢ “Карточный домик”:
➢части сильно связаны между собой
➢ Изменяется во время выполнения
➢ Состоит из:
➢Статически выделенных переменных
➢Динамически выделенных переменных
➢Стека
5
6. Что мы можем патчить?
➢ Не любые изменения кода
➢ Фундаментальные ограничения:
➢Изменившийся размер данных
➢Другой порядок полей в структуре
➢ Требуется ревью кода :(
6
7. Когда патч может быть приложен?
➢ Требуется остановка процесса
➢ Не в любой момент времени:
➢Изменяемый код может выполняться
➢На него могут быть ссылки на стеке
➢ Необходим анализ стека:
➢ “поймать” процесс в “подходящем” месте
7
8. Когда патч может быть приложен?
8
g(void)
{
. . .
f();
}
f(void)
{
. . .
}
9. Когда патч может быть приложен?
9
g(void)
{
. . .
f();
}
f(void)
{
. . .
}
Поток остановлен здесь
10. Когда патч может быть приложен?
10
g(void)
{
. . .
f();
}
f(void)
{
. . .
}
Поток остановлен здесь
f()Вызывается новая версия
11. Когда патч может быть приложен?
11
g(void)
{
. . .
f();
}
f(void)
{
. . .
}
Поток остановлен здесь
f()Вызывается новая версия
,Возврат по адресу
сохранённому на стеке
12. Когда патч может быть приложен?
12
g(void)
{
. . .
f();
}
f(void)
{
. . .
}
Поток остановлен здесь
f()Вызывается новая версия
Исполняется код
старой версии f()
,Возврат по адресу
сохранённому на стеке
13. Структура бинарного патча
➢ Код заменяется на уровне функций:
➢Надёжно
➢Просто
➢ Формат: ELF dynamic shared object
➢Загружается в адресное пространство процесса
➢Дополнительная секция с метаданными
➢ Список адресов символов
➢ build-id
13
37. Заключение
➢ Требуется ревью кода :)
➢ Используется стандартное ядро!
➢ Бинарники собираются как обычно!
➢ Libcompel используется для:
➢Останова процесса
➢Перезапуска процесса
➢Загрузки кода патча
➢Source: https://github.com/xemul/criu/tree/criu-dev
37
38. Заключение
➢ Требуется ревью кода :)
➢ Используется стандартное ядро!
➢ Бинарники собираются как обычно!
➢ Libcompel используется для:
➢Останова процесса
➢Перезапуска процесса
➢Загрузки кода патча
➢Source: https://github.com/xemul/criu/tree/criu-dev
➢ Libunwind используется для анализа стека
➢Source: http://git.savannah.gnu.org/cgit/libunwind.git
38
39. Заключение
➢ Требуется ревью кода :)
➢ Используется стандартное ядро!
➢ Бинарники собираются как обычно!
➢ Libcompel используется для:
➢Останова процесса
➢Перезапуска процесса
➢Загрузки кода патча
➢Source: https://github.com/xemul/criu/tree/criu-dev
➢ Libunwind используется для анализа стека
➢Source: http://git.savannah.gnu.org/cgit/libunwind.git
➢ Source: https://github.com/virtuozzo/nsb
39