DoS уязвимость в Open vSwitch

    Спойлер: Open vSwitch версий меньше 1.11 уязвим перед атакой вида «flow flood», позволяющей злоумышленнику прервать работу сети отправкой относительно небольшого потока пакетов в адрес любой виртуальной машины. Версии 1.11 и старше проблеме не подвержены. Большинство серверов с OVS до сих пор используют OVS 1.4 или 1.9 (LTS-версии). Администраторам таких систем настоятельно рекомендуется обновить систему на более новую версию OVS.

    Лирика: Прошло уже больше полутора лет с момента, когда я впервые сумел воспроизвести эту проблему. В рассылке OVS на жалобу сказали, что «в следующих версиях исправят» — и исправили, пол-года спустя. Однако, это исправление не коснулось LTS-версии, а значит, большинство систем, использующих OVS, всё так же уязвимо. Я пытался несколько раз связаться с Citrix'ом (т.к. он использует самую уязвимую версию OVS в составе Xen Server — в тот момент это был мой основной продукт для эксплуатации), но никакой внятной реакции не последовало. Сейчас у администраторов есть возможность устранить проблему малой кровью, так что я решил опубликовать описание очень простой в воспроизведении и крайне запутанной и в диагностике проблемы — проблеме «flow congestion», она же «flow flood attack», она же «странная неведомая фигня, из-за которой всё работает странно». Раньше в комментариях и в рассылках про эту проблему я уже несколько раз писал, но у меня ни разу не хватало пороху полностью описать проблему на русском языке так, чтобы суть проблемы была понятна обычному айтишнику. Исправляюсь.

    Следующая строчка hping3 -i u10 virtual.machine.i.p нарушает работоспособность хоста виртуализации, где запущена виртуальная машина. И не только хоста виртуализации — любую систему, работающую на Open vSwitch версий меньше 1.11. Я делаю особый упор на версиях 1.4.3 и 1.9, потому что они являются LTS-версиями и используются чаще всего.

    Более суровая версия того же вызова, на этот раз с нарушением правил пользования сетью: hping3 --flood --rand-source virtual.machine.i.p. Соотношение исходящего трафика (~10-60Мбит/с) и (потенциальной) пропускной способности интерфейса жертвы (2x10G, соотношение по доступной полосе атакующий/атакуемый порядка 1:300-1:1000) позволяет говорить именно про уязвимость, а не про традиционную DoS атаку флудом, забивающем каналы аплинков до нерабочего состояния.

    Симптомы со стороны хоста виртуализации: неожиданные задержки при открытии соединений, рост потребления CPU процессом ovs-vswitchd до 100%, потеря пакетов для новых или малоактивных сессий. Если используется OVS 1.4, то процесс ovs-vswitchd не только съедает свои 100% CPU, но и начинает подъедать память и делает это со скоростью до 20 мегабайт в минуту, пока к нему не приходит добрый дедушка OOM и не проводит воспитательную беседу.

    В отличие от обычных проблем с сетью, запущенные пинги с большой вероятностью «прорвутся», и как только flow с ними попадёт в ядро, ping работать будет без малейших нареканий, а вот новые соединения будет уже не установить. Это сильно затрудняет диагностику проблемы, потому что психологическое «пинги есть — сеть работает» изжить очень сложно. Если к этому добавить, что «прорвавшаяся» ssh-сессия на хост будет продолжать работать так же без особых затруднений, то убедить администратора в том, что проблема с сетью со стороны хоста будет крайне и крайне сложно. Если флуд на интерфейс превышает некоторый порог (~50-80Мб/с), то любая адекватная сетевая активность прекращается. Но коварство описанной проблемы состоит в том, что значительная деградация сервиса происходит при значительно меньших нагрузках, при которых канонические средства диагностики сети рапортуют «всё в порядке».

    Пользуясь случаем хочу извиниться перед si14, который о странности с сетью у лабораторных виртуалок говорил, но не мог мне доказать их наличие, а я «видел», что у меня всё хорошо, и потребовалось больше года, пока я, наконец, не только сам заподозрил неладное, но и смог найти однозначный краш-тест.

    В случае XenServer ситуация с OVS осложняется тем, что локальный management-трафик так же идёт через бридж Open vSwitch, а все бриджи обслуживаются одним процессом ovs-vswitchd, то есть счастливый администратор даже не сможет посмотреть на эти симптомы — его просто не пустят по ssh. А если пустят — то см выше, про «проблем нет». Поскольку трафик NAS/SAN так же идёт через бридж, то даже после исчезновения причин, виртуальные машины с большой вероятностью останутся в нерабочем состоянии. В этом случае симптомы проблемы — «неожиданное зависание, начавшееся с лагов и потери пакетов».

    Описание уязвимости с точки зрения «production manager'а» — любой школьник с 10-50 мегабитным каналом на ADSL может положить всю ферму серверов виртуализации с десятигигабитными портами, если с них хотя бы одна виртуалка «смотрит» интерфейсом в интернет. И правила/ACL внутри виртуалки практически не помогут. Аналогичное может устроить любой пользователь любой виртуалки, даже лишённой доступа в интернет.

    Техническое описание проблемы



    (иллюстрация из поста An overview of Openvswitch implementation)
    Причина: Старые версии Open vSwitch не умеют объединять похожие flow и при обнаружении ethernet-кадра, похожего на новый flow всегда отправляют кадр на инспекцию через netlink-сокет процессу ovs-vswitchd, Так как процесс инспекции крайне медлительный (на фоне ошеломительной скорости хэш-таблиц в ядре), а сам ovs-vswitchd является однопоточным и единственным в системе, то производительность сети в условиях появления множества новых flow оказывается ограничена скоростью userspace-приложения (и его хождения в ядро/обратно через netlink). Через короткое время существующие kernel flow оказываются заменены новыми записями и вытеснят существующие (если только те не очень активны), а шансы восстановления новой flow обратно пропорциональны числу конкурентов — то есть флуду. Причём, количество пакетов в добросовестной сессии не играет никакой роли — вся сессия оказывается одной-единственной flow. Именно это служило долгое время «слепым пятном» — любой burst-тест с единичной TCP-сессией радостно сообщал о гигабитах трафика при почти нулевой утилизации процессора.

    Kernel flow versus openflow flow


    Ключевым является понимание разницы между kernel flow и openflow flow. Openflow flow подразумевает, что flow сопровождается битовой маской, точнее, формат openflow подразумевает указание на интересующие поля. При этом для остальных полей неявно подразумевается «не важно», то есть "*".

    Модуль ядра в старых версиях Open vSwitch использует довольно изощрённый механизм работы с правилами, у которого есть только один недостаток: он не поддерживает маски и звёздочки.

    Механизм там следующий: у входящего ethernet-кадра выбираются все его заголовки, начиная с L2 и заканчивая L4 (то есть, например, номер порта у TCP), за вычетом уж совсем бесполезных, наподобие «размер окна» у TCP, или «номер сегмента». Все они упаковываются в бинарную структуру, после чего от этой структуры считается хеш. Дальше этот хеш ищется в хеш-таблице правил, и если для правила находится совпадение, используется оно. Если ни одно не совпадает, пакет отправляется на инспекцию более интеллектуальной программе в userspace (ovs-vswitchd), которая присылает обратно новое правило, что делать с такими пакетами. Правила для openflow, а так же наложенные вручную правила через ovs-ofctl обрабатываются именно ovs-vswitchd, а ядерный модуль о них ничего не знает. Особо это касается правила «normal», которое означает «веди себя как коммутатор». Но даже обычный drop всё равно требует инспекции в user-space, потому что drop чаще всего не включает в себя все возможные комбинации входящего/исходящего порта, а, значит, с точки зрения OVS, содежит «звёздочки».

    Хеш-таблица даёт фантастическую производительность, которая не зависит от числа правил (то есть 10000 правил будут обрабатываться примерно с такой же скоростью, как и одно).

    К сожалению, если заголовки у каждого нового пакета разные, то каждый новый такой пакет уйдёт на инспекцию в userspace. Что медленно и печально.

    Оригинальная задумка OVS была в том, что в рамках TCP-сессии все пакеты будут одинаковыми и на всю сессию будет одно правило. К сожалению, злой «хаккир вася», скопипастив строчку выше, сможет это ожидание нарушить.

    В новых версиях эту проблему решили с помощью megaflow.

    Megaflow


    Они появились в Open vSwitch начиная с версии 1.11. Megaflow не относится к openflow, а касается взаимодействия ovs-vswitchd и ядерного модуля. К сожалению, цена за megaflow вполне ощутимая — производительность в ряде случаев падает процентов на 5-20%. К счастью, взамен ovs-vswitchd практически ни при каких условиях не будет отъедать непропорционально много ресурсов.

    Что такое megaflow? Очень подробно на Си это излагается тут. Из того, что я понял — появляется понятие «маски», сами маски являются уникальными для всего kernel datapath, а при поиске приходится учитывать их все, то есть сложность поиска становится не o(1), а o(masks). Отсюда и получается некоторое падение производительности. Но на фоне невыразимых тормозов и отказа в обслуживании в случае flow flood'а — это радостная новость. И, пожалуй, единственный выход.

    Кроме того, во многих инсталляциях масок будет очень мало, и падение производительности будет неощутимым. Например, неуправляемый режим «простого коммутатора», то есть normal, вероятнее всего, будет содержать одну-единственную маску.

    Атака in the wild


    При том, что в начале статьи речь шла про «атаку на отказ в обслуживании с hping/nping», реальная проблема куда шире. Если к виртуальной машине по какой-то причине идёт много обращений с множества разных адресов, или просто устанавливается много сессий, то с точки зрения поведения OVS разницы с «атакой» и «высокой нагрузкой» никакой. Я такое наблюдал в реальности, когда виртуальная машина использовалась для раздачи статики для какой-то жутко популярной браузерной игры, содержащей кучу мелких картинок. Игроков было много, картинок было много, они были маленькие. Итого — несколько тысяч новых TCP-сессий в секунду размером 300-500 байт. При этом получался весьма умеренный поток в 15-20 мегабит. И худший случай для старых версий OVS, так как каждая сессия — хождение в юзерспейс.

    Дополнительную проблему создаёт то, что у netlink есть буфер, и у сетевых интерфейсов есть буфер, и у OVS есть буфер. Входящие пакеты не просто дропаются — они становятся в очередь, загружая процессор на 100% (да-да, на 100 из 800 доступных). Это приводит к росту latency в обработке новых flow. Причём эту latency крайне трудно диагностировать: лаг есть только на первом пакете, все последующие (в рамках созданной flow) обрабатываются быстро.

    Рост latency приводит к второй части проблемы: если пакет из существующей TCP-сессии оказывается в очереди достаточно долго, то запись о такой сессии вытирают из kernel flow table. И пакет опять идёт на инспекцию, на создание новой kernel flow, и это ещё больше добивает OVS до состояния «не дышит и не шевелится».

    Заметим, что проблема симметрична по отношению input/output. Это может быть не только «хаккир вася» снаружи, но и «хаккир вася» внутри. Виртуальная машина, рассылающая тысячи новых сессий наружу, вызывает такие же проблемы — и эти проблемы касаются всех, кто оказался рядом с «хаккиром». Если же рассылаются пакеты по соседям по сети, то одинокая виртуальная машина становится способна парализовать или сильно ухудшить качество сервиса для целого множества серверов виртуализации.

    Понятно, что для публичного провайдера такое смерти подобно. На предыдущей работе мне пришлось написать довольно уродливый патч, который резал большую часть функционала OVS (т.к. megaflow к тому моменту ещё не было), оставляя в бинарных отпечатках кадра (из которого делают хеш) только минимальный возможный набор параметров. В апстрим такое не берут, но возникшую проблему я решил. А до выхода OVS 1.11 c megaflow оставалось ещё примерно пол-года…

    Масштабы проблемы


    дистрибутив версия OVS уязвимость
    Debian Sqeeze x пакета нет
    Debian Wheezy 1.4.2 уязвимая версия + memory leak
    Debian Sid 1.9.3 уязвимая версия (вот вам и bleeding edge)
    Ubuntu 12.04 1.4 уязвимая версия + memory leak
    Ubuntu 14.04 2.0 ура, ура.
    XenServer 5.5 1.4.2 уязвимая версия + memory leak
    XenServer 6.2 1.4.3 уязвимая версия. До сих пор, даже не 1.9!
    RHEL/CentOS 5 x Пакет не предоставляется
    RedHat/CentOS 6.5 x Только модуль ядра, без userspace
    Fedora 21 2.1 свежайшая!

    (информация о версии OVS в вашем любимом дистрибутиве приветствуется и будет добавлена, указывать на версию желательно с ссылкой на сайт дистрибутива)
    Поскольку OVS является рекомендованным и штатным бриджем для openstack, причём как opensource-версий, так и многих проприетарных (они всё равно используют OVS для трафика до виртуалки), то можно говорить, что большинство дефолтных установок OpenStack подвержено проблеме. Аналогичная проблема ожидает штатные установки libvirt на базе OVS — так как в дистрибутивах, в основном, проблемные версии.

    Заключение


    Обновляться, обновляться, обновляться. К величайшему счастью пользователей CentOS 5 и прочих ценителей достижений мамонтов, ядерный модуль OVS 1.11 поддерживает 2.6.18 (но не более 3.8), так что он будет работать на большинстве систем. Для более новых ядер стоит использовать более новые версии OVS — 2.0, или даже 2.1 (только-только вышел в начале мая 2014). Ключевая потенциальная проблема — если при обновлении OVS не обновить модуль ядра, то получившееся работать не будет (хотя утилиты командной строки будут пытаться изображать работоспособность).

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

    Ссылки по теме:


    P.S. Если кто-то решит проверить «как оно работает» из виртуалки — учтите, что после запуска есть вероятность, что Ctrl-C вы уже не нажмёте. Точнее, нажмёте, но сервер вас не услышит и продолжит слать флуд в интерфейс, и даже перезагрузить такую виртуалку будет сложно — если управление идёт через такой же бридж, то команда на выключение или перезагрузку просто «не дойдёт» до утилит на хосте.
    Webzilla 69,00
    Компания
    Поделиться публикацией
    Комментарии 27
    • +1
      Старый-добрый SYN-flood:)
      • 0
        Тут ситуация даже чуть хуже — любой пакет с различающимся заголовками вызовет подобное. Например, банальная UDP-атака с разных хостов или даже с разных src-port вызовет такую же проблему.
        • 0
          А, ну да.
          Интересно, есть ли какие-то результаты тестов производительности — сколько «потоков» сможет ovs до патча?
          • 0
            Я когда писал статью, перепроверял поведение. У меня в лаборатории есть OVS 1.4.3 (из бубунты 12.04) начинал сильно хромать при примерно 10kpps. Полностью «всё умирало» при 60kpps.
          • 0
            Так это просто nmap все положит.
            • 0
              nmap, даже в самом ужасном режиме, сделает довольно мало запросов. Это вызовет короткий лаг, не более. Тут проблема в постоянности потока, а не в факте прихода каких-то пакетов.
        • 0
          Вывод — нехай использовать flow без необходимости. По пакетная маршрутизация наше всё.
          • +2
            Традиционный конфликт производительности и фичастости. Меня во всей этой истории скорее всего удивляет позиция Цитрикса, который не считает смерть хоста от чиха hping'а чем-то ощутимым или значительным.
            • +1
              Там, где пакетики могут ходить сильно разными путями, от потоков никуда не денешься.
            • +1
              Спасибо. Очень интересно. С openvswitch еще не работал, но, видимо, предстоит.
              • –1
                Баге уже куча времени, давно исправлена и тп. Зачем о ней писать сейчас? Все более или менее серьезные конторы все равно ключевой софт собирают сами и патчат и тп.
                Так что на мой взгляд проблема сильно надута.
                • +2
                  И много вы знаете контор, которые патчат xenserver без одобрения цитрикса, да еще не LTS версию?

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

                  Кроме того, сами ovs'ники не считают это уязвимостью, а говорят про «improved performance in some cases», а на самом деле это беда-беда для хостеров.
                  • +1
                    Так никто не заставляет использовать ovs, вот они и не считают это бедой бедой. А зачем получать одобрение цитрикса для патча?
                    • +1
                      Потому что xenserver поставляется в виде iso'шки, к которой апдейты выпускаются самим цитриксом, а установка чего-либо со сторонних источников крайне не рекомендована (из-за идиотского патченного lvm'а и udev'а).
                    • +1
                      Пользователи опенстека не ограничены в выборе версии OVS для большинства существующих дистрибутивов. Пользователи, сидящие на зенсервере в 2014 году, как бы это помягче сказать, ссзб, независимо от понуждающих причин. В общем проблема в современном мире отсутствует, vase совершенно верно подметил.
                      • 0
                        Ну, вот trusty вышла недавно — а до этого официальным OVS'ом для cloud archive считался 1.9. Лениво искать, но, подозреваю, что у многих готовых бандлов openstack'а там внутри тот же 1.9.

                        Причина проста — волшебные буквы LTS в названии.
                        • 0
                          Так никто не мешает взять посмотреть megaflow и сделать патчи к lts =). Все сидят и ждут, что кто-то поправит. К тому же модуль ядра обновить даже в цитриксе мне кажется не сложно…
                          • 0
                            Патчи к LTS сделать нельзя, потому что исправление это (в отличие от моего куцего патча) — фактическое переписывание функционала.

                            У цитрикса _всё_ сложно. Хотя бы потому, что все компоненты enterprise-части, написанные на bash'е (/etc/xensource/scripts) ожидают строгого поведения от других компонент и начинают нервно ломать что попало, когда их ожидания не выполняются.
                            • 0
                              Не знаю, я не парюсь на счет LTS или нет. Я использую то, что работает. Обычно это последний стейбл, на котором работают все тесты. Благо для openvswitch их на каждый чих…
                          • 0
                            Тут есть несколько факторов — а) практически все установки, использующие нейтрон и ovs — приватные б) публичные опенстечные облака используют только и исключительно нова-нетворк, в) у крупняка хватит денег на специалиста, который умеет отличать буквы LTS от работающего решения. Тем, кто не классифицируется по этим множествам, можно, пожалуй, посочувствовать :) Тем не менее, год назад картина была, конечно, ужасающей.
                            • 0
                              А вот эту мысль не поясните? Чем neutron не угодил public cloud?
                              • 0
                                Слишком сложен и гоняет лишний траффик внутри сегмента. Разделение идет по типам задач — публичной сети организация сети сложнее картофелины не нужна, а в приватной можно наворотить с квантумом суперсложную топологию под пожелания энтерпрайзов. О публичных опенстечных сетях, ориентированных не на розницу, мне ничего не известно.
                                • 0
                                  Ну, переложить с ноды на ноду трафик — не велика нагрузка. Но, неужели, никто не делает lbaas и metering для паблика? У каждого свои велосипеды?

                                  Я думаю, это, скорее наследие времени начала деплоя, когда квантум был страхолюда-страхолюдой…
                                  • 0
                                    Ну, кто-то делает, но en masse это исключение. Проблема опенвсвича к ним точно не применима, потому что возможностей сделать правильно в этом случае хватает.
                      • 0
                        Все более или менее серьёзные конторы? Ну-ну.

                        habrahabr.ru/company/sdn/blog/225587/?reply_to=7667415#comment_7667431
                      • 0
                        Ого, зашёл на Хабр, а тут такое оповещение :) Спасибо.
                        • 0
                          citrix xenserver openvswitch workaround:
                          xe-switch-network-backend bridge

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

                          Самое читаемое