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

Firmware Security Engineer

Send message

Не упомянуто главное отличие x86 от других популярных архитектур - memory ordering model.

x86 реализует сильную модель - Total Store Ordering, и очень многие программисты вообще не представляют, что бывают более слабые модели, и если на это не расчитывать, то в однопотоке вроде бы все хорошо, а многопоточный софт сразу приходит в полную небоеготовность. Какие там размеры кэш-линий и страниц памяти, если у вас любой забытый memory barrier в дальнем углу приводит к полной жопе неразберихе...

Вот почитайте лучше Linux Journal в двух частях, а то осатанеете свой многопоточный софт портировать намного раньше, чем вас более широкая кэш-линия начнет за производительность кусать.

Бери UEFITool 0.28.x, а не UEFITool NE, последний модификацию пока что не умеет, и это - его самая востребованная, но пока не реализованная фича, потому что старый движок умер под грузом неправильных архитектурных решений и умолчаний, а на новый нет и времени, и необходимости.

Отдельно скажу, что лучше драйверы ФС не из прошивки загружать, а с ESP через механизм DriverXXXX, или через подходящий промежуточный загрузчик вроде OpenCore. Так их и обновлять сподручнее, и сломать прошивку ими сложнее, грузить их нужно только если у тебя все ОС на этой ФС, а не только некоторые.

Давайте расскажу немного на примере UEFITool, на разработку которого донаты я не принимаю принципиально после нескольких случаев крайне неудачного опыта именно с людьми из бывшего СССР.

Дело в том, что наши люди плохо понимают, что донат - это "вот тебе, братан, немножко денег, потому что мне нравится то, что ты делаешь", а не "вот тебе, братан, немножко денег, теперь ты будешь делать то, что я скажу".

Нет, не стану, хотите сказать спасибо - скажите, хотите пожертвовать денег - пожертвуйте тем, кто в них нуждается. А я как делал то, что я хочу, и в том темпе, в котором хочу - так и продолжу. Хотите повлиять на это - давайте разговаривать, трекер на Гитхабе открытый, почту я тоже читаю, и даже отвечаю на нее. Хотите новую фичу сегодня-сейчас - пишите сами, код открыт, пулл-реквесты принимаются.

Предлагаю в качестве альтернативы рассмотреть также JSON5.

Атаки на срыв стека в этом смысле побеждены
Да если бы, блин горелый! Побеждены они буквально в паре программ, которые непрерывно атакуют, а там, где атакуют чуть менее яростно — цветут пышным цветом.

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

Задача безопасника гораздо шире задачи разработчика, потому что последнему нужно, чтобы программа, грубо говоря, выдавала ожидаемый результат при ожидаемых входных данных за ожидаемое время. Платят ему именно за это, и спрашивают именно за это, и инструменты его под это заточены. Безопаснику же нужно, не навредив «правильному» пути в этом огромном дереве принятия решений, отрубить как можно больше ветвей, ведущих к исполнению произвольного кода, который атакующий каким-то образом желает исполнять. А если у нас программа еще и с секретными данными работает — дополнительно предотвратить утечку этих данных по каким-либо сторонним каналам. Т.е. борьба и с возможностью и перехода программы в «неожиданные» состояния, и с возможностью сборки из таких состояний и переходов т.н. weird machine.

Вот эти задачи — они кратно сложнее «обычного» программирования, и именно они приводят к требованиям и ограничениям, которые «обычные» разработчики потом яростно ругают за то, что они ограничивают полет их мысли и свободу их самовыражения, не понимая, что без этих ограничений, процессов, линтеров, статических анализаторов, компиляторов, и прочего тулинга даже минимально безопасное ПО написать буквально нельзя, потому что комбинаторный взрыв, потому что бизнесу это ПО нужно уже сегодня, и потому что мы тут такие же люди, как и «обычные» разработчики, и ограничены таким же образом.

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

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

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

Корпорация отчуждает результаты твоего труда сразу и в полном объеме, потому что именно за этот труд и его результаты корпорасты деньги и платят. Русское выражение "заработная плата", т.е. "плата за работу" проигрывает в выразительном смысле английскому compensation. Работодатель буквально компенсирует деньгами, страховками, фитнес-центрами, и прочим остальным тот факт, что теперь он - обладатель прав на результаты твоего труда, твои идеи, твой код, твои действия и бездействия. И ты их добровольно передал в результате относительно честной сделки (насколько она может быть честной при большой разнице возможностей, понятно), от которой выгоду получают оба ее участника - корпорация монетизирует твои идеи, код и т.п., а ты при этом освобождаешься от необходимости заниматься этой монетизацией самостоятельно.

