Русский
Русский
English
Статистика
Реклама

Блог компании virtuozzo

Мониторинг Virtuozzo Hybrid Server с помощь Prometheus

01.06.2021 14:09:01 | Автор: admin

Пользователи продуктов Virtuozzo и OpenVZ обычно работают с множеством развернутых машин под управлением нашего ПО. Поэтому для них логично запустить централизованный мониторинг всего парка таких серверов. И сегодня мы расскажем о том, как использовать для этого встроенные сервисы мониторинга Virtuozzo Hybrid Infrastructure на основе Prometheus.

Схожие сервисы доступны и в VHS, но только если вы используете графические интерфейс для управления кластером Virtuozzo Storage. Если же у вас нет кластера Storage, или вы не используете GUI для его администрирования (либо работаете с OpenVZ, где подключение Virtuozzo Storage является возможным, но редко встречающимся сценарием), то для мониторинга приходится обращаться к сторонним решениям.

Анализ предпочтений пользователей (публично доступный для OpenVZ здесь) показывает следующее: как и для мониторинга серверов с Linux и основанных на нем решениями, для продуктов Virtuozzo популярны Zabbix и Prometheus.

Мы поговорим сегодня про Prometheus более молодой, но активно набирающий популярность инструментарий.

Непосредственно Prometheus занимается сбором данных от подвластных ему экспортеров - в репозиториях VHS доступны node_exporter (для сбора общих характеристик сервера, таких как использование ресурсов и состояние дисков) и libvirt_exporter (для сбора информации о виртуальных машинах, управляемых libvirt). Экспортеры основаны на соответствующих стандартных проектах, но содержат ряд специфичных для Virtuozzo изменений.

Для удобного изучения собираемой информации, в связке с Prometheus обычно устанавливается инструментарий визуализации данных Grafana, а для возможности получения оповещений о требующих внимания администратора событиях Alertmanager.

Готовим плацдарм

Prometheus, Grafana и Alertmanager можно развернуть на отдельной машине, не обязательно физической. Раз уж мы говорим о Virtuozzo Hybrid Server, то логично развернуть их внутри контейнера на одной из машин VHS. Например, внутри контейнера с Virtuozzo Linux 8; для функционирования вполне достаточно двух ядер ЦПУ и пары гигабайт памяти:

# prlctl create promct --vmtype=ct --ostemplate=vzlinux-8-x86_64# prlctl set promct --cpu 2# prlctl set promct --memsize 2G

Не забудьте выставить необходимый IP адрес и доменное имя, по которым будет доступен ваш контейнер.

Внутри контейнера не помешает выставить правильный часовой пояс:

# timedatectl set-timezone 'Europe/Moscow'

А также настроить firewall порт 9090 для веб-интерфейса Prometheus, 9093 для AlertManager и 3000 для Grafana. Обратите внимание, что веб Prometheus и Alertmanager доступны без пароля, так что выставляйте их только в ваши внутренние сети.

# firewall-cmd --zone=public --permanent --add-port=9090/tcp# firewall-cmd --zone=public --permanent --add-port=9093/tcp# firewall-cmd --zone=public --permanent --add-port=3000/tcp# firewall-cmd --reload

Устанавливаем Prometheus & co.

Prometheus входит в репозитории многих дистрибутивов, в том числе и Virtuozzo Linux 8, поэтому можно его установить штатными средствами:

# yum install prometheus

Если вас не устраивает версия из дистрибутива (например, хочется самую свежую, либо наоборот - свежая имеет какие-то раздражающие вас проблемы), то можно просто скачать бинарные файлы с GitHub и положить их в директорию /opt (или в другую на ваш выбор). Например, для версии 2.21.0:

# cd /opt# wget https://github.com/prometheus/prometheus/releases/download/v2.21.0/prometheus-2.21.0.linux-amd64.tar.gz# tar -xzf prometheus*.tar.gz

Единственный нюанс при ручной установке - не забыть создать (либо скорректировать) service-файл для systemd, чтобы там были правильные пути:

# cat /lib/systemd/system/prometheus.service[Unit]Description=PrometheusWants=network-online.targetAfter=network-online.target[Service]Type=simpleWorkingDirectory=/opt/prometheus-2.21.0.linux-amd64Restart=on-failureExecStart=/opt/prometheus-2.21.0.linux-amd64/prometheus[Install]WantedBy=multi-user.target

Аналогично с Alertmanager - можно установить из репозиториев:

# yum install alertmanager

... А можно и с сайта, точно также не забыв service-файл:

