Meltdown и Spectre: первые рабочие дни года - инвентаризация, патчи, просадка производительности
CVE-2017-5754 (Meltdown) и CVE-2017-5753/5715 (Spectre) опубликованы 3 января. Оцениваем парк серверов, патчим ядра Linux, смотрим что происходит с базами данных.
Публикация CVE-2017-5754 (Meltdown) и CVE-2017-5753/5715 (Spectre) 3 января 2018 - аппаратные уязвимости в механизме спекулятивного выполнения процессоров Intel, AMD и ARM
Новый год начался с подарка. 3 января публикуют CVE-2017-5754, CVE-2017-5753 и CVE-2017-5715 - Meltdown и Spectre. Аппаратные уязвимости в механизме спекулятивного выполнения, затрагивающие процессоры Intel (Meltdown - почти все выпущенные за последние десять лет), AMD и ARM (Spectre). Механика - атакующий из пространства пользователя может читать содержимое памяти ядра. В облачной среде - потенциально данные соседнего арендатора.
У нас в тот момент праздничный режим, половина команды в отпуске. Но это из серии «отложить нельзя».
Что вообще произошло
Meltdown (CVE-2017-5754) - уязвимость в процессорах Intel, позволяющая пользовательскому процессу читать произвольную память ядра. Закрывается патчем ядра - технология называется KPTI (Kernel Page-Table Isolation), она изолирует таблицы страниц ядра от пространства пользователя. Цена - дополнительный syscall overhead, который зависит от нагрузки.
Spectre (CVE-2017-5753 и CVE-2017-5715) - другая механика, основана на side-channel через branch predictor. Закрывается сложнее: частично патчами компилятора, частично микрокодом CPU, частично изменениями в ядре. И AMD, и Intel, и ARM под угрозой в разной степени.
К моменту публикации CVE патчи для Linux ядра уже готовы - ветки 4.14, 4.9 и 4.4 получили KPTI до публичного раскрытия. Дистрибутивы на подходе.
Инвентаризация: что у нас вообще есть
Первый шаг - понять масштаб. Наш парк серверов у клиентов неоднородный: RHEL 6 и 7, Debian 8 и 9, Ubuntu 14.04 и 16.04, несколько VMware-кластеров. Плюс облачные инстансы - AWS и несколько арендованных серверов у европейских провайдеров.
Собираем список: что на каком ядре, когда последний раз обновлялось. Картина ожидаемо грустная: часть серверов не обновлялась с лета, у одного клиента вообще RHEL 6 с ядром 2.6.32, которое в стоке, без backport-патча, закрыть будет нетривиально.
Версии ядра сами по себе не дают полный ответ на «под угрозой или нет» - важно, применён ли KPTI. Проверяем:
dmesg | grep -i "page table isolation"
cat /sys/devices/system/cpu/vulnerabilities/meltdown
Второй файл появился чуть позже с обновлёнными ядрами - удобный способ проверить статус прямо из userspace.
Патчим
Дистрибутивы выкатывают патчи быстро. Ubuntu 16.04 получил обновлённое ядро 4.4.0-108 через несколько дней после раскрытия. RHEL 7 - соответствующий backport в 3.10.0-693. Debian 9 - 4.9.65.
Алгоритм стандартный для такого случая:
- Сначала staging. Обновляем ядро на тестовых серверах, перезагружаем, проверяем что всё поднялось.
- Потом production по одному. Серверы баз данных - в последнюю очередь, после того как посмотрели на поведение.
- Автоматизация через Ansible.
yum update kernelилиapt-get dist-upgrade, потомrebootс ожиданием. Playbook несложный, но важно что он логирует время каждого шага - потом понадобится.
Проблем с загрузкой не было. На VMware пришлось обновить и гипервизоры - vSphere выпустил патчи для ESXi почти одновременно, но это отдельный процесс с обслуживанием кластера.
Производительность баз данных: смотрим внимательно
Вот это место оказалось интереснее, чем ожидалось. KPTI добавляет overhead на каждый системный вызов - а базы данных делают системных вызовов очень много. PostgreSQL и MySQL активно используют read(), write(), fsync(), сетевые вызовы. Каждый из них теперь стоит чуть дороже за счёт смены контекста таблиц страниц.
Конкретные цифры мы мерить не торопились - слишком много переменных, и сравнивать «до патча / после патча» в production без подготовленного бенчмарка - метод ненадёжный. Но ряд наблюдений сделали:
pgbench на тестовом PostgreSQL 9.6 показал заметное падение TPS на OLTP-нагрузке с короткими транзакциями. Логично - именно они делают больше всего syscall'ов на единицу полезной работы. Чем тяжелее и длиннее транзакция, тем меньше относительный overhead.
MySQL под InnoDB вёл себя похоже. Самую большую разницу увидели на воркload'е типа «много мелких SELECT'ов» - что характерно для приложений с ORM и N+1 запросами.
Нагрузка на CPU вверх - ожидаемо. KPTI требует сброса TLB при переключении контекстов, это процессорное время. На серверах с HT это немного смягчается.
Клиентам с критичными по latency базами данных рекомендовали запустить свои бенчмарки до раскатки в production и после - чтобы понять именно их дельту, а не ориентироваться на чужие цифры из интернета. Рабочие нагрузки разные.
Где стоим сейчас
К концу первой недели января все production-серверы под нашим управлением получили патчи ядра. По Meltdown - закрыто. По Spectre - сложнее: CVE-2017-5715 требует ещё и обновления микрокода Intel, которого на момент написания поста для части процессоров нет или оно ещё не добралось до всех вендоров. Следим.
Spectre CVE-2017-5753 частично закрывается компиляторными патчами - retpoline и co. - но это история для следующего апдейта.
Один практический вывод уже сейчас: аудит с инвентаризацией парка и версий ядер - это не разовая история перед сертификацией. Ситуация когда за три дня нужно понять что вообще крутится и в каком состоянии - нормальная при таких инцидентах. Организации, у которых CMDB живая, а не декоративная, справились с инвентаризацией за пару часов. Остальные разбирались вручную.