LINUX.ORG.RU

Интересная уязвимость в ядре Linux

 , ,


0

0

Автор проекта grsecurity, Brad Spengler, опубликовал эксплойт, использующий очень интересную уязвимость в ядре Linux (драйвер net/tun).

Специфика этой уязвимости состоит в том, что уязвимость отсутствует в исходном коде, но присутствует в бинарном. Как такое возможно? Давайте рассмотрим это на примере. Все начинается с того, что происходит инициализация указателя sk:

struct sock *sk = tun->sk;
Этот код не вызывает ошибок даже если tun == NULL, и не является сам по себе уязвимостью.

Несколькими строками ниже происходит проверка инициализации указателя tun:

if (!tun)
        return POLLERR;
Казалось бы, теперь все правильно. Злодей не пройдет.

Но! При сборке кода компилятор полагает, что указатель tun уже корректно инициализирован и, оптимизируя код, выкидывает проверку факта инициализации (приведенный выше оператор if). Таким образом, ничто не мешает злоумышленнику заставить ядро обращаться по нулевому адресу. Имеем классическую null pointer dereference vulnerability.

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

Представленный сплойт протестирован на ядрах версий 2.6.30 с SELinux и без, а также на 2.6.18 (RHEL5, собирать с опцией -DRHEL5_SUCKS). Для успешной работы данного сплойта необходимо наличие на машине PulseAudio и подгруженного модуля tun.

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

Кстати, эту уязвимость уже активно обсуждает у нас в толксах.

>>> Эксплойт

★★★★

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

То есть что, поскольку в нулевом кольце мы не получим SIGBUS первая конструкция загружает в sk какой-то мусор, а вторая вырезается, т.к tun разыменован и по мнению компилятор он заведомо != NULL?

Absurd ★★★
()

> Специфика этой уязвимости состоит в том, что уязвимость отсутствует в исходном коде

Ну всеже автор кривит душой. tun->sk есть разименование указателя.

ierton ★★
()

Автор эксплойта дебил. Как и подпевалы. Он нашел уязвимость tun-драйвера, которой можно воспользоваться через pulseaudio

annoynimous ★★★★★
()

уфф, не страшно, т.к. на серваках Pulseaudio никогда не будет (убунто^Wгусары молчать!)

dreamer ★★★★★
()

>ля успешной работы данного сплойта необходимо наличие на машине PulseAudio и подгруженного модуля tun.

Ага. И прокричать в микрофон "Kernel Panic" голосом Балмера.

Pavval ★★★★★
()

дааа.... выражение соснуть tunца приобретает новый, неожиданный смысл...

shty ★★★★★
()

Епт, товарищи!!!! У кого все-таки оно работает???

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

согласен, внятно и без смеси французского с нижегородским

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

> То есть что, поскольку в нулевом кольце мы не получим SIGBUS первая конструкция загружает в sk какой-то мусор, а вторая вырезается, т.к tun разыменован и по мнению компилятор он заведомо != NULL?

мм, в Ring0 MMU вызовет исключение CPU при обращении к незамапленному региону адресного пространства

rudchenkos
()

>> -DRHEL5_SUCKS

Т.к. /me не параноик, то из всей новости доставляет только этот флаг :)

Andru ★★★★
()

Наверное специально для ядра надо в gcc встроить опцию -OneVyiobyvaysya

А сабжевый код крив - надо бы поправить.

Pavval ★★★★★
()

код - гавно, ампутировать руки автору

rudchenkos
()

пульсоснули тунца, как говорится.

sid350 ★★★★★
()

> struct sock *sk = tun->sk;
> Этот код не вызывает ошибок даже если tun == NULL, и не является сам по себе уязвимостью.


А кто-нибудь может объяснить, почему разыменование нулевого указателя больше не является ошибкой?

pv4 ★★
()

1) -fno-delete-null-pointer-checks (это если внимательно прочитать http://www.grsecurity.net/%7Espender/exploit.txt )

2)
> struct sock *sk = tun->sk;

> Этот код не вызывает ошибок даже если tun == NULL, и не является сам по

> себе уязвимостью.


Этот код вызывал ошибку, почему, собственно, и был пофиксен: http://lkml.org/lkml/2009/7/6/19 (это, опять же, если внимательно читать).

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

>Сейчас набегут оруны „c/c++ - *$&#@!”

*$&#@! - это кривые руки. Обычно у подобных кодеров они растут из задницы, потому руки *$&#@!.

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

>Сейчас набегут оруны „c/c++ - *$&#@!”

Еще про микроядро можно поорать, типа надо засунуть все драйвера в юзерспейс.

Absurd ★★★
()

что делать без pulseaudio? жажду проверить :)

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

>Еще про микроядро можно поорать, типа надо засунуть все драйвера в юзерспейс.

+много

imp ★★
()

Мандрива вот только что выпустила уже патчи: на все пульсы и на утилиты пульс аудио и билиотеки. Какие дистрибутивы тоже выпустили патчи?

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

> Как я понимаю, в ring0 не происходит нарушения защиты.

Еще как происходит. Откуда иначе брать Kernel Panic? :)

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

>> Как я понимаю, в ring0 не происходит нарушения защиты.

>Еще как происходит. Откуда иначе брать Kernel Panic? :)


Да, признаю. Только за нарушением защиты иногда следует только oops.
А panic брать из любого места вызовом соотв. функции.

Pavval ★★★★★
()

B Ubuntu патч на pulseaudio уже есть, часа 2 назад

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

> А panic брать из любого места вызовом соотв. функции.

Oops тоже - конструкцией *(0) :) Но в приницпе да, Panic может быть вызван и другими причинами - на то в конце смайлик и стоит.

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

Не зарекайся. Ты что, не слышал про яву-на-чипе?

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

Не, в данном случае проблема ядра (код некорректный). А умность gcc уже давно создает проблемы ядру.

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

В данном случае проблему ядру создал не в меру умный программист. Ну вот кто ему мешал написать так, как показал sergeil (см. комментарии выше)?

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

>>собирать с опцией -DRHEL5_SUCKS
>Мне одному кажется, что это толстый троллинг?


Автор сплойта просто пошутил, а я оценил его шутку.

З.Ы. На рабочих серваках используем центос, в.т.ч 5, в качестве dom0. Имхо, неплохая система. Конкретно с RHEL уже давно не работал, но ничего против него не имею.

nnz ★★★★
() автор топика

Люопытно: в ISO/IEC 9899 TC2 говорится об udefined behavoiur при применении к invalid value (в частности, к null pointer) оператора "*" (сноска в разделе 6.5.3.2), но ничего подобного не сказано про применение к invalid value оператора "->" (раздел 6.5.2.3). Или я что-то проглядел, или в стандарте бага (очевидно, что в реальной жизни применение -> к невалидным указателям ни к чему хорошему приводить не должно). И пока стандарт таков, с формальной точки зрения gcc не может в своих оптимизациях полагаться на валидность указателя после первой же "->". Это баг gcc.

Мораль: любовь к низкоуровневым трюкам ни чем хорошим не заканчивается.

Manhunt ★★★★★
()

Автор эксплойта - рак!

строка 797:
fprintf(stdout, "           ,        ,\n");
fprintf(stdout, "          /(_,    ,_)\\\n");
fprintf(stdout, "          \\ _/    \\_ /\n");
fprintf(stdout, "          //        \\\\\n");
fprintf(stdout, "          \\\\ (@)(@) //\n");
fprintf(stdout, "           \\'=\"==\"='/\n");
fprintf(stdout, "       ,===/        \\===,\n");
fprintf(stdout, "      \",===\\        /===,\"\n");
fprintf(stdout, "      \" ,==='------'===, \"\n");
fprintf(stdout, "       \"                \"\n");

matich
()

на генту тоже выпустили обновление.

RedPossum ★★★★★
()

struct sock
{
};

struct tun
{  
   struct sock *sk;
};

int z;

int func(struct tun *tun)
{  
   struct sock *sk = tun->sk;

   if (!tun)
     return 2;

   z = 5;

   return 1;
}

/* С каким опциями надо собирать, чтобы увидеть описанную оптимизацию?
 */

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

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

советую поразмыслить на досуге над подобным кодом: &(((type*)0)->value)

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

Это само собой. И для оператора * аналогичный случай подробно разбирается, всё в той же сноске.

Manhunt ★★★★★
()

#include <stdio.h>

struct sock
{
};

struct vuln
{
  struct sock *a;
};

int main(int argc, char *argv[])
{
  struct vuln *a = 0;
  struct sock *z = a->a;

  return 0;
}

$gcc test.c -Wall -o test
$./test
Ошибка сегментирования

правда это из userspace

madepa
()

Пульсы у мну нет - бояться нечего.

Насчёт tun не уверен - но вроде бы тоже такого нету.

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