# wget https://github.com/prometheus/alertmanager/releases/download/v0.21.0/alertmanager-0.21.0.linux-amd64.tar.gz# cd /opt# tar -xzf alertmanager*.tar.gz# cat /usr/lib/systemd/system/alertmanager.service[Unit]Description=AlertmanagerWants=network-online.targetAfter=network-online.targetAfter=prometheus.service[Service]Type=simpleWorkingDirectory=/root/alertmanager-0.21.0.linux-amd64Restart=on-failureExecStart=/root/alertmanager-0.21.0.linux-amd64/alertmanager --config.file=alertmanager.yml[Install]WantedBy=multi-user.target

Grafana сразу предоставляет собранные rpm-пакеты, так что можно, опять же, поставить либо из дистрибутива:

# yum install grafana

либо с сайта проекта:

# yum install https://dl.grafana.com/oss/release/grafana-7.1.5-1.x86_64.rpm

Подготавливаем машины с Virtuozzo Hybrid Server

На каждом сервере VHS, который предполагается мониторить, необходимо установить пакеты с экспортерами:

# yum install node_exporter libvirt_exporter

Чтобы экспортеры могли отдавать данные в Prometheus, необходимо открыть соответствующие порты - 9177 для libvirt_exporter и 9100 для node_exporter. Доступ к ним желательно ограничить адресом машины с Prometheus, чтобы посторонние люди не делали попыток снять метрики с ваших серверов:

# firewall-cmd --permanent --zone=public --add-rich-rule=' rule family="ipv4" source address="1.2.3.4/32" port protocol="tcp" port="9177" accept'# firewall-cmd --permanent --zone=public --add-rich-rule=' rule family="ipv4" source address="1.2.3.4/32" port protocol="tcp" port="9100" accept'# firewall-cmd --reload

Здесь "1.2.3.4" необходимо поменять на реальный адрес Prometheus.

Наконец, смело включаем и запускаем сервисы экспортеров:

# systemctl enable node_exporter# systemctl enable libvirt-exporter# systemctl start node_exporter# systemctl start libvirt-exporter

Дело за малым - надо сообщить Прометею, откуда ему собирать информацию.

Настройка Prometheus

Конфигурация самого Prometheus содержится в наборе Yaml-файлов. Писать их с нуля, даже с помощью примеров из документации то еще развлечение. Именно этот процесс и решили улучшить в Virtuozzo, положив в репозитории VHS 7 пакет vz-prometheus-cfg с шаблонами файлов конфигурации. Его можно установить на любой машине VHS 7, а если вы развернули Prometheus внутри VzLinux 8 то можно его поставить прямо на сервере из репозиториев этого дистрибутива:

# yum install vz-prometheus-cfg

После чего изучать директорию /usr/share/vz-prometheus-cfg/, начав с файла prometheus-example.yml.

Этот файл необходимо отредактировать под ваши нужды и под именем prometheus.yml сохранить в машину или контейнер, где у вас расположен Prometheus. Главное, что там необходимо изменить это местоположение файлов *rules.yml и *alerts.yml, которые также можно скопировать из директории /usr/share/vz-prometheus-cfg/ на сервер Prometheus. Можно их изучить и даже отредактировать, однако они вполне работоспособны и в исходном варианте.

В первую очередь здесь интересны vz-rules, содержащие правила сбора информации о потреблении ресурсов (диска, процессора, памяти и сети) виртуальными окружениями и предупреждения о проблемах с ресурсами (останов ВМ из-за ошибки диска, исчерпание диска на сервере и тому подобное).

Непосредственно машины, с которых надо собирать информацию, указываются в target-файлах. В первом приближении достаточно одного такого файла со списком машин для каждого экспортера (напомним, node_exporter отдает информацию на порту 9100, а libvirt - 9177):

# cat my-vz-libvirt.yml- labels: group: my-vz-deployment targets: - my.node1:9177 - my.node2:9177# cat my-vz-node.yml- labels: group: my-vz-deployment targets: - my.node1:9100 - my.node2:9100

Пути к этим файлам необходимо указать в соответствующих разделах секции scrape_configs в prometheus.yml:

scrape_configs: ... - job_name: node ... file_sd_configs: - files: - /root/prometheus-2.21.0.linux-amd64/targets/my-vz-node.yml - job_name: libvirt ... file_sd_configs: - files: - /root/prometheus-2.21.0.linux-amd64/targets/my-vz-libvirt.yml

