LINUX.ORG.RU

Проект TrapC развивает Си-подобный язык, безопасно работающий с памятью

 , ,


1

5

Проект развивает Робин Роу (Robin Rowe), бывший профессор компьютерных наук, принимавший участие в комитетах по развитию стандартов С и С++, в своё время создавший графический редактор Cinepaint, использовавшийся при создании некоторых голливудских фильмов, и POSIX-библиотеку libunistd для Windows. Соучредителем компании Trasec выступает Габриэль Пантера (Gabrielle Pantera), занимавшая руководящий пост в компании Disney.

Из особенностей:

  • Проверки выхода за границы массива. В TrapC применяется фундаментально иной способ работы с указателями и специальный механизм перехвата ошибок на основе обработчиков исключений (trap).

  • Проверки use after free.

  • Наличие GC.

  • Выделение памяти через new. *alloc и free нет.

  • Явная инициализация нулями.

  • Строгая типизация.

Исходный код компилятора для TrapC планируют открыть в 2025 году.

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

★★★★★

Проверено: maxcom ()

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

На ассемблере должно обходиться, но специально я это не проверял.

Именно испортить указатель или через него получить доступ за пределами нельзя. Там аппаратная проверка. По ссылке подробно описано.

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

Вот есть уязвимость в shell или в сервисе — это особой разницы не имеет. Сервисов много. Но то, что 90% векторов атак закрываются автоматически, заметно повышает общую безопасность.

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

Именно испортить указатель или через него получить доступ за пределами нельзя.

Если есть возможность сделать

uintptr_t i = p;
i += offset;
char *p2 = i;

то пофиг, какая там проверка.

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

Может, мы обсуждаем разные вещи. Для меня лично нет разницы на каком уровне реализована хэш-таблица. Язык, рантайм, либа – какая разница? Хэш-таблица и в Африке хэш-таблица.

Собственно, я не вижу каким образом отсутствие управления памятью вредит программам. Уже продолжительное время пишу на C и Go. Когда приходится заботиться о памяти, хотя мне не посчастливилось встретиться с этой проблемой, нужно оперировать понятиями GC. Можно считать это абстракцией, с присущими ей достоинствами и недостатками, как у любой абстракции.

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

Так нельзя сделать. Можно написать на ассемблере функцию что будет создавать нужные указатели. Эта защита похожа на адрес санитайзер.

Эти указатели не совместимы со стандартом Си. Можно сконвертировать указатель в intptr, но нельзя обратно.

Поэтому, например, нельзя сделать выравнивание указателя вот так:

p = (char*)(((intptr_t)p + 15) & ~15);

Нужно так:

p += -(intptr_t)p & 15;
jpegqs
()
Последнее исправление: jpegqs (всего исправлений: 1)
Ответ на: комментарий от wandrien

Вот пример:

printf("%zu, %zu\n", sizeof(void*), sizeof(intptr_t));

В режиме с защищёнными указателями теневая часть указателя не переводится в intptr.

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

это(большая безопасность за счёт аппаратных «издержек») преимущество «неуловимого Джо»

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

само по себе тегированное железо не новость но в первом мире оно маргинально :)

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

былы времена когда не только функции в библиотеках но и сама машинерия «вызова» функции это кодовые вставки из «библиотек» (например железки где нет стека а организация кода полностью прерогатива софта)

зачем быть таким прибитым к «одной единственно верной» реализации?

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

Именно испортить указатель или через него получить доступ за пределами нельзя. Там аппаратная проверка.

Проверил. В user-mode нельзя скрафтить произвольный указатель. Зато можно получить указатель на все статические данные текущей программы (которая приложение, про библиотеки не знаю). Если в статических данных хранятся какие-то ключи, то к ним можно получить доступ. Но традиционные способы получить RCE закрыты. Поэтому я не вижу способов это эксплуатировать.

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

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

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

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

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

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

Это, мягко говоря, спорное утверждение.

А с каким утверждением спорите? В том сообщении их много.

Вы считаете, что сложность языка определяет способ записи его конструкций ?