Более того, иногда мотивы у корпорации могут быть совершенно отличными от банального "вон чувак умеет программировать, давайте купим его время и мозги, чтобы он нам напрограммировал всякого". Там может быть и "давайте наймем чувака раньше конкурентов, чтобы он им не принес никакой пользы", "давайте наймем чувака, чтобы он перестал нас шельмовать в медиа за косяки, которые он нашел, а мы не исправляем", и т.п.

У меня тут вокруг заметное количество очень сильных, иногда буквально гениальных людей, и почти десяток лет работы с ними научили меня всякому, в том числе тому, что процессы, правила, линтеры и запреты на использование языковых конструкций, которые слишком часто используются неверно даже гениальными людьми, потому что они в первую очередь все таки люди - они не просто необходимы, они неизбежны, также, как и разделение труда и специализаций. Нет, никто не предлагает делить до такой степени, что левую резьбу крутит инженер-леворезьбовик, а правую - инженер-праворезьбовик, но вы буквально упретесь в когнитивные возможности человеческого мозга "понимать все" и "видеть всю картину" уже на уровне RTL, не имея еще никакого ПО вообще.

Настоящего "фуллстека" буквально не бывает, потому что сложность у современных вычислительных систем - абсолютно запредельная, глубокоуважаемый @YuriPanchul не даст соврать. Поэтому договариваемся на берегу про словарь и умолчания, делим обязанности, и жрем этого слона по частям, больше никак.

Тогда давайте заменим в оригинальном коде все вхождения повторяющегося паттерна
if (assertion_evaluating_to_true) {
    error_handling();
    goto cleanup_label;
}

На широко известный в узких кругах макросrequire_action(assertion_evaluating_to_false, cleanup_label, error_handling());
Код станет короче, понятнее, и «голого» goto для обработки ошибок там больше не останется, т.е. если goto там таки появится — он начнет намного яростнее бросаться в глаза, и все такие места можно будет найти грепом, и при этом не нужно будет отделять обработку ошибок от выходов из глубоких вложенных {} и т.п.
8-часовой рабочий день — это ограничение на способы ведения бизнеса, такие же, как статическая типизация — на способы писать программы. И то ограничение, и другое успешно доказали свою полезность при массовом внедрении, тем не менее, по-прежнему достаточно людей, считающих, что «за 40 часов в неделю мы ничего не успеем» (дословная цитата моего бывшего тимлида, и вообще весьма популярная идея среди окружающих меня американцев), и что «эта ваша статическая типизация — это дурацкое ограничение моей свободы самовыражения». Идите самовыражовывайтесь куда-нибудь туда, где от вас не будет вреда, торгуйте там своими шедеврами, у нас же тут вроде свобода, рынок, капитализм, вот это все.

Современное IT — это не Computer Science, это Software Development для большей части, и Software Engineering для меньшей. Мы тут ПО не «разрабатываем», мы его буквально строим из относительно стандартизированных кирпичей под руководством людей, которые учились именно строительству и именно из кирпичей. И задача этих людей в том, чтобы стройку не нужно было прекращать потому, что один из строителей попал под автобус, и построено было то, что хотел заказчик, а не то, что само как-то получилось, потому что у строителей был творческий порыв. Если вы не хотите быть строителем — ваше право, будьте архитектором, дизайнером, визионером, кем угодно, только строить не мешайте, ёкарный бабай!

Ну и по поводу мешающих жить ограничений, вот вам мнение человека, который на Расте, языке с драконовскими (по сравнению с C) ограничениями на свободу самовыражения, написал не просто мелкую утилиту, а драйвер режима ядра для видеокарты, не имея при этом никакой документации на нее.
All the concurrency bugs just vanish with Rust! Memory gets freed when it needs to be freed! Once you learn to make Rust work with you, I feel like it guides you into writing correct code, even beyond the language's safety promises. It's seriously magic! ✨
There is absolutely no way I wouldn't have run into race conditions, UAFs, memory leaks, and all kinds of badness if I'd been writing this in C.
In Rust? Just some logic bugs and some core memory management issues. Once those were fixed, the rest of the driver just worked!!

Призыв изучать все подряд поддержу, все остальное - точно нет.