Пример полного файла конфигурации можно посмотреть в документации: https://docs.virtuozzo.com/virtuozzo_hybrid_server_7_users_guide/advanced-tasks/monitoring-via-prometheus.html. Обратите внимание, что важными параметрами являются job_name на них идет отсылка в файлах с правилами и алертами. Так что если задумаете менять эти имена не забудьте пройтись и по другим файлами конфигурации и провести соответствующие замены.

Как только все необходимые файлы отредактированы - пора стартовать сервисы:

# systemctl start prometheus# systemctl start alertmanager# systemctl start grafana-server

После чего продолжать уже с настройкой двух других инструментов

Grafana и Alertmanager

Конфигурация Grafana осуществляется через ее веб-интерфейс по адресу http://<ваш-сервер>:3000. Логин-пароль по умолчанию - "admin" / "admin".

Настройка достаточно проста и стандартна - сначала необходимо указать "Prometheus" как источник данных, пройдя в Configuration -> Data Sources -> "Add data source", выбрав "Prometheus" и указав http://localhost:9090 в качестве его адреса.

Далее можно импортировать готовые json-файлы, опять же поставляемые с пакетов vz-prometheus-cfg - grafana_hn_dashboard.json и grafana_ve_dashboard.json - служащие соответственно для отображения информации о серверах и о виртуальных окружениях. Импорт осуществляется в меню "Dashboards" -> "Manage" -> "Import", в качестве источника данных необходимо добавить настроенный ранее Prometheus.

И, вуаля, к этому моменту Prometheus уже вполне мог получить какие-то данные с ваших машин, так что можно практически сразу изучать графики.

Наконец, настройка оповещений Alertmanager тут все на ваше усмотрение, готовых рецептов а-ля отправить отчет в саппорт Virtuozzo не предусмотрено. Так что можно, например, просто настроить типичные оповещения по email в /etc/alertmanager/alertmanager.yaml:

route:   receiver: 'email'  group_by: ['alertname', 'cluster']   group_wait: 30s   group_interval: 5m   repeat_interval: 3h   receivers:  - name: 'email'   email_configs:   - to: 'admin@myserver.com'   from: 'vz-alert@myserver.com'   smarthost: smtp.myserver.com:587

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

Надеемся, обилие и нетривиальность параметров не отпугнет вас от использования Prometheus. Тем более что настроить его достаточно один раз, а шаблоны от Virtuozzo должны в этом неплохо помочь. В результате вы получаете красивую, удобную и функциональную систему мониторинга, без которой современному системному администратору будет намного сложнее работать.

Подробнее..

CVE и квадратная вероятность

29.07.2020 12:21:28 | Автор: admin
Приблизительно год назад, с июля 2019 года нам в OpenVz начали поступать странные багрепорты на RHEL7-based kernel. На первый взгляд баги были разными: ноды крашились в разных местах и даже в разных подсистемах, но каждый раз расследование обнаруживало тот или иной кривой объект. Объекты были разными, иногда там обнаруживался какой-то мусор, иногда ссылка в освобожденную память, иногда сам объект оказывался освобожден, но во всех случаях память под этот объект выделялась из kmalloc-192 cache. Под катом подробный рассказ про эту историю.

image


Обычный траблшутинг в таких случаях внимательно исследовать жизненный цикл пострадавшего объекта: посмотреть, как под него выделяется память, как она освобождается, насколько правильно берутся и отпускаются reference counters, обращая особое внимание на error-пути. Однако в нашем случае карраптились разные объекты, и проверка их жизненного цикла багов не обнаруживала.

kmalloc-192 cache довольно популярен в ядре, он объединяет несколько десятков различных объектов. Ошибка в жизненном цикле одного из них наиболее вероятная причина такого рода багов. Даже просто перечислить все такие объекты довольно проблематично, а о том, чтобы все их проверить, даже речи не идет. Багрепорты продолжали поступать, а обнаружить их причину расследованием в лоб нам так и не удавалось. Требовалась подсказка.

С нашей стороны эти баги расследовал Андрей Рябинин, специалист по memory management, широко известный в узких кругах kernel developers как разработчик KASAN офигительной технологии ловли ошибок обращения к памяти.



В сущности, именно KASAN наилучшим образом подходил для обнаружения причин нашего бага.

В оригинальный RHEL7 kernel KASAN не вошел, однако Андрей портировал необходимые патчи к нам в OpenVz. В боевую версию нашего ядра мы KASAN не включили, но в debug-версии ядра он присутствует и активно помогает нашему QA в поиске багов.

В debug-ядро помимо KASAN включено множество других debug фич, унаследованных нами от Red Hat. В результате debug ядро получилось довольно медленным. QA говорит, что те же самые тесты на debug ядре идут в 4 раза дольше. Для нас это непринципиально, мы там не performance измеряем, а баги ищем. Однако для клиентов такой slowdown оказывался неприемлемым, и наши просьбы проставить debug ядро в production неизменно отклонялись.