Смотря что понимать под словом «сложность». Сложность изучения часто зависит от способа записи конструкций. Например, конструкции Haskell и APL сходу сложно выучить. В отличие от конструкций BASIC, например.

А сложность языка в смысле семантики, разумеется, от конструкций не зависит. И даже сложность восприятие конструкций достаточно субъективна. Кому-то хорошо читается COBOL, кому-то APL.

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

Эти указатели не совместимы со стандартом Си.

Совместимы.

Вот это выполняется:

The following type designates a signed integer type with the property that any valid pointer to void can be converted to this type, then converted back to pointer to void, and the result will compare equal to the original pointer:

Только после «converted back to pointer» по ним нельзя объект читать.

Стандарт разрешает блокировать указатели из чисел: «An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.».

monk ★★★★★
()
Ответ на: комментарий от wandrien
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
int main() {
  int *p = (int*)malloc(sizeof(int));
  intptr_t c1 = (intptr_t)p; 
  int *k = (int*)realloc(p, sizeof(int));
  intptr_t c2 = (intptr_t)k;
  *k = 2;
  if (c1 == c2) {
    *(int *)c1 = 1;
    printf("%d %d\n", *(int *)c1, *(int *)c2);
  }
}

Выводит 1 2 на clang. Хотя тут формально даже UB нет: к p я после realloc не обращаюсь, по адресу из c1 пишу после того, как убедился, что он указывает на k (равен c2).

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

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

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

Хотя тут формально даже UB нет

Есть:

The original pointer ptr is invalidated and any access to it is undefined behavior (even if reallocation was in-place).

https://en.cppreference.com/w/cpp/memory/c/realloc

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

Не надо путать список и связный список это не одно и тоже.

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

Так к p нет доступа после строки

int *k = (int*)realloc(p, sizeof(int));

Могу даже так переписать, чтобы даже области видимости не было:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
int main() {
    intptr_t c1;
    int *k;
    {
        int *p = (int*)malloc(sizeof(int));
        c1 = (intptr_t)p; 
        k = (int*)realloc(p, sizeof(int));
    }
    intptr_t c2 = (intptr_t)k;
    *k = 2;
    if (c1 == c2) {
        *(int *)c1 = 1;
        printf("%d %d\n", *(int *)c1, *(int *)c2);
    }
}
monk ★★★★★
()
Ответ на: комментарий от monk

А с каким утверждением спорите? В том сообщении их много.

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

Смотря что понимать под словом «сложность». Сложность изучения часто зависит от способа записи конструкций.

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

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

который оптимизатором определяется как алиас на p.

c1 - это число. Где в стандарте указывается алиасинг для чисел?

Могу так сделать

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
 
int main() {
    intptr_t c1;
    int *k;
    {
        int *p = (int*)malloc(sizeof(int));
        c1 = (intptr_t)p; 
        k = (int*)realloc(p, sizeof(int));
    }
    intptr_t c2 = (intptr_t)k;
    intptr_t x = c1 + 5;
    intptr_t y = x - 5;
    *k = 2;
    if (y == c2) {
        *(int *)y = 1;
        printf("%d %d\n", *(int *)y, *(int *)c2);
    }
}

y – это число, полученное путём некоторых арифметических операций из числа c1 и равное c2. Но всё равно объект, полученный из указателя, полученного из этого числа не тот, который получается из равного ему числа c2.

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

c1 - это число. Где в стандарте указывается алиасинг для чисел?

Ну тут оптимизатор сам себя перехитрил, я думаю. Логика его тут понятна. А вот насколько она обоснована, это вопрос…

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

Но «the result will compare equal to the original pointer» выполняется. (int *)y == k.

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

Стандарт разрешает из одинаковых чисел получать указатели на разные объекты. Или вообще неработающие указатели. Оптимизатор пользуется.

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

Не надо смешивать список как АТД и список как структуру данных.

Так и я о том. В Python конструктор list() создаёт другую структуру данных. Не список.

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

это очень фрактальнная ситуация

и python( в прочем как и любая открытая(по сырцам){конкретнее обозримая и в пределах «5+-2» постигаемая система<антитеза немыслимой/по Биру Стафарду>}система})

