LINUX.ORG.RU

Си. Почему бы не запретить запись в стек?

 


1

4

Решил немного разобраться как работают уязвимости. Как я понял, весомая их часть модифицирует стек.

#include <stdio.h>

register long unsigned rsp asm("rsp");

void print_arg(int arg) {
    ((int*)rsp)[3] = 0xBADC0DE;
    printf("arg = %x\n", arg);
}

int main(int argc, char **argv) {
    print_arg(0xF00D);
    return 0;
}

Этот код отрабатывает и не выводит ошибкок с

-fhardened -fcf-protection=full

На мой взгляд выглядит небезопасно.

Почему бы не вставлять проверки на ассемблере при записи в память, на включаемость в регион стека? Если нужно записать что то в аргумент на стеке (int), то проверку можно не вставлять. При записи по указателю, уже обязательно вставлять. Если адрес стека то ошибка. В memset проверять пересечение двух диапазонов.

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

void read_file(const char *name)
{
        char buff[999];
        FILE *f = fopen(name, "rb");
        read_block(f, buff);
}

void read_block(FILE *f, char *buff)
{
        // тут компилятор должен вывести что len(buff) == 999
        fread(buff, 1, 9999, f);
}

Что бы все идеально работало, нужно будет:

  • Пометить libc функции
  • Если функция работает со стеком как у меня в верхнем примере, но это правильное поведение, пометить и ее
  • Перекомпилировать основные библиотеки, что бы не ломать ABI можно ввести экспорт двух прототипов, с доп.значениями для проверки диапазонов и без, дублирование прототипов понадобится для малого числа функций
★★★★★

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

Вполне допускаю что и под переписывание программного кода ИИ скоро кто-нибудь заточит.

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

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

Я могу поинтересоваться - как проверки на уровне сегментов помогут с >corruptions в пределах одного stack frame?

Сразу скажу что за давностью лет могу ошибаться - программистом я работал в 90е годы и тонкости мог уже забыть.

Но насколько я помню, обратиться к сегменту можно было только если правильно выставлен сегментный регистр на его начало. То есть просто так откуда попало записать в сегмент не получится. Да, это уберет НЕ ВСЕ ошибки записи,но попытки записи откуда угодно куда угодно по произвольно взятому указателю блокирует.

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

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

Основная проблема в том,что проверки границ сегментов способен поддерживать только классический x86. Процы с другой архитектурой,например ARM,такого не умеют.

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

У современных «ИИ» проблема они недетерминированные, вероятностные и как >следствие допускают как и человек ошибки, но самостоятельно их исправлять >не умеют

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

использовать их как ассистентов вполне можно и сейчас.

Вот именно,что уже можно. Думаю еще через десять лет ИИ поумнеют весьма значительно. И пусть даже в виде ассистентов смогут оказывать существенную реальную помощь в переписывании старого сишного кода на более безопасные языки (там где это нужно разумеется,в прикладном софте в первую очередь).

Так-то трансляторы с одного языка на другой существуют и без ИИ,но пока ограничены в возможностях и требуют значительного ручного допиливания кода. Примеры: https://c2ada.sourceforge.net/c2ada.html https://github.com/emareg/c2ada Допиливать приходится тем больше чем больше было разного рода «хакерских трюков» в исходном коде.

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

Вещание про это API идёт уже не один год. Никто правда кроме автора не понимает что это и зачем нужно, но упоминание есть практически в каждой теме, в которой Владимир отметился

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

Раз дцать детально объяснял и приводил примеры для чего разработано API и какой-от него профит.
Кто-то не понимает, а Владимир виноват ...

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

Какие намёки?
Многократно приводил примеры использования.

Ладно ещё раз.

API позволяет на основании метаданных объекта создать его в run-time и использовать.
То бишь компилятор об объекте ничего не знает, но тем не менее в программе можно с объектом работать.
К примеру имеются метаданные об объекте типа Excel.
Так вот хотя компилятору ничего не известно об объекте, но API позволяет с ним работать.
Это не выдумки, а реально протестировано.

Всё просто.
API позволяет в run-time получить из #include любой сложности и вложенности данные и работать с ними.