В качестве альтернативы KASAN клиентов просили включить на пострадавших нодах slub_debug. Эта технология также позволяет выявлять memory corruption. Используя для каждого объекта red zone и memory poisoning, memory allocator при каждом выделении и освобождении памяти проверяет, все ли в порядке. Если что не так, он выдает error message, по возможности исправляет обнаруженные повреждения и позволяет ядру продолжать работу. Кроме того, сохраняется информация о том, кто в последний раз аллоцировал и освобождал объект, так что в случае post-factum обнаружения memory corruption можно понять, кем этот объект был в прошлой жизни. Slub_debug можно включить в kernel commandline на боевом ядре, но эти проверки также потребляют память и ресурсы cpu. Для отладки в development и QA это вполне приемлемо, но клиенты в production используют это без особого энтузиазма.

Прошло полгода, приближался Новый Год. Локальные тесты на debug ядре с KASAN проблему так и не поймали, багрепортов от нод с включенным slub_debug нам так и не поступило, в сырцах мы ничего найти не смогли и проблему так и не раскопали. Андрея загрузили другими задачами, у меня, наоборот, образовался просвет и очередной багрепорт поручили разбирать мне.

Разобрав crash dump, я вскоре обнаружил проблемный kmalloc-192 объект: его память была заполнена каким-то мусором, информацией, принадлежащим другому типу объектов. Это было сильно похоже на последствия use-after-free, однако внимательно просмотрев в сырцах жизненный цикл поврежденного объекта, я тоже не нашел ничего подозрительного.

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

В конце концов я вернулся к своему багу и стал разглядывать предыдущий объект. Он тоже оказался in-use, однако по его содержимому было совершенно непонятно что это такое там не было констант, ссылок на функции или другие объекты. Отследив несколько поколений ссылок на этот объект, я в конце концов выяснил, что это был shrinker bitmap. Этот объект был частью технологии оптимизации освобождения контейнерной памяти. Технология изначально разрабатывалась для наших ядер, позднее её автор Кирилл Тхай закоммитил ее в linux mainline.

The results show the performance increases at least in 548 times.

Несколько тысяч подобных патчей дополняют оригинальный rock-stable RHEL7 kernel, делая Virtuozzo kernel максимально удобным для хостеров. По возможности мы стараемся заслать наши наработки в mainline, поскольку это облегчает поддержание кода в исправном состоянии.

Пройдя по ссылкам, я нашел структуру, описывающую мой bitmap. Descriptor полагал, что размер bitmap должен быть 240 байт, и это никак не могло быть правдой, поскольку фактически объект выделялся из kmalloc-192 cache.

Bingo!

Получалось что работающие с bitmap функции обращались к памяти за его верхней границей и могли менять содержимое следующего объекта. В моем случае в начале объекта был refcount, и когда bitmap его занулял, последующий put приводил к внезапному освобождению объекта. Позднее память выделялась заново под новый объект, инициализация которого воспринималась как мусор кодом старого объекта, что рано или поздно неизбежно приводило к крашу ноды.

image


Хорошо, когда можно проконсультироваться с автором кода!

Разглядывая с Кириллом его код, мы вскоре нашли первопричину обнаруженной нестыковки. При увеличении числа контейнеров bitmap должен был увеличиваться, однако один из случаев мы упустили из рассмотрения и в результате иногда пропускали resize bitmap. В наших локальных тестах такая ситуация не обнаружилась, а в версии патча, которую Кирилл заслал в mainline, код был переработан, и бага там не было.

С 4 попытки совместными усилиями мы с Кириллом сочинили вот такой патч, с месяц гоняли его в локальных тестах и в конце февраля выпустили апдейт c исправленным ядром. Выборочно проверили другие крашдампы, тоже обнаружили по соседству неправильный bitmap, отпраздновали победу и под шумок списали старые баги.

Однако старушки все падали и падали. Ручеёк таких рода багрепортов сократился, но полностью не иссяк.

В общем-то, это было ожидаемы. Наши клиенты хостеры. Они сильно не любят ребутить свои ноды, потому что reboot == downtime == потерянные деньги. Мы тоже не любим часто релизить ядра. Официальный выпуск апдейта довольно трудозатратная процедура, требующая прогона кучи различных тестов. Поэтому новые стабильные ядра выпускаются приблизительно раз в квартал.