вопрос как привить «виденье» с низу в верх вы знаете(ибо реализовали свой велосипед с колёсами из фигур постоянной ширины) как устроенно теперь начните применять эту компоненту

али с верху в низ вы умеете (ибо в тех и тех «курсачах» использовали эти компоненты как чёрные ящики блюдующие согласованные контракты и обнаружили что частично рекурсивные функции не всюду определены ибо таков путь)оперировать компонентой теперь катите реализацию

али полный спектр охватывающий(и возможно не ограниченый) вышеприведённые 'крайности'

ps. инструментализация(и экспоненциальный рост о общей вычь моще) позволяет использовать в качестве нотации ваще любую произвольную «достаточно полную» 'систему указаний действий и хранения данных и их обмена'

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

А уже на стеке просто так указатель не получить.

Эти указатели не защищают от Use-After-Free, достаточно аллоцировать много памяти, записать указатели, освободить память. А указатели останутся корректными, по ним можно получить доступ к уже чужим данным. То же самое со стеком, выделить много стека, запомнить указатель, освободить стек, теперь по указателю у нас есть окно. Впрочем, памяти много и можно выделять всегда в разных местах. И насчёт стека я не уверен, может там еще какие-то защиты понатыканы, тем не менее, указатель будет корректный.

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

см

https://tinlizzie.org/IA/index.php/Alan_Kay_at_OOPSLA_1997:_The_Computer_Revo...

лаг по времени между Кнутовым литературным программированием и распространением ещё даже не в индустрии Jupyter блокнотов (ipython не подходящее имя :( )

полезно переодически пробегать глазами:

https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf

ради понимания что на одном и том тексте совсем разное вчитывается как функция уровня читающего :)

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

Учить полгода Rust вместо использования уже знакомого Си мало кто будет, легче взять TrapC.

Абсолютно согласен. Мало того, я лично руками и ногами за такой язык. Как-то у меня давно прошли времена, когда лихо гусарствовал с адресами на Си и PDP-11/VAX макроассемблере. Как-то хочется спокойно и без лишних нервов нужные утилиты покод(ж)ивать.

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

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

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

Как-то хочется спокойно и без лишних нервов

на Си

Ловите наркомана!

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

Если не страивает стандартная реализация просто пишешь свою. В чем проблема-то?

sabacs
()

Из глубин интернетов пишут:

I don’t use C cause it’s «fast». I use it cause it’s Simple (Simple != Easy). If you dismiss the Simplicity Argument with «I’d sAcRiFiCe sPeEd fOr cOnVeNiEnCe» you are a moron who can’t listen and should not be taken seriously (too many such cases). If I needed speed I’d use Rust

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

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

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

На текущем этапе развития, собираемые в Fil-C программы медленнее примерно в 1.5-5 раз, по сравнению со сборкой обычными компиляторами. В планах заявлена работа по проведению оптимизации. Предполагается, что после завершения этой работы в большинстве случаев код будет выполняться медленнее в 1.2 раза, а в наихудших сценариях замедление не превысит полтора раза.

Хмм. С такими показателями лучше писать на Расте.

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

Ещё хуже:

Другим ограничением Fil-C является принципиальный отказ от сохранения совместимости на уровне ABI для кода на C/C++, что не позволяет связывать собираемый в Fil-C код с библиотеками и объектными файлами, собранными другими компиляторами. Методы вызова функций и способ динамического связывания в Fil-C отличается от существующих компиляторов и компоновщиков. Подобное решение объясняется тем, что при связывании с незащищённым кодом теряется суть предлагаемой в Fil-C защиты и возникает иллюзия защищённого приложения - при наличии совместимости ABI, у разработчиков возникал бы соблазн собрать в Fil-C лишь отдельные файлы, не утруждая себя портированием всего проекта.

dataman ★★★★★
()

бывший профессор компьютерных наук

Сдулся склифасовский.

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

лучше писать на Расте.

Ловите наркомана!

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

лучше писать на Расте

Говорила сестрица Алёнушка братцу Иванушке:

- Не пиши, братец, на Расте, небинарной личностью станешь!

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