Так понятно?

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

Так понятно?

так непонятно. непонятно компилятор какого языка, что такое обьект - excel, и непонятно как работать с обьектом…о котором ничего не известно. как работать с черным ящиком? без мануала, непонятно.

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

так непонятно. непонятно компилятор какого языка,

C++.
Поддержан синтаксис C++ struct и расширенный, который позволяет добавить в struct данные о свойствах полей и объектов.
Например: алиасы поля, допустимы диапазон значений, ... короче любую семантику.

что такое обьект - excel

В исходниках Libreoffice в #include имеются сотни struct, которые используются API для открытия Excel, ...
Так вот метаданные содержат все struct и API на основании этих метаданных умеет в run-time создать объект Excel, загрузить в него данные и работать с объектом.

Как работать с черным ящиком

Обеспечена возможность создания обобщённых алгоритмов, которые умеют работать с объектами, созданными в run-time на основании метаданных.

без мануала, непонятно.

Нет смысла пока писать, так как разработка выполнена лишь процентов на пять от запланированного.
Ныне API расширяю возможностью работы с базами знаний.

Как тестирую API?

В основном на конфигурациях 1С.
Имеются метаданные, которые позволяют корректно загрузить и использовать любую конфигурацию 1С.
Это позволяет отладить часть API.

API не «прибито гвоздями» к 1С.
1С всего лишь один из подопытных.

API можно использовать для 2D, 3D, ...

Например в freetype и SDL уже добавил возможность использования этого API.

Хоть что-то понятно?

Многократно ведь в постах ранее детально объяснял о назначении API ...

И ещё.
В постах пишу лишь о том, в чём имею реальный опыт использования.

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 10)
Ответ на: комментарий от watchcat382

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

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

Так что можете просто взять компилятор gnat и пользоваться.

Как мне им перекомпилировать либжпег? Я хочу улучшить безопасность существующего кода.

В точности так сделана проверка границ массивов в ADA

Проверка границ есть и в gcc.

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

По поводу экселя вам уже ранее писали, что никакое самопальной апи там не нужно. Ну вот вообще. Так что пример вообще не объясняет ни принцип работы, ни необходимость апи

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

Всё разжевал, а вам опять не понятно.
Дело вовсе не в Excel.
Это был всего лишь пример, для объяснения назначения API.

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

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

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

Умение доходчиво объяснить - это знаете ли талант.

Может начнем с простого - что значит фраза «но тем не менее в программе можно с объектом работать»? Что именно вы с объектом хотите делать, вне зависимости от его типа и структуры. Мне вот в голову приходит только одна штука, которая умеет выполнять самые разнообразные действия с абсолютно разнородными объектами. Причем в том числе и применять к ним «различные обобщенные алгоритмы». Это файловая система.

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

Причем в том числе и применять к ним «различные обобщенные алгоритмы».

В многих постах говорил о том, что API в частности позволяет создавать обобщенные алгоритмы.

Например.
Каким образом API умеет работать с Excel?
А вот как.
Имеется обобщенный алгоритм, который умеет проанализировать метаданные xml файлов (например для Excel) и на их основании создать метаданные объекта.
Для Microsoft Office он как раз и использовался.
Указываем место в котором расположены сто Excel файлов.
Алгоритм их все анализирует и создаёт метаданные для работы с Excel.

Кстати необязательно вести разработку обобщенных алгоритмов.
Можно создать метаданные для любых объектов и в run-time с ними работать.

К примеру создаём объекты типа Документы, Справочники, ...
У нас имеются метаданные и некоторый файл в котором хранятся конкретные данные.
Так вот API позволяет на основании метаданных иметь доступ к реальным данным.

Ничего революционного не разработал.
dll, elf, ... для программ.
Разрабатываемое API - для динамического использования данных.

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

Мне вот в голову приходит только одна штука, которая умеет выполнять самые разнообразные действия с абсолютно разнородными объектами

Объект может быть: 2D, 3D, звук, конфигурация 1С, Excel, ...

Фух.
Так хоть понятно?

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