Чтобы обеспечить оперативную доставку багфиксов на клиентские prоduction-ноды мы используем ReadyKernel live patches. По-моему, кроме нас так больше никто не делает. В Virtuozzo 7 используется необычная стратегия применения live patсhes.

Обычно лайфпатчат только security. У нас же 3/4 исправлений это багфиксы. Исправления багов, на которые наши customer'ы уже наткнулись или могут запросто наткнуться в будущем. Эффективно такие вещи можно делать только для своего дистрибутива: без feedback'а от пользователей не понять, что им важно, а что нет.

Live patching, конечно, не панацея. Все подряд вообще невозможно лайфпатчить технология не позволяет. Новый функционал таким образом тоже не добавляют. Однако заметная часть багов фиксится простейшими однострочными патчами, которые превосходно подходят для лайфпатчинга. В более сложных случаях оригинальный патч приходится творчески доработать напильником, иногда глючит live-patching машинерия, однако наш кудесник лайфпатчей Женя Шатохин превосходно знает свое дело. Недавно, например, он раскопал феерический баг в kpatch, про который по хорошему вообще стоит отдельному оперу писать.

По мере накопления подходящих багфиксов, обычно раз в одну-две недели Женя запускает в производство очередную серию ReadyKernel live patches. После релиза они моментально разлетаются на клиентские ноды и предотвращают наступание на уже известные нам грабли. И все это без ребута клиентских нод. И без необходимости часто релизить ядра. Сплошные преимущества.

Однако зачастую live patch доезжает до клиентов слишком поздно: закрываемая им проблема уже случилась, но нода, тем не менее, еще не упала.

Именно поэтому появление новых багрепортов с уже исправленной нами проблемой не было для нас чем-то неожиданным. При их разборе раз за разом обнаруживались знакомые симптомы: старое ядро, мусор в kmalloc-192, неправильный bitmap перед ним и незагруженный или поздно загруженный live patch с фиксом.

Одним из таких случаев выглядел и OVZ-7188 от FastVPS, поступивший к нам в самом конце февраля. Большое спасибо за багрепорт. Соболезнуем. Сходу сильно похоже на known issue. Жаль, что в OpenVZ лайв-патчей нет. Ждите релиза стабильного ядра, switch to Virtuozzo или используйте нестабильные ядра с багфиксом.

Багрепорты одна из наиболее ценных вещей, которые дает нам OpenVZ. Их исследование дает нам шанс обнаружить серьезные проблемы до того, как на них наступит какой-нибудь из толстых клиентов. Поэтому несмотря на known issue, я тем не менее попросил залить нам крашдампы.

Разбор первого из них меня несколько обескуражил: неправильного bitmap перед кривым kmalloc-192 объектом не обнаружилось.

А чуть погодя проблема воспроизвелась и на новом ядре. А потом еще, еще и еще.

Oops!


Как так? Недофиксили? Перепроверил сырцы все нормально, патч на месте, ничего не потерялось.

Опять corruption? В том же месте?

Пришлось разбираться по новой.

image
(Что это? смотри сюда)

В каждом из новых крашдампов расследование опять утыкалось в kmalloc-192 объект. В общем и целом, такой объект выглядел вполне нормально, однако в самом начале объекта каждый раз обнаруживался неправильный адрес. Отслеживая взаимосвязи объекта, я обнаружил что в адресе занулялись два внутренних байта.

in all cases corrupted pointer contains nulls in 2 middle bytes: (mask 0xffffffff0000ffff)
0xffff9e2400003d80
0xffff969b00005b40
0xffff919100007000
0xffff90f30000ccc0


В первом из перечисленных случаев вместо неправильного адреса 0xffff9e2400003d80 должен был быть правильный адрес 0xffff9e24740a3d80. Аналогичная ситуация обнаружилась и в других случаях.

Получалось, что какой-то посторонний код занулял нашему объекту 2 байта. Наиболее вероятный сценарий use-after-free, когда некий объект после своего освобождения обнуляет какое-то поле в первых своих байтах. Проверил наиболее часто используемые объекты, но ничего подозрительного не нашлось. Опять тупик.

FastVPS по нашей просьбе неделю погонял debug ядро с KASAN, но это не помогло, проблема так и не воспроизвелась. Мы попросили прописать slub_debug, однако это требовало перезагрузки, и процесс сильно затянулся. В марте-апреле ноды падали еще несколько раз, но slub_debug был выключен, и новой информации это нам не дало.

А потом наступило затишье, проблема перестала воспроизводиться. Закончился апрель, прошел май новых падений не было.

