Pull to refresh
313
0
Николай Шлей@CodeRush

Firmware Security Engineer

Send message
Вот еще примеры. По сути, это такой способ пояснить анализатору, что вот эта твоя функция — это memcpy на самом деле, или malloc, а то, что она выглядит странно и вызывается через указатель на указатель — не повод пропускать ее на taint-анализе, и не повод ругаться на нее за то, что она повторяет якобы системную библиотеку, которой у нас все равно нет.
Спасибо вам за ваш труд, серьезно. Проблема только в том, что гарантировать и не нужно, нужно улучшить статут кво. Бизнесу не интересно переписывать все их миллионы строк кода на языках, которые непонятно когда появятся, потому что продукт нужно выпускать уже в этом году, а код сам по себе — это не продукт, это технические детали реализации. Нельзя отмахиваться от инструментов улучшения существующей кодовой базы только потому, что инструменты эти не универсальные, или пропускают ошибки, или не находят ошибки, потому что нет вообще ничего совершенного и даже идеальные программы все равно на реальном железе исполняются.
Ну там в Rust пришлось внести очень серьезные ограничения на инварианты для ссылочных типов, чтобы анализ этот стал дешевле, но по сравнению с C и C++ компилятор медленный все равно. Совет не то, чтобы вредный, но вот это «прокрустово ложе до горизонта» нужно принять (кому-то это дается легче, кому-то — тяжелее). Есть огромное множество языков без него на выбор, и появление новых языков с ним я приветствую, потому что оно расширяет этот самый выбор. «Пусть расцветают сто цветов, и процветают сто школ».
Мы используем Coverity и серезно снизили накал ложных срабатываний моделированием.
Тут уже volatile все вспомнили, да и линтер хорош даже для системного программиста. Более того, для системного он особенно хорош, потому что цена ошибки там намного выше, и потому любые инструменты по их раннему обнаружению — это безусловное благо.

Все вот эти хитрые трюки, которые необходимы на системном уровне — их тоже можно и нужно пояснить и компилятору, и анализатору. «Я знаю, что делаю, не мешай», как с unsafe в Rust. И это тоже замечательно, посколько позволяет потом обычным поиском по тексту найти все места с практической магией, и обратить на них внимание в первую очередь при отладке действительно сложных проблем.
Принуждение можно организовать по-разному, в Rust вот реализовали прямо в компиляторе (и это отлично), а на С никто не мешает внутри отдела RnD потребовать использования анализатора, либо поставить его на pre-commit hook и выдавать предупреждения сразу же там, плюс еще раз снова на ревью. Понятно, что это решение технических проблем административными мерами, но это тем не менее решение, и оно вполне подходит тем, кто свой код на Rust или SPARK не может просто так переписать — его там до этого писали 15 лет, и там его 500к строк, например.
Даже ложные срабатывания это полезно, и время на их начальное разгребание (т.к. когда у вас уже 10к+ строк кода, а анализатор до этого не использовался никогда) окупится сторицей и найденными багами (не видел я вот ни разу еще, чтобы в большом проекте на С или С++, в котором до этого анализаторы не использовались, ничего бы не нашлось), и повышением вашего профессионализма как разработчика на этих языках (потому что расследования ответов на вопросы вроде «да какого хрена ему тут то не нравится?» сильно расширяют кругозор).

Уже приводил этот пример в осуждениях PVS-Studio на opennet.ru, процитирую сам себя оттуда:
боролся я однажды с интересным багом при инициализации дополнительных ядер процессора AMD Merlin Falcon в прошивке. Нулевое ядро там назвают BSP (BootStrap Processor), а остальные — AP (Application Processor), так вот, инициализация очередного AP иногда зависала на ровном месте в ~0.1% случаев (а т.к. процесс работы прошивки до этого времени детерминирован, то в таких зависаниях чаще всего виновато оборудование или код, который его неправильно использует).
Зависающая прошивка — это show stopper, т.е. пока это не починим, дальше разрабатывать нет смысла. Я просидел две недели в попытках понять, что не так, и пошел пробовать статические анализаторы, которые давали попробовать (AMI использует CppCheck для своего кода, но он совсем слабый по сравнению с любыми коммерческими анализаторами).
В итоге PVS-Studio нашла переменную в структуре, у которой был пропущен аттрибут volatile, а в коде было что-то вроде такого:
// Prepare CPU context structure

apStructPtr->InSync = 0;

// Send context to AP

// Wait for AP sync
while(apStructPtr->InSync) {
// Still waiting
}

Т.к. ни apStructPtr, ни InSync не были помечены как volatile, то компилятор просто выбрасывал цикл, т.к. он не влияет на наблюдаемое поведение и аналогичен while(0), в результате получалась гонка между внутренними процессами в CPU и продолжением исполнения, и выигрывали её чаще всего внутренние процессы, т.е. все работало почти всегда. Но потом стало больше ядер, вышли новые процессоры и более долгой синхронизацией, и все сломалось.
А PVS-Studio сразу сообщила, что вот тут место подозрительное, проверьте. Проверил, добавил volatile, баг исчез. Вот так и помогает, вполне реально.
Должно.
According to the C99 Rationale [C99 Rationale 2003], other than calling a limited, prescribed set of library functions, «the C89 Committee concluded that about the only thing a strictly conforming program can do in a signal handler is to assign a value to a volatile static variable which can be written uninterruptedly and promptly return.»
However, this issue was discussed at the April 2008 meeting of ISO/IEC WG14, and it was agreed that there are no known implementations in which it would be an error to read a value from a volatile sig_atomic_t variable, and the original intent of the committee was that both reading and writing variables of volatile sig_atomic_t would be strictly conforming.
Более того, компилятору тоже придется указать на то, что данные в этом A[] могут меняться «внезапно» вне текущего контекста исполнения, и анализатор эти указания скорее всего тоже примет к сведению. И в #3 весь буфер будет volatile, в #2 — тоже, плюс там еще синхронизацией обмазываться в любом случае.
Если кусок памяти не помечен специальным образом, то оптимизирующий компилятор по стандарту вправе считать, что данные в нем «внезапно» не изменяются, и потому удалить вот эту повторную проверку. Анализатор, кстати, сообщает именно об этом, т.е. «ребята, data flow-анализ есть не только у меня, но и у вашего компилятора, вы действительно имели в виду то, что написали?»
Не расстраивайтесь, Андрей, люди по мере набора опыта придут к пониманию, что статический анализатор — это благо. Поначалу всегда кажется, что это все не нужно, и все ошибки на поверхности, код почитай и все увидишь. На деле же любые инструменты, помогающие в разработке и отладке на ранних этапах, снижают в итоге и количество ошибок, и цену этих ошибок.

Писал много раз, и еще напишу: изучайте ваши инструменты, анализаторы, санитайзеры, фаззеры, SAT-солверы, профилировщики, отладчики, средства символьного исполнения и т.п., потому что все они и сильно повышают качество вашего ПО, и сильно ускоряют его разработку, и снижают накал рутины, потому что действия по монотонной проверке инвариантов теперь исполняет машина, которая не скучает, не отвлекается, и не устает.
Делюсь тем опытом, который имею. Если у вас другой — поделитесь и им тоже, это всегда интересно.
Тут еще очень сильная культурная разница, потому что в западных крупных компаниях нужно непрерывно сохранять лицо, и никогда не упоминать в разговоре с кем либо, кроме начальника 1:1 то, что тебе активно не нравится, потому что это «негативно» и «демотивирует окружающих». Люди совершенно не хотят слушать от своих лидеров, что «вокруг огонь, все в огне, и мы в аду», и потому сказать про это по сути можно только своему терапевту, своему начальнику на 1:1, и своим друзьям из России, потому что у нас тут принято делиться проблемами с близкими, т.к. это и позволяет легче переносить их коллективно, и сплачивает саму группу во время их решения. «Совместный труд, он объединяет!» как говорил известный кот из советского мультфильма. Я пробовал так вести себя на западе, и это очень сильно помешало продвижению по карьерной лестнице. Не повторяйте моих ошибок, ребята.
Зависит от загруженности менеджера, в основном, и от уровня позиций. Чем выше и уровень позиций, и квалификация участников, тем реже 1:1 проводятся, но когда их нет по несколько месяцев, стоит напомнить, что неплохо было поговорить про накопившееся.
Если разделить микросхему физически на две части, получится две микросхемы вдвое меньшего объема. Это увеличивает BoM cost проекта на $100k+ вот прямо тут, потому что производство массовое (200к+ штук), а два чипа поменьше стоят на 50 центов дороже одного чипа побольше. Плюс пайка, плюс тестирование, плюс дополнительный прогон через refurbishing station всех плат, на которых вышел из строя только один чип из двух, итого ~$120k и небольшое снижение механической надежности. Любой штатный оптимизатор BoM cost вам за эти «лишние» 120к лицо обглодает, фигурально выражаясь, и будет по своему прав.