Для решения этой задачи требуется доработка: компиляторов, линкера и ядра >как минимум.

Ну вроде как в формате ELF есть возможность деления на «секции» и даже прописывания атрибутов к ним типа разрешение чтения-записи-исполнения. Положить массив в отдельную секцию(=сегмент в OS/2) насколько я понимаю можно. Так что компилятор и линкер может особо трогать и не придется. А вот ядро и загрузчик исполняемых файлов - да. Сейчас-то ядро грузит весь elf в один большой сегмент.

Надо бы погуглить - может кто-то уже что-нибудь делал в этом направлении…

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

Да забейте. Вы «в теме». Печально что объяснить ничего путем вы так и не смогли, может реально штука крутая и кому нибудь пригодилась бы. Ну и реальные примеры кода, которые у вас уже много кто просил в течении длительного времени, вы так и не привели. А для понимания лучше всего подходят либо формальное описание, либо примеры использования кода.

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

Разве сегмент стека исполняемый?

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

Ты видимо про сегменты 16 битные думаешь. 16-битные сегменты были на 286 (и я лично этот механизм использовал под достаточно редкой верский ParLap DOS Etender).

На 386 и далее в 32-битном режиме сегменты могут быть до 4Gb размером и смещение в сегменте 32-битное. Так что не вижу каких-либо сильно мешающих ограничений. Ну да, нельзя будет объявить массив более 4 гигов размером. Но это уж точно надо не часто. А кому надо - могут использовать 64-битные системы с «плоской» адресацией.

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

В чем годность идеи? В чем преимущество сегментов доса перед современными линуксовыми секциями elf?

По моему сегментная память это невыразимая мерзость.

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

Сейчас-то ядро грузит весь elf в один большой сегмент.

Секция и сегмент это одно и тоже? Если да, то ты ошибаешься.

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

https://www.opennet.ru/man.shtml?topic=mprotect&category=2&russian=0

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

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

Посты были о сути разработки.
Ещё раз - работа с динамическими объектами, созданными или уже ранее созданными на основе метаданных в run-time.
Объект: 2D, 3D, звук, html страница, ...

Неужели не понятно?

Forum0888
()
Последнее исправление: Forum0888 (всего исправлений: 4)
Ответ на: комментарий от MOPKOBKA

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

Сегменты никакого отношения к досу не имеют (кроме того что дос запускается при их наличии) - это регионы памяти с аппаратной (внутри процессора) проверкой границ.

«Секции elf» же действительно линуксовая штука, то есть чисто програмная - условное разделение файла на куски, на работу проца никак не влияющее.

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

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

Компилятор GNAT и нормальный и бесплатный. Есть по умолчанию во многих дистрибутивах линукса. Проверено - работает. У него платная поддержка,а не сам компилятор. Так что можно просто поставить gnat и писать на Ada. Единственная сложность с которой столкнется начинающий адский писатель - это небольшое количество готовых библиотек(в сравнении с Си). Но можно делать «переходники» для сишных библиотек и их подключать. Проверено - работает. Возможность подключения библиотек на других языках - заложена в стандарт.

Есть даже русский перевод стандарта Ады с комментариями и пояснениями. Книжка была выпущена издательством «Мир» и так и называлсь «Язык Ада». У меня есть аж в бумажном варианте,именно там в издательстве и купил тридцать лет назад. Да, там «непоследний» вариант стандарта,но Ада это не Си,там совместимость очень строго поддерживается,а до ограничений того стандарта добраться достаточно не просто. Очень уж в нем умно всё предусмотрено. Хотя конечно никто не мешает скачать и новейший стандарт,но уже на английском конечно.

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

на работу проца никак не влияющее

Меняет, mov [section_ro], rax делает уже другое.

Сегменты никакого отношения к досу не имеют

Связь между сегментами и досом очень сильная.

это регионы памяти с аппаратной (внутри процессора) проверкой границ

Прекрасно, что мне мешает переключить селектор сегмента или как он там назывался?

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

Но можно делать «переходники» для сишных библиотек и их подключать.

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

У него платная поддержка

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

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

Я хочу улучшить безопасность существующего кода.