Дело в том, что ваше "творчество" именно что никому в бизнесе не нужно, там нужен предсказуемый результат к предсказуемым же срокам. Хотите творить - творите у себя дома, выкладывайте в открытый доступ (или не выкладывайте, дело ваше), но за деньги бизнеса этот самый бизнес хочет решения своих задач в той постановке и теми средствами, которые он считает для себя оптимальными. Более того, уже на этапе, когда разработчиков станет больше одного, придется договориться о том, сколько где ставить пробелов и в каком порядке модули подключать, потому что иначе кому-то обязательно придется терпеть неудобства, и поручить применение этих правил ко всем изменениям автоматике - это экономия времени и усилий всех участников-людей.

То же самое и с отсутвием goto (от которого ушли вовсе не потому, что Дейсктра такой влиятельный, а потому, что устали бороться с настоящими проблемами, вызванными его наличием и неправильным использованием, а именно с добавленными "творцами" непредсказуемыми переходами хрен знает куда, отчего рассуждать сколько-нибудь успешно о настоящем control flow стало невозможно. Да, его можно использовать правильным образом, но мы не умеем, также как мы не умеем самостоятельно управлять памятью в Си-подобных языках. Исключения, кстати, тоже выкинули по похожим причинам - переход хрен знает куда во время выполнения программы, это не только очень грустно с точки зрения производительности, но еще более грустно с точки зрения поддерживаемости, отлаживаемости, и вообще возможности понять, что в программе происходит, может произойти, и не может произойти, не запуская ее и не имея полного набора всех возможных входных данных).

Проблема "мне дали нож для масла, он тяжелый и тупой, а я хочу скальпель - он легкий и острый" - она очень старая, но у нас тут давно уже не операционная, где один хирург оперирует, а двое ассистентов подают ему инструменты и вытирают пот со лба, а мясокомбинат, в котором вчерашние студенты без опыта очень быстро, почти не думая, лепят бесконечные котлеты, стоя по колено в фарше. Индустрия давно уже успешно доказала самой себе, что среднестатистический разработчик - это человек, который ошибается просто по природе своей, и нужно сделать так, чтобы минимизировать и вред от этих ошибок, и распространение эффектов от них, сделать их как можно более локальными и заметными, либо невозможными в принципе без специальной здоровенной таблички "ОСТОРОЖНО, РАБОТАЮТ ЛЮДИ!". И goto, и исключения, и прямой доступ к оборудованию, и ручное управление памятью, и динамическую типизацию, и права рута, и доступ к внутренностям ОС, и все похожее остальное у вас отобрали чтобы защитить вас от вас самих же, а бизнес - от ущерба, который вы наносите тем фактом, что вы обычные люди, и у вас бывает плохое настроение, неудачный день, "мозговой пердеж", недосыпание, недостаток кофеина в крови и знаний в голове. Вот это все выше - не "поветрия", а неизбежность, и ограничения подобные возникают и кодифицируются при любой совместной работе множества людей над любыми большими проектами, в которых ошибки дороги, а люди - обыкновенные люди.

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

Добавлю еще, что современные аллокаторы пришлось научить в дополнению ко всему остальному еще и предотвращению эксплуатации типичных для небезопасных ЯП проблем вроде double free, use-after-free и т.п., вот прекрасная статья Саара Амара о нынешнем состоянии memory safety.

Следующим шагом будет расширение подобного простого NVS до полноценной NVRAM, для чего понадобятся:

  • wear-out leveling, т.е. выравнивание нагрузки на страницы флеша, чтобы многократная запись в переменную Х использовала не только страницу, куда Х была записан изначально, но все доступные по очереди.

  • fault-tolerant write, т.е. такой алгоритм записи в переменную, который гарантирует, что "настоящей" эта запись станет исключительно после того, как все данные и все критические для правильной работы метаданные уже записаны, а все остальное можно однозначно восстановить после перезагрузки.

  • transparent storage backup, т.е. такой алгоритм управления хранилищем, который гарантирует, что при его разрушении у нас есть копия большинства переменных, пусть даже и не самая свежая.

Понятно, что нужно вот это все только там, где софт много пишет в свою же NVRAM по разным причинам. Именно так делают большинство современных систем вычислительных систем разных архитектур, в том числе ПК на х86 (использующие UEFI NVRAM), вся техника Apple (iBoot NVRAM), и т.п.