Физические атаки на перемещение тумблера будут примерно те же, что и на перешивку на программаторе — evil maid, т.е. оставил ноут в номере отеля, вышел в бар за пивом, а тебе в прошивку уже подсадил трояна условный Моссад. Вот эта атака из статьи именно на прошивку (если она вообще реальная, а не ПЕАР) — она именно таким образом и провернута, скорее всего, или похожим очень.

Более того, необходимость двигать тумблер сразу же лишает возможности автоматического обновления прошивки, а т.к. там десяток мегабайт кода (после распаковки), который из крупных кусков кода на С и Ассемблере разных производителей низкооплачиваемые азиатские инженеры собрали на скотч и отборный мат, то в таком коде неизбежны баги, и их очень хочется починить таким образом, чтобы пользователю для этого ничего делать не пришлось. Именно для этого у нас сейчас обновления прошивки ставятся через ESRT прямо из Windows Update и Linux Vendor Firmware Service так же, как и обновления драйверов и остального софта. Просто прошивка современного ПК и сервера — давно уже намного более software, чем firmware, там сетевой стек от FreeBSD, драйверы для FAT32 и NTFS, и OpenGL в BIOS Setup. А сделаешь тумблер — и все, никаких тебе автоматических обновлений, потому что у пользователя лапки, и никакие тумблеры он переключать не будет, потому что боится, потому что сложно, и потому что «лошадь в ванне с огурцами.жпг».

И тумблер WE/RO, и резервирование, и несколько микросхем физически — все это делается давно и успешно на промышленной электронике, обслуживаемой профессионалами за деньги. А тут у нас домашняя электроника, которую пользователь боится больше, чем она его, и потому все подобные начинания будут немедленно зарезаны отделом дизайна и отделом маркетинга у всех компаний, ориентирующихся не на энтузиастов. Для остальных есть ребята типа Purism и system76, у которых там и прошивки все открытые, и тумблер они могут поставить легко, если их убедить в том, что с тумблером их целевая аудитория энтузиастов купит больше их продукции.
И вас, бандитов, я тоже вспоминаю добрым словом регулярно. ;) Семь лет прошло с половиной, а ощущается как целая вечность.

Прискорбно, что я могу сказать. Низы не могут, верхи не хотят, 10-15% корпоративных пользователей продолжают думать, что у них все отлично. А достучаться там не очень трудно, на деле, 3-5 выступлений на крупных конференциях, на которых прошивку очередного тайваньского ОЕМа разносят в пух и прах семнадцатью разными способами, пара сворованных из памяти ключей шифрования или паролей, десяток перепечаток крупных СМИ, и вот компании уже хотя тебя или убить, или посадить, или купить, или нанять, главное, чтобы ты заткнулся и не портил им продажи, решать же проблемы безопасности при этом не просто не обязательно, а даже вредно, потому что долго и дорого, и поддерживать все это потом, и проверять, что все обновления всех машин не регрессировали все обратно в жопу к предыдущему небезопасному состоянию. Впрочем, у меня у самого рыло в пуху по самый затылок, так что дальше разводить огород не стану. Нет запроса на безопасность прошивки — ну значит будет еще, а пока продолжаем брать ASUS в качестве гарантированно открытой платформы для экспериментов.
Влад, доброго тебе здоровья, и спасибо за борьбу, хорошее дело делаете.

От себя лично могу посоветовать только одно: наймите уже кого-нибудь толкового вам прошивки защищать хотя бы на корпоративных ноутах, ладно уже не до игровых. Но до сих пор же решето, сколько в AMI про про это не пиши. Ладно я понимаю когда на десктопах USB BIOS Flashback штатно подписи не проверяет — там это даже приветствуется, пусть энтузиасты модифицируют как угодно, но на ноуте я вот реально хочу, чтобы прошивка сопротивлялась хотя бы базовым атакам, про которые еще в 2015 году знали даже дети из соседнего двора.

Реально очень хочу советовать продукцию Asus людям, которые у себя на ноутбуках хранят что-то ценное и важное, но пока что не могу. Вместо этого продолжаю наблюдать примерно такое:
Furthermore, the leaks reveal that the UEFI infection capability (which is referred to by Hacking Team as ‘persistent installation’) was tested on ASUS X550C laptops.

Понятно, что вся эта безопасность денег стоит, а продать ее нелегко, и понятно, что это все даже вредно в продуктах для геймеров, но если Asus таки хочет конкурировать с Dell, HP и Lenovo на поле корпоративных ноутбуков, проблемами безопасности прошивки я советую заняться уже вчера, если не 5 лет назад.
Вредоносный код в этой теме тупой как пробка, и скорее всего, вставлен в прошивку вручную (точнее инструментом вроде UEFITool). Обновление прошивки на новую версию, или даже на ту же версию, удалит этот вредоносный код без следа.
Поддержку в итоге так и не выкинули до сих пор, потому что Интел уже раз обожглись на молоке (Itanium) и теперь так усиленно дуют на воду, что непонятно, когда уже наступит эта долгожданная дата, когда эти дурацкие «способы адресации и форматы команд» наконец уйдут в историю. CPU IO-порты никак не могут выкинуть, хотя там уже настоящих почти не осталось, все эмулируется прошивкой, PIC со статическим IRQ routing'ом, которым никто не пользуется толком уже лет 10, и прочее вот это все. Понятно, что оно нужно для всякой промышленной автоматизации и прочих EnI-вещей, но из процессоров для обычного ПК и сервера весь этот чемодан без ручки можно было выкинуть еще лет пять назад без особого вреда. В итоге Интел обещала перестать поддерживать слой совместимости с BIOS (CSM) в конце этого года, надеемся-ждем, но прогноз мой лично неутешительный — еще пару лет полуживого забавлять придется, как минимум.
Усложнение железа под прошивкой скрыто от простого пользователя слоями поверх слоев обратной совместимости, и потому очень многие по-прежнему уверены, что интерфейс BIOS Interrupt Call — это отлично, а загрузка через MBR — лучший способ загрузки, несмотря на то, что там вообще нет никакого способа защититься от загрузочных вирусов, кроме крайне легко обходимой защиты от редактирования этой самой MBR.

Делать из вот этой статьи про собранный китайцами на коленке из утекших исходников 2015 года руткит, найденный позже на машинах с AMI AptioV производителя второго эшелона, вывод о том, что UEFI сломан весь вообще, и надо все переделывать — это как-то обескураживает даже. Знали бы вы насколько BIOS сломан был, и каким сломанным он стал к его закату…

Прошивка любая подобная будет с багами, потому что у тех тайваньских ОЕМов второго эшелона и так уже маржинальность 10% (т.е. вкладывать какие-то деньги в безопасность, или вообще во что-либо, что напрямую не влияет на продажи — это для них верная смерть от рук конкурентов, которые не вкладывают ничего). И виноват тут не BIOS, не UEFI, не coreboot, и не U-boot, это все малозначительные детали реализации. Виновато простейшее управление рисками, т.е. пока такие атаки находят одну за пару лет, как не пару десятков тысяч в день, чинить прошивку будут стараться только всякие странные граждане вроде меня, а ОЕМу как было пофиг на нее, так и будет дальше — денег он от ее разломанности в плане безопасности пока что не теряет, а потому тратить на нее какие-либо ресурсы для него не имеет смысла.

Information

Rating
Does not participate
Date of birth
Registered
Activity

Specialization

Инженер встраиваемых систем, Системный инженер
Ведущий