В общем случае - только переписыванием. Но есть одна тонкость: делая «переходники» к сишной библиотеке можно использовать встроенную адскую (в прямом и переносом смысле!) проверку передаваемых в сишный код аргументов. Что резко снижает вероятность падения сишного кода от передачи в него чего-нибудь «не того». Тоже самое можно делать и для возвращаемых из библиотеки данных. Причем моя практика показывала что даже не очень-то надо дополнительный код проверок добавлять руками - во многих случаях хватает того что встроено в Аду. Да, для этого надо разобраться как это работает и тогда Ада становится реально удобным инструментом. Сначала после Си и тем более Ассемблера тяжеловато привыкать к адской дисциплине.

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

В чем годность идеи?

В «внутрипрограммной» защите памяти. Поместили массив в отдельный сегмент - и при попытке вылезти за его границу тут же получаете исключение,причем проверка границы - аппаратная. Аналогично,поместив функцию в отдельный сегмер - вы не сможете случайно передать управление куда-нибудь в её середину. Вызов возможен только через так называемый «шлюз»(см.документацию к 80386,она есть на русском).

В чем преимущество сегментов доса перед современными линуксовыми секциями >elf?

Во-первых не ДОСа,а OS/2 ну или хотябы дос-экстендера. То есть того,что работает в защищенном режиме процессора. Во-вторых нынешние секции elf хотя и существуют в самом файле,но толком не используются системой для защиты памяти. Засунутый в отдельную секцию массив также можно переполнить.

По моему сегментная память это невыразимая мерзость.

Это ощущение вызвано у вас только и исключительно слишком маленьким размером сегмента у процов младше 386. У 386 и старше сегмент может быть размером до 4 гигабайтов.

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

Ещё раз, секции тут ни при чём. Поставить права на страницу можно безо всяких секций, функция mprotect(). Да, elf-лоадер их тоже ставит но это детали реализации, а не что-то нативное. Если с чем и сравнивать сегменты то со страницами, и то и то обрабатывается нативно на проце.

Связь между сегментами и досом очень сильная.

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

Прекрасно, что мне мешает переключить селектор сегмента или как он там назывался?

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

Если от злонамеренного поведения - то на селекторах есть права доступа, впрочем этот аспект уже мало от страниц отличается. Но отличается: во-первых, у страниц уровней прав всего два, а у x86-сегментов четыре, во-вторых, у сегментов уже со времён 16-битных процов 1982 года был флаг исполняемости, а страницах же этот флаг ввели с большим шумом «новая технология защиты от вирусов NX-бит» только в начале 2000-х уже кажется в 64-битных процах.

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

И можно в run-time переназначить права на определенный участок памяти, >запретить писать в него, или исполнять из него код, или разрешить это все.

И как это может помочь в проверке выхода за границу массива? К тому же значение адреса у mprotect должно быть выравнено на границу страницы. И права назначаются на страницу,которая обычно фиксированного размера (например 4К). Максимум для чего это можно приспособить - это сделать стек неисполняемым,а область хранения констант - незаписываемой. Так что страничный механизм куда менее гибкий в использовании чем сегментный. Зато более быстрый,что и предопределило его использовании в системах, дизайн которых разрабатывался во времена 386 процессора (Линукс в частности,судя по мемуарам его автора).

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

«Секции elf» же действительно линуксовая штука, то есть чисто програмная - >условное разделение файла на куски, на работу проца никак не влияющее.

Теоретически можно было бы приспособить формат elf к сегментной модели памяти отобразив при загрузке секции на «аппаратные» сегменты. Вобщем-то примерно так и работал формат файлов NE.

заявлять подобную чушь.

Упоминаемых мной тонкостей вполне простительно не знать. Потому что в те времена когда сегментная модель поддерживалась (OS/2 и дос-экстендеры) работать с этим умели немногие. Да,я был одним из этих немногих. Но конечно за четверть века что-то и подзабыть мог.

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

ELF приспособить можно, но тогда опять будут NEAR/FAR указатели (причём второй - 48бит) и куча кода сломается. Т.е. это будет существенно другая платформа.

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