LINUX.ORG.RU

Fil-C — компилятор для языков C и C++, гарантирующий безопасную работу с памятью

 , , ,


1

6

Цель разработки компилятора – полная совместимость с синтаксисом языков Си и С++ при обеспечении полной безопасности работы с памятью. Заявляется, что для использования достаточно пересобрать существующий код, так уже компилируются и работают bzip2, zip, pcre и ncurses. С незначительными модификациями поддерживается сборка OpenSSH, OpenSSL, CPython, SQLite, Lua, Curl, Lynx, jpeg6b, zsh, xzutils и simdutf.

Защита обеспечивается благодаря применению 128-битных указателей и сборщика мусора. Если защита отслеживает ошибку, программа аварийно завершается, что позволяет не эксплуатировать уязвимость.

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

Компиляция занимает в 1,5-5 раз больше времени, чем у gcc. Скорость выполнения в 1.2 раза ниже, чем при работе аналогичных программ, скомпилированных gcc. Пока компилятор доступен только для linux-платформ, такое решение было принято разработчиками для того, чтобы не распылять усилия. Линковка с объектным кодом, созданным другими компиляторами, невозможна в силу разного ABI.

Задействованный в Fil-C механизм MonoCap основывается на применении 16-байтовых указателей, в которых помимо адреса в памяти, указывается ссылка на объект, включающий сведения о возможностях (capability), таких как верхняя и нижняя границы буфера, ассоциированного с указателем, а также массив, определяющий типы данных, хранимые в каждом блоке памяти (1 байт с информацией о типе (unset, int, ptr, free) для каждого 16-байтового блока памяти). При каждом обращении к памяти по указателю осуществляется проверка границ и типа (например, в память с типом «ptr» не могут быть записаны данные с типом «int» и наоборот).

Все операции выделения и освобождения памяти обрабатываются сборщиком мусора FUGC (Fil’s Unbelievable Garbage Collector), который при освобождении памяти переводит все связанные с освобождаемым буфером записи о типах в значение «free» и затем перенаправляет все указатели на освободившиеся объекты на отдельный объект, сигнализирующий о том, что память уже освобождена. Любое дальнейшее обращение к блоку данных с типом «free» или по указателю, связанному с освобождённым объектом, приводит к генерации исключения, что позволяет защититься от уязвимостей класса use-after-free. Сборщик мусора работает параллельно и не приостанавливает выполнение других потоков.

Использование комбинации из MonoCaps и FUGC позволяет сохранить возможность привычной работы с указателями и оставить неизменной семантику вызовов malloc и free, предоставив при этом гарантированную защиту. Код программы может содержать различные логические ошибки, такие как неправильное приведение типов, неверные арифметические операции с указателями, состояния гонки и несвоевременный вызов функции free(), но независимо от всего этого, Fil-C запомнит исходные границы и тип данных, и прервёт выполнение, если будет предпринята попытка доступа по указателю к области вне запомненных границ, обращения к освобождённому блоку памяти или чтения данных с типом «int» как указателя или наоборот.

Автор Fil-C, Филипп Пизло (Filip Pizlo), занимает в компании Epic Games пост директора, отвечающего за проекты, связанные с языками программирования. Филипп имеет богатый опыт работы над виртуальными машинами, языками программирования, компиляторами и сборщиками мусора, например, в IBM он развивал язык программирования X10, в Microsoft работал над сборщиками мусора Stopless, Clover и Chicken, в Apple занимался JIT-компилятором и оптимизациями браузерного движка WebKit, в Epic Games возглавляет команду разработчиков, развивающую язык программирования Verse и связанную с ним виртуальную машину. Филипп также является одним из ключевых разработчиков виртуальных машин Jikes RVM, Ovm и Fiji VM.

>>> Подробности

★★★★★

Проверено: hobbit ()
Последнее исправление: unfo (всего исправлений: 7)

Хотелось бы услышать авторитетное и непредвзятое мнение о сей инициативе у уважаемых граждан @Stason и @firkax.

Ygor ★★★★★
() автор топика
Ответ на: комментарий от gns

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

sartakov
()

1.2x стоимость по поризводительности кажется мало реалистичной для такого количества фич, хотя в принципе MPX инструментация и ее софтовые аналоги вполне себе укладывались в этот интервал. любые увеличения размеров поинтеров ведут к засеранию кеша, так что честные оценки стоимости весьма условные ибо зависят от особенностей кода: в CHERI обработка данных вообще в ноль выходит, а может и 20-30% показать.

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

sartakov
()
Ответ на: комментарий от Ygor

Думаю что идея интересная но лично я вряд ли буду использовать.

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

firkax ★★★★★
()
Ответ на: комментарий от gns

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

firkax ★★★★★
()
Ответ на: комментарий от sartakov

Да все просто. Есть некий бандл памяти. В начале бандла лежит массив структур вида

struct some_struct {
   ...... (какие-то нужные поля)
    union {
        char *k_path;     /* file path -- kernel's view */
        ptrdiff_t u_path; /* file path -- userspace view */
    } p;
    struct hlist_node node;
}

После этого массива лежат выровненные на 8 байт строки, на начало строки светит поле u_path (оффсет от начала бандла, например).

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

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

Сверху плюсы, внизу С. Ну и все друг друга знают как родные.

gns ★★★★★
()
Последнее исправление: gns (всего исправлений: 2)
Ответ на: комментарий от firkax

Согласен. Мы ж уже спорили о том же применительно к Trap-C и пришли к сходным выводам. Исправлять Си действительно неуместно. Пишите на чем-нибудь другом.

gns ★★★★★
()
Ответ на: комментарий от sartakov

А что это, если не китайский автомобиль?

gns ★★★★★
()
Ответ на: комментарий от firkax

Ну если sizeof(void*) == 16 то твоя схема

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

Может не сработать. Народ любит прибавить к указателю что-нибудь и скастить полученное дальше. Твоя схема на традиционный размер указателя рассчитана, КМК. Или я чот недопонял?

gns ★★★★★
()

Идея компилировать условный «ssh» (и прочий сетевой софт) избавившись от целых классов уязвимостей разом, при этом не переписывая с чистого листа на другой ЯП, конечно выглядит заманчиво.

Вопрос в накладных расходах.

Замедление до 2 раз, как оптимистично предполагает автор — мне представляется вполне оправданным. Если же в пять раз — сомнительно.

wandrien ★★
()
Ответ на: комментарий от gns

Что куда скастить? (ulong)ptr даст сырой адрес без метаданных, работающий обычным образом. (void*)(ulong)ptr даст указатель опять без метаданных для проверок - работать он будет как обычный в Си, преимущества 128-битных потеряет но не сломается. Вся арифметика работает как и раньше.

firkax ★★★★★
()
Ответ на: комментарий от wandrien

В ssh критична к скорости только криптография. Но мне кажется что он и без перекомпиляций надёжен.

firkax ★★★★★
()
Ответ на: комментарий от wandrien

при этом не переписывая с чистого листа на другой ЯП

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

jpegqs
()
Последнее исправление: jpegqs (всего исправлений: 1)
Ответ на: комментарий от firkax

Допустим...

Как будет работать (ptr_to_some_struct*)long_var + 4? И на что в этом случае рассчитывал бы автор кода? Явно же на четвертый элемент массива структур.

gns ★★★★★
()
Последнее исправление: gns (всего исправлений: 1)
Ответ на: комментарий от wandrien

просто скормите исходники ИИ, и он найдет все ваши уязвимости. потому что задачка нулевой сложности.

alysnix ★★★
()
Ответ на: комментарий от firkax

В ssh критична к скорости только криптография.

Как будто в SSL библиотеках ошибок не находят. Была же история несколько лет назад, после чего много OpenSSL форков появилось.

jpegqs
()
Ответ на: комментарий от jpegqs

Была же история несколько лет назад, после чего много OpenSSL форков появилось.

Угу, только у всех форков OpenSSL автор Эрик Янг (автор оригинального OpenSSL).

sarumeister
()
Ответ на: комментарий от gns

Так и будет работать. Как вообще разрядность указателей на это может повлиять?

firkax ★★★★★
()
Ответ на: комментарий от Logopeft

Ну, по описанию, почти не тормозные, но невозможность линковки делает это бессмысленным в проектах чуть больше консольных утилит/небольших демонов.

Shadow ★★★★★
()
Последнее исправление: Shadow (всего исправлений: 1)
Ответ на: комментарий от Shadow

Кстати да, тут либо отдельную архитектуру libc придётся (как 64+32 уже есть) либо все обращения к ОС будут нуждаться в обёртках. Ну вообще 64+32 нормально работает параллельно, почему бы и нет.

firkax ★★★★★
()
Ответ на: комментарий от sartakov

в CHERI обработка данных вообще в ноль выходит, а может и 20-30% показать.

А что это точно значит? Если я правильно понял, на ARM Morello плате стоит ARM Neoverse N1 с расширением CHERI. Неужели они аппаратную реализацию кеша не передалали под capability в таком случае?

dsl
()
Ответ на: комментарий от AntonI

Интересно, доживем ли мы до версии плюсов которая будет иметь обратную совместимость и при этом на уровне ЯП будет исключать утечки?

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

Rust тоже от утечек не защищает.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от gns

Это с самого начало было implementation defined behavior, так что да.

X512 ★★★★★
()
Ответ на: комментарий от dsl

«цена» CHERI зависит от количества указателей (капабилити) используемых в конкретной задаче. есть два экстремума: всë интеджеры (т.е. данные), или всё капабилити (т.е. указатели). соответственно в первом случае падение производительности около 0*, а во втором хз как получится, ну вряд ли больше 30% по опыту. в реальности есть какая-то пропорция, и влияние на производительность разная, вплодь до отрицательной. у меня был тестик один, там для нативного кода довольно старый компмлятор использовался, а для pure-cap очень свежий, ну и выходило что pure-cap был быстрее за счет более современной оптимизации. это так, в рамках шутки о ценности всех этих бенчмарков.

multi-threading к слову довольно часто помогает снизить overhead от CHERI. глянул вот, в 4 потока ggml в pure-cap всего на 1.5% медленнее чем native, считайте бесплатно и погрешность измерения

sartakov
()
Ответ на: комментарий от X-Pilot

Не астрологи. В США на уровне правительства официально набычили на «небезопасные» языки, и стали не рекомендовать пользоваться всякими сями — вот народ и всколыхнулся.

https://www.theregister.com/2024/11/08/the_us_government_wants_developers/

Smacker ★★★★★
()
Ответ на: комментарий от luke

никак. комманда в арме по софту переформирована на что-то более важное (AI я полагаю) – они сделали поддержку PCuABI (некоторые сисколы стыли pure-cap), pure-cap ядро вообще ждать смысла нет, какие-то русские в финском huawei выкатывали свою версию поддержки pure-cap ABI (не в курсе чем лучше/хуже армовых), ну вроде codasip планирует дальше тащить Linux, я в это правда слабо верю, это в значительной степени бессмысленно. может сама комманда CHERI возьмется, не знаю, слабо верится.

sartakov
()
Ответ на: комментарий от mittorn

Хто??

Автор Fil-C, Филипп Пизло (Filip Pizlo), занимает в компании Epic Games пост директора

Он?? Э-э-э-э??

Somebody ★★
()

Не трогайте сишку!

Если не умеете на ней писать — пишите на чём-то другом.
Если считаете что другие не умеют на ней писать — предложите писать на чём-то другом.

Не нужно ломать то, что изначально сломано не понимаете!

mord0d ★★★★★
()
Ответ на: комментарий от mord0d

Это такое тонкое предложение закопать Си или вера в существование программистов на Си которые умеют на нём писать без UB и уязвимостей?

X512 ★★★★★
()
Ответ на: комментарий от gns

Мне вот кстати интересно, что мешало сделать то же самое, но с 64битным указателем, оставив под адрес только 32 бита? Боольшая часть софта вполне помещается в 32битное адресное пространство если не требуется aslr или большие объёмы данных. ABI конечно всё равно бы поломалось (указатель, прилетевший в обычный код становится невалидным), но зато новое ABI было бы по модели данных совместимо с существующим кодом и потребовалась бы просто пересборка из исходников. Так же можно по идее ограничить расположение/выравнивание этих дополнительных структур в памяти (если они достаточно компактные) и дать указателю ещё несколько бит, 36-38 бит уже покроет большую часть софта кроме совсем уж прожорливых случаев
Ограничить указатели 32мя битами можно как это, например, делает wine - просто маппит всю память выше 32 бит, если конечно других способов это сделать нет. Разве что придётся от vdso отказаться т.к он ни по abi ни по адресам не совместим

mittorn ★★★★★
()
Последнее исправление: mittorn (всего исправлений: 2)

У меня один вопрос, зачем???

sabacs
()
Ответ на: комментарий от sartakov

вроде codasip планирует дальше тащить Linux, я в это правда слабо верю

Слишком маленькая команда?

luke ★★★★★
()

Вот если бы анрил скомпилировали было бы круто

doomer
()
Ответ на: комментарий от firkax

В ssh критична к скорости только криптография.

Я не зря дописал «и прочий сетевой софт».

wandrien ★★
()
Ответ на: комментарий от I-Love-Microsoft

Что-то по описанию оно не звучит как будет быстрее чем санитайзер, надо чтоб кто-то попробовал сравнил

pftBest ★★★★
()
Ответ на: комментарий от X512

Это такое тонкое предложение закопать Си или вера в существование программистов на Си которые умеют на нём писать без UB и уязвимостей?

Время покажет.

mord0d ★★★★★
()

Что только не придумают, лишь бы не учить rust, zig или crystal (не люблю go) или что там вам больше подходит под задачу

q0tw4 ★★★★
()

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

Что плохо, в отличие от раста и других изначально безопасных ЯП, эта штука никак не решит проблем в коде. Так что в целом этот костыль в ряде программ может даже ухудшить ситуацию, сообщая вирусописателям об уязвимостях, при том, что авторы и пользователи останутся в неведении.

usermod
()
Ответ на: комментарий от BydymTydym

Ты прочти то, c чего мой коммент возник. Это была критика идеи коллеги vbr.

gns ★★★★★
()
Последнее исправление: gns (всего исправлений: 1)

Линковка с объектным кодом, созданным другими компиляторами, невозможна в силу разного ABI

Но системные shared objects то можно дергать? А в своем чудо-ABI можно создавать so? И как они будут обозначаться, какое расширение?

Впрочем доднедовские exe/dll имеют привычные расширения, но там в заголовках что то помечено что они байткод. Может и тут у ELF будет какой то флаг специфический?

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

И как они будут обозначаться, какое расширение?

А для отдельного ABI нужно новое расширение? Это всегда решалось отдельным установочным префиксом просто.

wandrien ★★
()
Ответ на: комментарий от I-Love-Microsoft

Впрочем доднедовские exe/dll имеют привычные расширения, но там в заголовках что то помечено что они байткод. Может и тут у ELF будет какой то флаг специфический?

А, ты имеешь в виду, если миксовать ABI. Пон. Так можно в эльфе вхерачить маркировку, да. Формат расширяемый.

wandrien ★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.