Только 4 Гб, и тот факт, что MS не могут исправить проблему со слишком большими файлами (особенно с учетом того, что формат WIM поддерживает нативно нарезку на файлы любого размера) и тем, что установщику ОС не нравится наличие EFI-раздела на носителе, с которого происходит установка - результат безалаберного отношения к тому небольшому количеству пользователей, которые устанавливают ОС с нуля, а не получают ее предустановленой при покупке железа.

UEFI тут не при чем, и винить его разработчиков не в чем.

Потому что очень устали тренировать десятки гигабайт памяти 16-битным кодом с 64кб на страницу и пояснять такому же 16-битному коду на ассемблере, написанному в 1992 году, что у нас теперь диски по 2 терабайта, и переферия вся подключена по USB.

Ко временам чипсета P55 там в 16-битном БИОСе этом творилась такая дикая вакханалия чада и угара, что переход на UEFI Platform Interface (т.е. на PEI/DXE/BDS) в следующем поколении решил огромное количество проблем. При этом некоторые вендоры даже не стали этот самый UEFI публиковать, все равно на тот момент загрузчиков совместимых почти не было, и прошивка продолжала делать вид, что она BIOS, с переменным успехом. Некоторые вендоры потом таки опубликовали новый интерфейс обновлением прошивки, но есть еще модели, в которых это приходится делать разблокировкой скрытых опций. К 2012 году на UEFI PI в качестве базы и UEFI в качестве интерфейса с загрузчиками и ОС ПК-индустрия перешла окончательно, последние сервера HP с БИОСами как раз в конце 2011 и вышли, ЕМНИП.

В общем, зачем - чтобы жить проще стало и не нужно было писать на ассемблере драйверы для USB, PCIe и Thunderbolt, и потому, что вендоры процессоров продавили с одной стороны, в вендоры ОС - с другой. Intel к тому времени над UEFI работал уже 13 лет, и уже лет 5 как поставлял Memory Reference Code в виде 32-битного бинаря, который с 16-битным БИОСом тоже надо было женить при помощи мата и уговоров, поэтому рано или поздно с дохлой лошади наконец слезли, и теперь вот понемногу слезают с CSM, который уже отключен по умолчанию почти на всех платах начиная с 2020 года, а на некоторых его уже нет совсем.

В действительности, все не так, как на самом деле.

BIOS - это собирательное название прошивок x86 систем в том виде, в котором их начала выпускать IBM, т.е. таких, которые стартовали и работали в 16-битном режиме исполнения, имели текстовый или псевдографический интерфейс BIOS Setup, и предоставляли операционной системе интерфейс BIOS Interrupt Call, основанный на программных прерываниях. По мере развития железа и перехода на 32, а затем и 64-битные процессоры 16-битная прошивка стала серьезной обузой, как и устаревший и несовместимый с новыми устройствами интерфейс BIOS IC, и от них начали понемногу избавляться в пользу комбинации из трехфазового Platform Interface (32-битной Pre-EFI Initialization, где происходит тренировка памяти, чтобы перестать исполнять код с SPI flash, 32\64-битной Driver Execution Environment, где происходит вся остальная инициализация железа, и 32\64-битной Boot Device Selection, которая рисует графический Setup, запускает Option ROMы, находит на известных ей ФС загрузчик ОС и передает на него управление). При этом BDS (совместно с DXE) и реализует тот самый Unified Extensible Firmware Interface, который загрузчик ОС затем использует вместо устаревшего BIOS Interrupt Call. Тем не менее, последний все еще поддерживается на многих системах при помощи механизма Compatibility Support Module, который позволяет UEFI-совместимой прошивке публиковать не только свой нативный (32\64-битный) UEFI, но и оставленный для обратной совместимости 16-битный BIOS IC, и сделано это при помощи довольно хитрых трамплинов в старый режим и обратно. Запускается CSM частично в D
XE, частично в BDS, а работает только в BDS (потому что загрузчики ОС работают только там).

Таким образом, из "BIOS запускает UEFI", и "UEFI запускает BIOS" - это бессмысленные выражения. На старых компьютерах 16-битный BIOS имел 16-битный интерфейс IC, и никакого UEFI там не было еще. На новых компьютерах 32-битный PEI запускает 32\64-битный DXE, который запускает 32\64-битный BDS, который имеет либо только 32\64-битный UEFI, либо еще и 16-битный CSM, который эмулирует старый 16-битный IC в достаточной степени, чтобы старые загрузчики запускались.

BIOS IC и UEFI - не единственные интерфейсы между прошивкой и ОС на x86, как и BIOS и PI не единственные способы добраться до них. Вместо BIOS и PI можно использовать coreboot, вместо DXE/BDS/IC/UEFI - напрямую запускать ядро Linux или любой другой ОС. Интерфейс UEFI тоже не обязательно публикуется DXE и BDS, его могут публиковать и другие загрузчики, например, uBoot или TianoCore payload для coreboot.

Короче: BIOS - это собирательное название 16-битного всего, что работало на старых х86-машинах до ОС. UEFI - это интерфейс между прошивкой и ОС, и ничего больше. Прошивка же сама по себе называется "UEFI-совместимой", если на публикует вышеупомянутый интерфейс.

coreboot уже работает на Alder Lake, пока что только на одной плате, ребята из Dasharo недавно демонстрировали на Open Source Firmware Conference.

С полноценной нейтрализацией через me_cleaner пока непонятно, но поддержку отключения HAP-битом для Alder Lake уже скоро добавят.

Дисклеймер: кода чужого не видел, утечек никаких не качал, пересказываю людей из твиттера, цитировать меня не надо, пожалуйста.

Поправлю немного, утечка произошла не у Intel, а у LCFC, подразделения Lenovo по выпуску линеек для обычных пользователей (Yoga и подобных). Вот хороший пост про это все.

ThinkPad'ы на этом заводе не делают, и их прошивки разрабатываются другой командой.

Внутри утечки не только референсный код Intel для Alder Lake, но и очень много кода платформы Insyde H2O, практически весь код, специфичный для продуктов LCFC, свежие версии разных внутренних утилит Lenovo, несколько типов закрытых ключей, и т.п.

Очередной сильный удар по репутации Lenovo, но им не привыкать, отряхнутся и дальше пойдут.

Intel перестал выпускать десктопные платы довольно давно, а всякие NUCи и прочее отдано на аутсорс AMI, и базируется на AMI AptioV, одной из самых дырявых платформ для х86-прошивок из используемых.

MS делает десктопные компьютеры и ноутбуки довольно давно, и тоже начинали с покупки лицензий у IBV, но года 4 уже делают прошивки сами на основе EDK2, и получается у них весьма неплохо, особенно после старта проекта Secured-core PC.

К сожалению, нормальных производителей компьютеров на х86-процессорах, с точки зрения безопасности прошивок, остается все меньше с каждым годом. Apple ушел с этого рынка, HP испортился (HPE еще вроде держится, но даже там сделали свой SureStart поверх обычного EC и называют это "решением"...), Lenovo как никогда до топов не дотягивала, так и сейчас не дотягивает, а производители второго эшелона вроде Asus/Gigabyte/MSI никогда безопасностью прошивок и не интересовались.

В итоге относительно нормальные x86-машины с относительно безопасными прошивками делают теперь только MS (и, может быть, Dell, но MS лучше все равно, потому что используют свои собственные наработки из Project Mu, а не непонятный код от IBV), и потому, кроме какого-нибудь последнего Surface Laptop Go 2 for Business, покупать решительно нечего.

Потогонка у них это "работа", а нормальная работа вида "головой, а не 20 часов в сутки" - это "уход". Уважаемые авторы, пожалуйте, не распространяйте этот ублюдочный термин, проплаченный очередными PR-специалистами на зарплате. Никакого ухода там нет и не было, и то, что люди наконец-то в массе начинают догадываться, что "то везет - на том и едут" - это благо.

Только не Secure Boot, а просто EFI boot, потому что первое - это про то, что собранный загрузчик подписан, и его подпись EFI-совместимая прошивка проверяет до того, как передаст управление на его точку входа.

Не совсем понятно, зачем тут ассемблер, кроме как "захотелось вот на ассемблере", потому что все, что тут на ассемблере написано - это переопределения типов данных из С, части структур из Extended Firmware Interface тоже из С, и вызов функций с интерфейсом MS x64 ABI.

Выучите лучше С, намного легче станет писать что-то сложнее хелловорлдов, а ассемблер оставьте для задач, которые на С либо решаются плохо (мужики из coreboot'а в свое время ROMCC не от хорошей жизни написали), либо не решаются совсем. Ссылку на EDK2 и TianoCore уже сверху давали.

Information

Rating
Does not participate
Date of birth
Registered
Activity

Specialization

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