Ожидание закончилось 7-го июня наконец то проблема выстрелила на ядре с включенным slub_debug. Проверяя red zone при освобождении объекта slub_debug обнаружил два нулевых байта за его верхней границей. Другими словами, выяснилось, что это не use-after-free, виновником опять оказался предыдущий объект. Там располагался нормально выглядящий struct nf_ct_ext. Эта структура относится к connection tracking, описанию сетевого соединения, которое использует firewall.

Однако все равно было непонятно, почему так происходило.

Стал вглядываться в conntrack: в один из контейнеров кто-то по ipv6 постучался на открытый 1720 порт. По порту и протоколу я нашел соответствующий nf_conntrack_helper.

static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
{
.name = "Q.931",
.me = THIS_MODULE,
.data_len = sizeof(struct nf_ct_h323_master),
.tuple.src.l3num = AF_INET, <<<<<<<< IPv4
.tuple.src.u.tcp.port = cpu_to_be16(Q931_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
.help = q931_help,
.expect_policy = &q931_exp_policy,
},
{
.name = "Q.931",
.me = THIS_MODULE,
.tuple.src.l3num = AF_INET6, <<<<<<<< IPv6
.tuple.src.u.tcp.port = cpu_to_be16(Q931_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
.help = q931_help,
.expect_policy = &q931_exp_policy,
},
};

Сравнивая структуры, я заметил, что ipv6 helper не определял .data_len. Полез в git разбираться, откуда оно такое взялось, обнаружил патч 2012 года.

commit 1afc56794e03229fa53cfa3c5012704d226e1dec
Author: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu Jun 7 12:11:50 2012 +0200

netfilter: nf_ct_helper: implement variable length helper private data

This patch uses the new variable length conntrack extensions.

Instead of using union nf_conntrack_help that contain all the
helper private data information, we allocate variable length
area to store the private helper data.

This patch includes the modification of all existing helpers.
It also includes a couple of include header to avoid compilation
warnings.

Патч добавил в helper новое поле .data_len, которое указывало, сколько памяти требуется обработчику соответствующего сетевого соединения. Патч должен был определить .data_len для всех имеющихся на тот момент nf_conntrack_helpers, но пропустил обнаруженную мной структуру.

В результате чего получилось, что сonnect по ipv6 на открытый порт 1720 запускал функцию q931_help(), она писала в структуру, под которую никто не выделил память. Простой скан портов занулял пару байт, передача нормального протокольного сообщения заполняла структуру более осмысленной информацией, однако в любом случае перетиралась чужая память и рано или поздно это приводило к крашу ноды.

В 2017 году Florian Westphal очередной раз переработал код и убрал .data_len, а обнаруженная мной проблема осталась незамеченной.

Несмотря на то, что в нынешнем linux kernel mainline обнаруженного бага уже нет, проблема была унаследована ядрами кучи дистрибутивов linux, включая актуальные до сих пор RHEL7/CentOS7, SLES 11 & 12, Oracle Unbreakable Enterprise Kernel 3 & 4, Debian 8 & 9 и Ubuntu 14.04 & 16.04 LTS.

Баг тривиально воспроизвелся на тестовой ноде, и на нашем ядре, и на оригинальном RHEL7. Явный security: удаленно управляемый memory corruption. Там, где открыт 1720 ipv6 порт практически ping of death.

9-го июня я сделал однострочный патч c невнятным описанием и заслал его в mainline. Подробное описание я отправил в Red Hat Bugzilla и отдельно отписал в Red Hat Security.

Дальше события развивались без моего участия.
15-го июня Женя Шатохин зарелизил ReadyKernel live patch для наших старых ядер.
https://readykernel.com/patch/Virtuozzo-7/readykernel-patch-131.10-108.0-1.vl7/

18-го июня мы выпустили новое стабильное ядро в Virtuozzo и OpenVz.
https://virtuozzosupport.force.com/s/article/VZA-2020-043

24-го июня Red Hat Security присвоил багу CVE id
https://access.redhat.com/security/cve/CVE-2020-14305

Проблема получила moderate impact с необычно высоким CVSS v3 Score 8.1 и в течение следующих нескольких дней на публичный шляпный баг отреагировали и другие дистрибутивы
SUSE https://bugzilla.suse.com/show_bug.cgi?id=CVE-2020-14305
Debian https://security-tracker.debian.org/tracker/CVE-2020-14305
Ubuntu https://people.canonical.com/~ubuntu-security/cve/2020/CVE-2020-14305.html

6-го июля KernelCare выпустил livepatch для affected distributives.
https://blog.kernelcare.com/new-kernel-vulnerability-found-by-virtuozzo-live-patched-by-kernelcare

9-го июля проблему пофиксили в stable Linux kernels 4.9.230 and 4.4.230.
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?h=linux-4.9.y&id=396ba2fc4f27ef6c44bbc0098bfddf4da76dc4c9

Дистрибутивы, однако, дырку так до сих пор и не закрыли.

Смотри, Костя, говорю я своему напарнику Косте Хоренко, у нас снаряд два раза в одну воронку попал! Я и один-то access-beyond-end-of-object последний раз встречал непойми когда, а тут оно нас дважды подряд посетило. Скажи мне, это ж вроде квадратная вероятность? Или не квадратная?
Вероятность квадратная, да. Но тут надо смотреть какого события вероятность? Квадратная вероятность того события, что именно 2 раза подряд попались необычные баги. Именно подряд.

Ну, Костя умный, ему виднее.
Подробнее..

Как теперь процессить kernel crash и bug report? Или несколько слов о разнице между интересным и удивительным

30.04.2021 22:19:48 | Автор: admin

Широко известен исторический анекдот о том, что царица Екатерина II писала простое русское слово из 3 букв с 4 ошибками. Куда менее известно, что эта ошибка вовсе не уникальна. Дети европейских экспатов, изучающие русский язык, запросто могут в диктанте слово ёжик написать как Й-О-Ш-Е-Г.

И ведь дети отнюдь не безграмотные, просто они уже привыкли к своему родному языку. Услышанное слово разбивается на буквы на родном языке, затем побуквенно же транслируется на русский и записывается чужими прикольными иероглифами. Этот алгоритм хотя и неоптимальный, но, в принципе, рабочий. На каждом его этапе срабатывает испорченный телеграф, что приводит к закономерным искажениям оригинала. Так что, да, интересно, но, если вдуматься, ничего удивительного. И о подобной ситуации относительно новых ядер Linux я расскажу в этом посте.

Автор этих строк много лет пилит гирю OpenVz linux kernel maintenance. OpenVz сейчас потихоньку переезжает с ядра RHEL7 на RHEL8. Ядро в Red Hat за 5 лет сильно изменилось, поэтому мы очередной раз пересматриваем наши старые патчи и думаем, что с ними делать: перетащить как есть, переделать получше или дропнуть за неактуальностью.

В рамках этой большой задачи я разбирался с memcg accounting. OpenVZ аккаунтит различные kernel objects практически с самого рождения с v2.2.x ядер далекого 2001 года. Зачем и почему мы решили аккаунтить тот или иной объект, сейчас сходу понять довольно затруднительно, приходится поднимать историю по старым багам и коммитам.

В стародавние времена мы использовали свою собственную систему accounting, так называемые user beancounters. Там была пара десятков разных параметров, и правильно их настраивать было затруднительно для админов. В upstream эту подсистему тоже принимать не особо хотели, для них приходилось изобретать namespaces и cgroups, а для своих ядер скрещивать ежа, ужа и трепетную лань.

Пересмотрев наш memcg accounting из Virtuozzo Hybrid Server 7.5, я большую их часть перетащил в Virtuozzo Hybrid Server 8, посмотрел, что из этого до сих пор отсутствует в последнем upstream и подготовил соответствующий патчсет. Если кому интересно, кстати говоря, вот он: https://lkml.org/lkml/2021/4/28/70

Перед отсылкой в upstream изменения полагается хотя бы минимально проверить. Я скомпилил свое ядро, взгромоздил его на свою тестовую VM с Fedora Rawhide и давай его по-всякому тестить.

Чтобы разобраться в деталях memcg аккаунтинга в ядро в свое время засунули per-memcg sysfs файлик memory.kmem.slabinfo. В нем показывается количество тех или иных SLAB объектов, которые нашлись в соответствующей memory cgroup, нечто типа обычного /proc/slabinfo. В новых upstream ядрах из соответствующие файлики тоже были, однако из них почему то вообще ничего не вычитывалось. Я посмотрел на своем ядре, посмотрел на оригинальном ядре Fedora то же самое: файл есть, контента нет.

Стал разбираться. Выяснилось, что с полгода назад memcg подсистему очередной раз переделали, но с выводом контента в memory.kmem.slabinfo возникли сложности. Поэтому вывод решили обнулить, а для тех, кому он все таки интересен, в ядро закоммитили drgn скрипт tools/cgroup/memcg_slabinfo.py.

Обычно с ядром разбираются посредством crash но на живом ядре это довольно тяжелый способ. сrash долго стартует, потребляет кучу ресурсов, и на сильно загруженной production node такое делать стремно можно запросто разбудить OOM-killerа. Можно пытаться заюзать ftrace, perf или systemtap но у каждого из них свои недостатки и неудобства.

drgn их легковесная альтернатива. Позволяет добраться до внутренностей ядра, и удобным образом переходить по ссылкам структур ядра. Много говорить про него не буду, кому интересно -- посмотрите-покрутите самостоятельно. В целом, по-моему, удобно, впечатления от использования положительные, рекомендую. Исходник здесь: https://github.com/osandov/drgn.

Закоммиченный полгода назад скрипт на новом ядре уже не работал, структуры ядра за это время уже успели несколько раз поменяться. Неудивительно, на это обречен любой внешний скрипт или out-ouf-tree модуль. Однако благодаря простоте drgn исправить скрипт оказалось несложным.

Я проверил исправленным скриптом свое ядро со своими фиксами accounting все отработало нормально. Потом решил, что стоит посмотреть на то, как вело себя непропатченное ядро. Откатывать свои патчи и перекомпилировать свое ядро заново мне было лениво. Тем более, что у меня уже было другое upstream ядро от Fedora Rawhide aka fc35. Я специально проапдейтился, загрузил самое последнее ядро, запускаю скрипт а он не работает. И проблема похоже даже не в самом скрипте: drgn сам по себе не запускается.

[root@localhost test]# rpm -q drgn

drgn-0.0.11-2.fc35.x86_64

[root@localhost test]# drgn -s /usr/lib/debug/lib/modules/5.12.0-0.rc8.191.fc35.x86_64/vmlinux

Traceback (most recent call last):

File "/usr/bin/drgn", line 33, in

sys.exit(load_entry_point('drgn==0.0.11', 'console_scripts', 'drgn')())

File "/usr/lib64/python3.9/site-packages/drgn/internal/cli.py", line 119, in main

prog.load_debug_info(args.symbols, **args.default_symbols)

Exception: /usr/lib/debug/usr/lib/modules/5.12.0-0.rc8.191.fc35.x86_64/vmlinux: .debug_info+0x7704ab: unknown DWARF CU version 5

Ставлю ядро от fc34, чуть более раннее не помогает.

Ну хорошо, думаю, раз не получается залезть в эти ядра drgn, давай попробую crash.

А он тоже не запускается!

[root@localhost ~]# crash -d 1 (без дебага dwarf error не виден)

...

Dwarf Error: wrong version in compilation unit header (is 5, should be 2, 3, or 4) [in module /usr/lib/debug/usr/lib/modules/5.11.12-300.fc34.x86_64/vmlinux]

crash: /usr/lib/debug/lib/modules/5.11.12-300.fc34.x86_64/vmlinux: no debugging data available

Рассылаю багрепорты во все стороны, выясняю:

Fedora 34 переехала на новый gcc 11, который для всего подряд генерит debuginfo в новом формате DWARF version 5. Обычный userspace с ним вполне нормально работает, gdb этому формату уже давно обучили.

Однако для ядра это оказалось поистине катастрофично, потому что:

  • crash использует внутри старую версию gdb, которая DWARF 5 еще не понимает

  • drgn поддержку DWARF 5 еще не прикрутил,

  • и у systemtap, похоже, аналогичные проблемы.

И пока я рассылал во все стороны багрепорты, Fedorа 34 благополучно зарелизилась.

М-да! Как они собираются процессить kernel crashes и bug reports? Возможно, у них есть хитрый план?

Связался с девелоперами crash и drgn - ни там, ни там быстро прикрутить поддержку DWARF 5 не обещают. Так что похоже, хитрого плана все-таки нет. Возможно, недосмотрели. Возможно, даже, специально закрыли на это глаза, чтобы посмотреть что именно развалится и собрать багрепорты. В конце концов, Fedora не Red Hat и не CentOS. Она как раз и предназначена для обкатки новых технологий. Удивительно, как оно так получилось. Однако при этом совершенно неинтересно, почему.

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

Во-первых, можно перекомпилировать ядро с DWARF 4, в ядре для этого есть соответствующий CONFIG_DEBUG_INFO_DWARF4. Полагаю, Fedora именно так и поступит в ближайшем будущем.

Во-вторых, можно установить ядро от предыдущей Fedora 33. Брать, например, здесь: https://koji.fedoraproject.org/koji/buildinfo?buildID=1738749. Проверил, вроде как то работает.

В-третьих, вспомнить, что Fedora для production не предназначена, и смириться с тем, что в ней багов больше обычного.

И, в любом случае, не поленитесь забить им багрепорты, это очень важно и для них, и для любого другого Open Source.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru