OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Вторник, 15 Октябрь, 2019 17:56

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 36 ]  На страницу 1, 2  След.
Автор Сообщение
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 08:16 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 10:37
Сообщения: 875
Откуда: Россия, Владивосток
Набрёл на новость:
Цитата:
Автор проекта 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.

Заявление про "даже если tun == NULL, и не является сам по себе уязвимостью" меня удивило (я с C++ не шибко знаком), полез проверять. Действительно:
Цитата:
Еще одна известная особенность языка C++ может усугубить проблемы, возникающие при вызове delete this. После удаления объекта можно продолжить с ним работать, вызывать те его функции, что не работают с данными и не подозревать о том, что он вообще удален.

Пример:
Код:
class CBase
{
  int m_i;
public:
  CBase() : m_i (0){}
  void printBase() { cout<<"CBase"<<endl; }
};

int main()
{
  CBase* b = NULL;
  b->printBase();
  return 0;
}

Экземпляр объекта CBase никогда даже и не создавался, но код будет шикарно работать годами до тех пор, пока вы не обратитесь к данным класса как-нибудь так:
Код:
void printBase() { m_i++; cout<<"CBase"<<endl; }


Понятно, что приведённый код изначально кривой. Но сочетание с оптимизатором получилось интересное :)


Последний раз редактировалось Иван Горячев Понедельник, 20 Июль, 2009 00:52, всего редактировалось 1 раз.

Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 08:38 
Аватара пользователя

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 8183
Откуда: Троицк, Москва
Вумные компиляторы были 30 лет назад, и сейчас они по-прежнему ... вумные.
Бред какой-то.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 09:04 

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

Предупреждать надо что выкидываешь.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 09:23 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
Иван Горячев писал(а):
Код:
struct sock *sk = tun->sk;

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


Бред какой-то. Этот код (обращение на чтение по нулевому адресу + небольшое смещение) вызовет исключение в любой современной популярной ОС. Не говоря уже о том, что с точки зрения языка этот код некорректен (undefined behavior), поэтому реакция компилятора по выкидыванию последующей проверки на NULL вполне адекватна. Эта проверка не имеет смысла, потому что если tun == NULL, то до этой проверки дело просто не дойдет.

Иван Горячев писал(а):
Таким образом, ничто не мешает злоумышленнику заставить ядро обращаться по нулевому адресу. Имеем классическую null pointer dereference vulnerability.


Ужас какой :) Последний раз я такую "vulnerability" видел в ДОСе - там как раз по нулевому адресу находился вектор перываний и если туда записать всякий мусор...

Иван Горячев писал(а):
Еще одна известная особенность языка C++ может усугубить проблемы, возникающие при вызове delete this.


Гхм. Это проблема всех языков с ручным управлением памятью... Причем здесь C++?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 10:54 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Vlad писал(а):
Иван Горячев писал(а):
Код:
struct sock *sk = tun->sk;

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

Бред какой-то. Этот код (обращение на чтение по нулевому адресу + небольшое смещение) вызовет исключение в любой современной популярной ОС.
Гхм, а там действительно идет обращение? Есть подозрение что компилятор и его откидывает. Во всяком случае стандарт по этому поводу не возражает.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 11:22 
Администратор

Зарегистрирован: Вторник, 15 Ноябрь, 2005 01:14
Сообщения: 4313
Откуда: Россия, Орёл
Vlad писал(а):
Бред какой-то. Этот код (обращение на чтение по нулевому адресу + небольшое смещение) вызовет исключение в любой современной популярной ОС.

Угу. Только код этот находится в ядре этой самой ОС и может благополучно довести последее до Kernel Panic.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 11:58 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
Борис Рюмшин писал(а):
Угу. Только код этот находится в ядре этой самой ОС и может благополучно довести последее до Kernel Panic.


А. Даже если и так. Undefined behaviour - никаких претензий к компилятору быть не может. Ошибка программирования и точка. Не нравится - используйте другой язык и другие компиляторы. Кстати, любители оберона могут поискать в знаменитом 16-страничном описании место, где описывается реакция на разименование нулевого указателя ;)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 12:07 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
GUEST писал(а):
Гхм, а там действительно идет обращение? Есть подозрение что компилятор и его откидывает. Во всяком случае стандарт по этому поводу не возражает.


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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 12:52 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Vlad писал(а):
Ну вообще да, эта самая строчка не обязывает обращаться к памяти. Надо более полный пример. В приведенном виде (обращение и последующая проверка) компилятор вообще может ничего не генерить :)
Кому-то может быть и не до шуток. Найденную уязвимость можно считать критической.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 13:26 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
GUEST писал(а):
Кому-то может быть и не до шуток. Найденную уязвимость можно считать критической.


