LINUX.ORG.RU

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

 , , ,


0

4

Цель разработки компилятора – полная совместимость с синтаксисом языков Си и С++ при обеспечении полной безопасности работы с памятью. Заявляется, что для использования достаточно пересобрать существующий код, так уже компилируются и работают 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)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.