LINUX.ORG.RU

Философия и архитектура NT против UNIX с точки зрения безопасности


0

0

Хорошая общая статья на тему безопасности NT и Unix достаточно исзвестного в определённых круга Криса Касперски. Главная прелесть статьи - её достаточная объективность и отсутствие фанатсвующих ноток.

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

★★★★

Проверено: ivlad
Ответ на: комментарий от sS

sS:
>по крайней мере в Linux имеет место это можно сделать через /proc/[pid]/mem
Угу, а через ptrace вообще много где :)

>существующие патчи для Linux прекрасно решают проблемы - связанные с ограничениями возможности исполнения кода в стеке
Ну да. IIRC, signal trampoline с 2.5 уже находится не на стеке.

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

Ну если вспоминать все способы то есть еще и LD_PRELOAD ;)

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

> Ну да. IIRC, signal trampoline с 2.5 уже находится не на стеке.
А по-подробнее можно? Они теперь без sigreturn() чтоли обходятся,
или просто trampoline в другое место кладут? А если используется
sigaltstack(), то куда trampoline теперь помещается?
Или я что-то не так понял?

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

Про запрет исполнения кода в стеке - это маловероятно. Потому как при использовании flat-модели (а её используют как Windows, так и Linux) все сегменты (и код, и стек) проецируются в одну и ту же область , поэтому любой байт стека принадлежит также и сегменту код и наоборот. Если и существуют какие-то патчи, перекрывающие наиболее частые метода взлома через bufer overflow, то это лишь пришлёпки. Нужно было изначально сегментную модель использовать, а не гнаться за простотой. В целом же статья на редкость неграмотная, как в отношении Linux (открытые пароли и пр. бред), так и в отношении Windows (взлом с помощью сообщений и пр.)

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

+

>Про запрет исполнения кода в стеке - это маловероятно. Потому как при
>использовании flat-модели (а её используют как Windows, так и Linux) все
>сегменты (и код, и стек) проецируются в одну и ту же область , поэтому
>любой байт стека принадлежит также и сегменту код и наоборот. Если и
>существуют какие-то патчи, перекрывающие наиболее частые метода взлома
>через bufer overflow, то это лишь пришлёпки. Нужно было изначально
>сегментную модель использовать, а не гнаться за простотой.

При таком раскладе просаживается производительность при работе с данными
в стеке (из за межсегментных обращений) - видимо когда проектировались эти системы, это был один из резонов такого решения.

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

flat vs segmentation

2 Eugene_Korobko:

> Про запрет исполнения кода в стеке - это маловероятно.

Не, это просто медицинский факт

http://pageexec.virtualave.net/

> Потому как при использовании flat-модели (а её используют как Windows, так и Linux)

s/Linux/vanilla Linux kernel/

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

>Нужно было изначально сегментную модель использовать, а не гнаться за простотой.
Про не-IA32 архитектуры что-нибудь слышали? Расскажите мне в каком месте Alpha живут енти самые сегменты (а на Alpha живут как NT4 так и Linux).

К тому же все равно как обращались к локальным переменным через DS: префикс - так же будут обращаться через SS и такие же overflow будут.

А вот сделать EXEC бит на страничках по-моему особой проблемы не было... но Intel как всегда были впереди планеты всей...

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

>А по-подробнее можно? Они теперь без sigreturn() чтоли обходятся
Нет, просто теперь код возврата из сигнала живет по адресу 0xFFFFE000 (kernel/user read-only, то бишь read-exec-only :)), это т.н. VSYSCALL страничка. Там же живут и точки входа в SYSENTER/SYSEXIT.

Раньше же было примерно так: когда ты входишь в сигнал ядро кладет на стек (либо на altstack) целиком фрейм и код, выполняющий sigreturn, и возврат указывает как раз на этот код. Теперь на стек кладется только фрейм, а код возврата перманентно живет в 0xFFFFE000 (на него указывает точка возврата в фрейме).


>А если используется sigaltstack(), то куда trampoline теперь помещается?
Все тоже самое, по-моему. На altstack кладется только фрейм, точка возврата - __kernel_sigreturn на VSYSCALL странице.

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

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

Если развести данные, код и стек по разным сегментам, то им можно установить разные флаги доступа. Код - только исполнение и чтение, данные и стек - только чтение и запись (не исполнение), и следить за этим будет процессор (аппаратно). Я почитал про Exec Shield. Эта утилита как раз и вводит элементы сегментации. Сегмент кода ограничивается по размеру, чтобы не накрывал стек. Т.е. это отход от flat-модели. Что, собственно, и требовалось доказать. Управление правами доступа на уровне страниц сделсть, конечно, можно было, но зачем? Управлять на уровне сегментов логичнее и естественнее, что и было реализовано. Нужно было просто в ОС поддержать. Про другие платформы: управление сегментами - это настольно низкоуровневая фича, что всё равно для каждой платформы пишется отдельно. Поэтому поддержка сегментации для платформы Intel не сильно бы отразилась на переносимости. Про быстродействие: сдаётся, что flat-модель не добавляет скорости, и вот почему. Процессор ничего не знает про flat. Процессор ВСЕГДА (а защищённом режиме) работает с сегментами. И даже при flat-модели существует три сегмента: код, данные и стек. для каждого из которых заведён дескриптор. А то, что базы этих сегментов совпадают,на скорости вычисления линейных адресов не отражается. Операции всё равно будут "межсегментными", даже если работают с одним и тем же блоком памяти. Впрочем, есть серьёзные сомнения относительно того, что на процессорах начиная с 386 "межсегментность" на что-то влияет.

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

Eugene_Korobko:

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

Управление - да, но если ввести сегменты, то для ядра не будет существовать понятие "адреса" в адресном пространстве (ну или по меньшей мере его нужно будет расширить до "сегмент:адрес", ведь тому же copy_to_user понадобится знать куда копировать - в сегмент кода, данных или стека процесса/нити или же вообще в "виртуализированный сегмент"), к тому же возникнет куча гемора с тем, что IA-32 хоть и имеет сегменты, но во многом предполагает плоскую модель, например breakpoints расставляются отладчиком в сегменте кода (еще можно привести примеры).

>Про быстродействие: сдаётся, что flat-модель не добавляет скорости, и вот почему. Процессор ничего не знает про flat. Процессор ВСЕГДА (а защищённом режиме) работает с сегментами. И даже при flat-модели существует три сегмента: код, данные и стек. для каждого из которых заведён дескриптор. А то, что базы этих сегментов совпадают,на скорости вычисления линейных адресов не отражается. Операции всё равно будут "межсегментными", даже если работают с одним и тем же блоком памяти.

Тут согласен, ведь все равно сегментные регистры на IA-32 кэшируют дескрипторы.

>Эта утилита как раз и вводит элементы сегментации. Сегмент кода ограничивается по размеру, чтобы не накрывал стек. Т.е. это отход от flat-модели. Что, собственно, и требовалось доказать.

На самом деле это не отход от flat модели, просто у сегмента кода уменьшается предел, при этом сама трансляция логических адресов в линейные остается той же x->x. То есть это - ни что иное как единственный способ борьбы с отсутствием exec битов на IA-32.

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

> Нужно было изначально сегментную модель использовать, а не
> гнаться за простотой.
Ну ещё чего. Использование защиты на уровне страниц гораздо
практичнее. То, что она у x86 практически отсутствует, ещё не
означает, что нормальные ОС должны из-за этого на сегментацию
переходить.

> так и в отношении Windows (взлом с помощью сообщений и пр.)
Взлом с помощью сообщений не он придумал. На эту тему совсем
недавно было написано не мало статей и даже в Микрософт признали
угрозу и вроде бы поставили даже какие-то костылики.

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

> А если используется sigaltstack(), то куда trampoline теперь помещается?
> Все тоже самое, по-моему. На altstack кладется только фрейм,
> точка возврата - __kernel_sigreturn на VSYSCALL странице.
А, то есть теперь trampoline вообще не создаётся, а просто
лежит по фиксированному адресу, куда и производится возврат?
Вроде разумно.
Интересно почему раньше так сделать не могли, это же вроде как
проще гораздо...

> А вот сделать EXEC бит на страничках по-моему особой проблемы
> не было... но Intel как всегда были впереди планеты всей...
А я думаю, проблемы как раз были и очень серьёзные:)
Вот например почему сделали для страниц бит U вместо некоего
аналога DPL из двух бит - это сделало практически бесполезным
использование двух колец защиты из четырёх, и теперь актуально
использовать только Ring-0 и Ring-3, что и делают все современные
ОС. А казалось бы, зачем надо было 1 бит экономить?
Ну и вообще там ещё много приколов было, так что проблемы у Интел
явно были довольно серьёзные на этот период. Они явно куда-то
сильно спешили... :)
Вообще это наверное большой гемор писать операционку для х86...
Вот интересно мне, а как они при таком раскладе ухитрились
mprotect() отхакать? Ведь по идее он не должен тут нормально
работать:)

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

anonymous:
>Интересно почему раньше так сделать не могли, это же вроде как
проще гораздо...

Хороший вопрос... в принципе можно порыться в kernel-mailing list... может там есть какие-нибудь умные мысли по этому поводу.

>Вот интересно мне, а как они при таком раскладе ухитрились
mprotect() отхакать? Ведь по идее он не должен тут нормально
работать:)

А он разве работает? :) Или ты о всяких патчах к ядру? Тот, про который я читал в свое время, просто расширит предел для сегмента кода, если ты PROT_EXEC на страницу поставишь. Там был такой смысл: ld-linux и ядро "стараются" размещать в младших адресах адресного пр-ва исполняемый код, но если ты делаешь mprotect на старшие адреса, то ты сам себе злобный буратино.

Может сейчас что-нибудь умное придумали, хотя вряд ли эту схему можно сильно усовершенствовать.

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

Про проблемы переносимости при переходе к сегментной модели спорить не буду - я плохо знаю другие архитектуры. Что же касается запрета на исполнение кода в стеке - модель flat, насколько я её понимаю, предполагает ПОЛНОЕ совмещение сегментов, а не только баз. Так что ограничение длины сегмента - это всё-таки уход от плоской модели. Про защиту на уровне страниц - не убедили. Вообще, есть три уровня адросации - виртуальные адреса (те, с которыми работает приложение), линейные (после примнения десегментации) и физические (после примнения страничного механизма к линейному адресу). Разделение на типы памяти (стек, код, данные) нужно делать на уровне виртуальных адресов, т.к. именно здесь адреса разделяются по назначению. Линейные адреса аморфны, в них уже нет информации о том, в каком качестве используется память. У механизма страничного разбиения другая функция.

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

> mprotect() отхакать? Ведь по идее он не должен тут нормально
> работать:)
> А он разве работает? :)
Вроде да, хотя конечно все возможные комбинации я не проверял.

> Или ты о всяких патчах к ядру?
Да обычный mprotect() (man 2 mprotect)
Написано, что есть PROT_NONE, PROT_READ, PROT_WRITE и PROT_EXEC.
Ну с PROT_NONE и PROT_WRITE ещё понятно, а вот как они реализовали
PROT_READ и PROT_EXEC, мне лично не совсем ясно...

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

RE:

>Вроде да, хотя конечно все возможные комбинации я не проверял.
Ну я только что перепроверил на 2.4 vanilla и RH, вроде не работает, как и раньше...

>allocated a chunk of length 5 @0x40150000
>Running stupidity with PROT_EXEC @ 0x40150000...
>Checking if we can read the area ...
>U
>Running stupidity with PROT_READ @ 0x40150000...
>Running stupidity with PROT_READ|PROT_EXEC @ 0x40150000 ...
>Running stupidity with PROT_NONE @ 0x40150000 ...
>Received SIGSEGV, reason SEGV_ACCERR @ 0x40150000
>failed!

Выполняю примерно такой код (с разными флажками):
> st = (stupidity_t)area;
> if (setjmp (env) == 0) {
> if (mprotect (area, stupidity_len, PROT_READ) == -1) {
> fprintf (stderr, ".failed to set protection to READ\n");
> }
> printf ("Running stupidity with PROT_READ @ %p...\n", st);
> st ();
> }
> else printf ("failed!\n");

Murr ★★
()
Ответ на: RE: от Murr

RE:

2.4.20 имелся в виду (vanilla и из RH 9.0)

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

> Вообще, есть три уровня адросации - виртуальные адреса (те, с которыми
> работает приложение), линейные (после примнения десегментации) и
> физические (после примнения страничного механизма к линейному адресу).
> Разделение на типы памяти (стек, код, данные) нужно делать на уровне виртуальных
> адресов, т.к. именно здесь адреса разделяются по назначению. Линейные адреса
> аморфны, в них уже нет информации о том, в каком качестве используется память.
Эта информация всё равно есть у ОС. Вместо того чтобы разделять
линейное пространство на неперекрывающиеся сегменты, можно (было бы
при наличии соотв. аппаратной возможности) просто пометить области,
предназначенные для стека и для данных, как неисполняемые, и получить
практически тот же результат, только не отходя от flat модели.

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

Тут ключевое слово - "не отходя от flat-модели". В условиях, когда УЖЕ РЕАЛИЗОВАНА flat-модель, сделать защиту на уровне страниц проще, чем вводить сегментацию. А если рассматривать вопрос о том, как нужно бы делать изначально, то на уровне сегментов было бы логичнее.

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

2 Eugene_Korobko >Про проблемы переносимости при переходе к сегментной модели спорить >не буду - я плохо знаю другие архитектуры. Что же касается запрета на >исполнение кода в стеке - модель flat, насколько я её понимаю, >предполагает ПОЛНОЕ совмещение сегментов, а не только баз

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

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

> Тут ключевое слово - "не отходя от flat-модели". В условиях,
> когда УЖЕ РЕАЛИЗОВАНА flat-модель, сделать защиту на уровне
> страниц проще, чем вводить сегментацию.
Так идея (моя по крайней мере) то как раз в том, что работать с
flat моделью реально проще. По этому если есть возможность её
эффективно использовать, то почему бы и нет?

> А если рассматривать вопрос о том, как нужно бы делать
> изначально, то на уровне сегментов было бы логичнее.
Поскольку в х86 защита на уровне страниц весьма ущербна, в данном
случае возразить нечего. Однако если бы всё нормально было, то
сегментация была бы, имхо, не сильно нужна. Я понимаю конечно,
что все мы к ней ещё со времён ДОСа привыкли, но всё же этот
механизм сильно усложняет работу введением дополнительных конструкций.
Гораздо удобнее работать с непрерывным пространством адресов,
а не сегмент:смещение, хотя бы уже по тому, что данные и код
располагаются в одном физическом адресном пространстве.
Для сравнения: есть такая архитектура mcs51 (однокристалка).
Вот там данные и код (а так же регистры) имеют физически разные
адресные пр-ва. Там я бы согласился с целесообразностью сегментной
модели, однако там всё сделано по-другому (для доступа к разным
адресным пр-вам используются различные команды процессора просто).
А здесь сегментация просто как дополнительный наворот выглядит,
ну и, естественно, компенсирует недостатки страничной защиты иногда.

anonymous:
> В 32-битных архитектурах использовать сегментную
> модель вместо flat это полное безумие, до которого только
> "начитанные ламера" могут додуматся.
Ламера или пользователи х86? Нет нормальной защиты на уровне страниц
здесь, по этому эти подходы иногда приходится комбинировать.

> А с защитой стека никаких проблемм в модели flat нет можно
> для каждой страницы поставить отдельно режим доступа.
На какой архитектуре?

> Можно для всех страниц памяти которые принадлежат стеку
> поставить запрет на выполнение, если ОС
> этого не делает значит есть уже много разного кода который
> требует исполнения в стеке.
Да нельзя этого на х86 сделать! Хочется, а нельзя. По тому как нет
битика соответствующего. Если бы было можно, всего этого спора
не было бы вообще и mprotect() бы работал:)

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

Этот автор подельник широко известного клоуна Арви хЭкера и этим о нем все сказано :)

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

Мда, интересно:

> количество дыр, обнаруженных в NT за все время ее
> существования, можно свободно пересчитать по пальцам
> одной руки (причем, большая часть из них была обнаружена
> практически случайно). В UNIX же, напротив, дыры
> обнаруживаются постоянно.

> ...К тому же медленное, эволюционное (а не революционное
> как у NT) развитие UNIX отнюдь не способствует появлению
> грубых, легко обнаруживаемых ошибок, которыми так славится NT.

Это только мне кажется, что тут маа-ааленькое противоречие?

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

Для anonymous (*) (21.10.2003 9:27:39)

Если в этой фразе нет противоречия, то это означает, что у автора статьи не пять пальцев на руке...

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

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

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

В AMD64 добавили такой бит в page table - NX (NoExecute). А API Windows NT изначально поддерживал эту возможность, но не x86 архитектура. Microsoft-овцев специально об этом спросили, и они ответили, что Windows поддерживает этот бит на всех платформах, где его поддерживает аппаратура.

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

>Если развести данные, код и стек по разным сегментам, то им можно установить разные флаги доступа. Код - только исполнение и чтение, данные и стек - только чтение и запись (не исполнение), и следить за этим будет процессор (аппаратно).

Так и делают - но на уровне страниц. А за ненулевую базу сегмента процессоры x86 давно получают такой пенальти, что мало не покажется. И только повсеместное использование flat модели делает это малозаметным. AMD64 вообще требует нулевую базу в native 64-битном режиме - точнее не требует, а игнорирует при расчете :)

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

>Линейные адреса аморфны, в них уже нет информации о том, в каком качестве используется память

Вот только именно по ним лежат байты - а каждый байт изначально принадлежал коду или данным - противоречие :) ?

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.