Только компилятор здесь не причем :) Язык - причем. ОС с монолитным ядром и вкомпеленными в него драйверами - причем. Ну и криворукие программеры :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 14:53 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Vlad писал(а):
Только компилятор здесь не причем :) Язык - причем. ОС с монолитным ядром и вкомпеленными в него драйверами - причем. Ну и криворукие программеры :)
При том. Перечитайте тему ещё раз.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 21:49 

Зарегистрирован: Вторник, 25 Апрель, 2006 16:21
Сообщения: 2180
Откуда: Нижний Новгород
Гм. А с каких это пор ядро линукса написано на С++? К чему тут С++ вообще в заголовке темы? Для красного словца?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 19 Июль, 2009 22:06 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
GUEST писал(а):
При том. Перечитайте тему ещё раз.


Блин. Еще раз. Для кривого исходного кода компилятор может генерить кривой код. Это явно оговорено в спецификации языка. Это сделано для того, чтобы для нормального кода у компилятора было больше простора в оптимизации. Нормальный подход для языка с претензией на максимальную эффективность.
Вот еще пример:
Код:
int *p1 = NULL;
int &r = *p1;
int *p2 = &r;
assert(!p2);


Этот код будет работать на большинстве платформ/компиляторах. Тем не менее, это кривой код, и если на очередной платформе или версии компилятора он перестанет работать - винить можно только криворукого программера.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 20 Июль, 2009 00:52 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 10:37
Сообщения: 875
Откуда: Россия, Владивосток
Alexey Veselovsky писал(а):
Гм. А с каких это пор ядро линукса написано на С++? К чему тут С++ вообще в заголовке темы? Для красного словца?

Из второй цитаты. Могу поправить, если это принципиально, вопрос то не в языке


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 20 Июль, 2009 04:22 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Vlad писал(а):
GUEST писал(а):
При том. Перечитайте тему ещё раз.

Блин. Еще раз. Для кривого исходного кода компилятор может генерить кривой код.

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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 20 Июль, 2009 05:01 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
GUEST писал(а):
Было уже подчеркнуто, что он делает необоснованные предположения об инициализации. Или этого мало?


Компилятор может делать любые предположения и генерировать любой код в случае undefined behaviour. В данном случае логика опатимизатора вполне понятна - проверка на NULL не имеет смысла, потому что строкой выше указатель был разименован, что возможно только если указатель не NULL. В корректной программе. Некорректные программы компилятор не волнуют. Причем корректность/некорректноть определяется стандартом языка, а не особенностями линуксовог ядра, в котором чтение по нулевому адресу может быть сколько угодно "корректным".


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 20 Июль, 2009 05:11 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
GUEST писал(а):
Было уже подчеркнуто, что он делает необоснованные предположения об инициализации. Или этого мало?


Для интереса проверил сейчас на VC9:
Код:
struct X
{
int x;
};

bool f(X* p)
{
    p->x = 1;
    return p ? true : false;
}


Без оптимизации:
Код:
    cmp DWORD PTR _p$[ebp], 0
    setne   al


С оптимизацией:
Код:
    mov al, 1


Комментируем "p->x = 1;":
Код:
    cmp DWORD PTR _p$[esp-4], 0
    setne   al


Что и требовалось доказать.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 20 Июль, 2009 05:24 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Напрасно старались. Там другой компилятор и случай тоже другой.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 20 Июль, 2009 05:37 

Зарегистрирован: Суббота, 26 Ноябрь, 2005 18:38
Сообщения: 1857
GUEST писал(а):
Напрасно старались. Там другой компилятор и случай тоже другой.


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


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 21 Июль, 2009 07:45 

Зарегистрирован: Вторник, 29 Ноябрь, 2005 21:41
Сообщения: 1026
Vlad писал(а):
Тоже самое - сначала разименование, а потом вычисление нулевости.
Оператор -> - это не "разименование", а доступ через указатель. Для компилятора может быть не важно значение которое имеет этот указатель и действий над его значением не будет. Поэтому и другой.
Иван Горячев писал(а):
Набрёл на новость: ...полез проверять... Из второй цитаты.
Про такие случаи хорошо Булгаков сказал:" Не читайте перед обедом советских газет!". В смысле тем более советских.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 36 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2019, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB