Выполнить код в PASSIVE_LEVEL.
От: Аноним  
Дата: 26.01.07 06:40
Оценка:
День добрый!

Описываю ситуацию.

Есть в Win-де такая штука как filter-hook driver,
которая может занимаеться фильтрацией IP-пакетов.
В драйвере регистрируется так называемая filter-hook callback function,
которая выглядит примерно так:

убедительная просьба использовать таги ccode & asm для соотв. кусков кода — модератор

PF_FORWARD_ACTION
hook_proc(
        unsigned char *PacketHeader,
        unsigned char *Packet,
        unsigned int PacketLength,
        unsigned int RecvInterfaceIndex,
        unsigned int SendInterfaceIndex,
        ULONG RecvLinkNextHop,
        ULONG SendLinkNextHop)
{
PF_FORWARD_ACTION action;
KIRQL=c_irql;

c_irql=KeGetCurrentIrql();
KdPrint(("текущий IRQL %d\n",c_irql));

//smthcode
...
//end smthcode

action=PF_DROP;
//action=PF_FORWARD;

return action;
}

В промежутке 
//begin smthcode
...
//end smthcode


вызываеются слдеующая группа функций
ZwDeviceIoControlFile
ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
ZwCreateFile
ZwDeviceIoControlFile
ZwWriteFile
ZwReadFile
ZwClose

которые работаю на уровне IRQL 0 (PASSIVE_LEVEL),
а KeGetCurrentIrql показывает что уровень IRQL есть 2 (DISPATCH_LEVEL)
и естественно получаю синий экран с IRQL_NOT_LESS_OR_EQUAL.

Как быть, как заставить выполится этому участку кода?
Дело в том, что значение action, то что должна вернуть filter-hook callback function,
зависит как раз от того, как обработаются данные из пакета в этом уастке кода.
На сколько я понимаю понизить IRQL в 0 перед //begin smthcode
а потом обратно повысить в 2 после //end smthcode нельзя? Как же поступить?
Re: Выполнить код в PASSIVE_LEVEL.
От: onyx2 Украина  
Дата: 26.01.07 06:57
Оценка:
вообще то, желательно так не делать.
А вы можете объяснить какие данные вы пытаетесь вытянуть из пакета?

ZwQueryInformationToken

По видимому пытаетесь получить SID usera процесса в контекcте которого передается/принимается пакет; так вот я скажу, что ничего не получится для incoming packets там случайный контекст; хотя для outgoing packets там вроде верный контекст, кто передает, того и контекст.


ZwDeviceIoControlFile

Это вообще непонятно зачем


ZwCreateFile
ZwWriteFile
ZwReadFile
ZwClose

Работу с этими функциями надо организовать в отдельном потоке, я так понимаю это для логирования.
www.cubik.biz
Re[2]: Выполнить код в PASSIVE_LEVEL.
От: Аноним  
Дата: 26.01.07 07:20
Оценка:
Здравствуйте, onyx2, Вы писали:

O>вообще то, желательно так не делать.

O>А вы можете объяснить какие данные вы пытаетесь вытянуть из пакета?

Из пакета получаем, то что есть в нем, номер протокола, адреса, порты и т. п.

ZwDeviceIoControlFile
ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
ZwCreateFile
ZwDeviceIoControlFile
ZwWriteFile
ZwReadFile
ZwClose

Эти функции нужны для определения других вещей на основе данных полученых из пакета.
Логирование тоже присутсвует .

Так что, предлагаете весь этот участок кода перекинуть в другой поток?
Может и пример подкините, как в потоке с IRQL=2 получать данные из потока с IRQL=0?
Re[3]: Выполнить код в PASSIVE_LEVEL.
От: onyx2 Украина  
Дата: 26.01.07 08:33
Оценка:
А>Эти функции нужны для определения других вещей на основе данных полученых из пакета.

В общем, мне неизвестно что там вам надо получить, поэтому ничего советовать не буду.

А>Логирование тоже присутсвует :).


Вот по поводу логирования. Это дело надо однозначно перенести в отдельный поток.
1. Где нибудь в DriverEntry...
//Создаем поток
PsCreateSystemThread(&hLogThread, THREAD_ALL_ACCESS, NULL, NULL, NULL, (PKSTART_ROUTINE)LogThreadFunction, NULL);
//Также инициализируем очередь (стандартная работа с LIST_ENTRY очередями)
//элементами очереди будут структуры типа LOG_RECORD (см. ниже)
InitializeListHead(&LogListHead);
// SpinLock для очереди
KeInitializeSpinLock(&LogListLock);


2. В сетевом фильтре:
PF_FORWARD_ACTION
hook_proc(
  unsigned char *PacketHeader,
  unsigned char *Packet,
  unsigned int PacketLength,
  unsigned int RecvInterfaceIndex,
  unsigned int SendInterfaceIndex, 
  ULONG RecvLinkNextHop,
  ULONG SendLinkNextHop
)
{
  PF_FORWARD_ACTION action;
  
  //...
  // здесь добавляем элемент в очередь со всей необходимой информацией для логирования
  //...
  
  return action;
}


3. В LogThreadFunction (Ф-ция LogThreadFunction будет выполняться на IRQL = PASSIVE_LEVEL, так что проблем с повышенным IRQL не будет)

Вот, например, самая простая реализация
VOID LogpThreadProcedure( IN PVOID StartContext )
{        
    PLOG_RECORD          pLogRecord    = NULL;

    ///////////////////////////////////////////////////////////////////////////////
    //log thread cycle
    while(!bLogFlushDiskShutdown) {        
        
        //шаримся по списку, пока есть в нем элементы и сбрасываем инфу на диск
        while ( (pLogRecord = LogGetFirstRecordList()) ) 
        {
                        
            //сбрасываем инфу на диск
                LogFlushToDisk(...);
                //удаляем элемент из очереди
            LogRemoveRecordList(pLogRecord);
        }
        
            //здесь говорим потоку спать 5c
            SleepLogThread();
    }
    ///////////////////////////////////////////////////////////////////////////////


// - вот тут я не уверен нужна ли здесь эта ф-ция, в примерах MSDN она используется, 
//но у меня и без нее все нормально работает
//т.е. вопрос к знатокам: "При выходе из потока нужно ли вызыватьPsTerminateSystemThread?"
//по логике - не нужно, но там кто его знает...
    PsTerminateSystemThread( STATUS_SUCCESS ); 
}

}



структура LOG_RECORD буде иметь вид:
typedef struct _LOG_RECORD {
    
    LIST_ENTRY        Entry;
    LARGE_INTEGER    LogTimeStamp;

    //здесь любая инфа на ваш вкус: ip-адреса, порты и т.п.

}LOG_RECORD, *PLOG_RECORD;


Ф-ции по работе с очередью (LogRemoveRecordList, LogGetFirstRecordList) и другие ф-ции (LogFlushToDisk, SleepLogThread) напишите сами.
Ну что ж, let's go!
www.cubik.biz
Re[4]: Выполнить код в PASSIVE_LEVEL.
От: DimanKGKZ  
Дата: 27.01.07 04:01
Оценка:
Здравствуйте, onyx2, Вы писали:



А>>Эти функции нужны для определения других вещей на основе данных полученых из пакета.


O>В общем, мне неизвестно что там вам надо получить, поэтому ничего советовать не буду.


ZwCreateFile
ZwDeviceIoControlFile
Эти функции используются для получения структур MIB_TCP_RAW и MIB_UDP_RAW от TCPIP драйвера
посылая ему IOCTL_TCP_QUERY_INFORMATION_EX.

ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
Эти функции используются для получения имени файла запущеного процеса по заданому PID и
SID юзера запустившего его.

Итого, надо получать эту инфу на каждый прием/посылка IP пакета и спать 5 секунд нельзя .
Еслиб не этот случай, что callback функция работает на IRQL=2 ... наверное все былоб хорошо .

Конечно такая схема работы на первый взгляд не есть хороший вариант. Но иметь на любой момент времени
табличку запущенных процессов в системе, чтобы на каждый IP пакет получать инфу по заданному PID процесса
пока не представляется возможным... Работать ведь надо этой filter-hook callback function быстро...
Re[5]: Выполнить код в PASSIVE_LEVEL.
От: Аноним  
Дата: 27.01.07 09:49
Оценка:
DKG>Конечно такая схема работы на первый взгляд не есть хороший вариант. Но иметь на любой момент времени
DKG>табличку запущенных процессов в системе, чтобы на каждый IP пакет получать инфу по заданному PID процесса
DKG>пока не представляется возможным... Работать ведь надо этой filter-hook callback function быстро...
Наивно думаете что все это будет работать быстрее одной несчастной мапы?
Re[6]: Выполнить код в PASSIVE_LEVEL.
От: DimanKGKZ  
Дата: 27.01.07 10:05
Оценка:
Здравствуйте, Аноним, Вы писали:

DKG>>Конечно такая схема работы на первый взгляд не есть хороший вариант. Но иметь на любой момент времени

DKG>>табличку запущенных процессов в системе, чтобы на каждый IP пакет получать инфу по заданному PID процесса
DKG>>пока не представляется возможным... Работать ведь надо этой filter-hook callback function быстро...
А>Наивно думаете что все это будет работать быстрее одной несчастной мапы?

Пока не представляю как все это должно работать.
По подробней можете сказать, что вы имеете в виду?
Re[5]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 27.01.07 20:23
Оценка:
Здравствуйте, DimanKGKZ, Вы писали:

DKG>ZwCreateFile

DKG>ZwDeviceIoControlFile
DKG>Эти функции используются для получения структур MIB_TCP_RAW и MIB_UDP_RAW от TCPIP драйвера
DKG>посылая ему IOCTL_TCP_QUERY_INFORMATION_EX.

Это можно заменить на посылку IRP соответствующему устройству. Работать будет на DISPATCH_LEVEL

DKG>ZwOpenProcess

DKG>ZwQueryInformationProcess
DKG>ZwOpenProcessToken
DKG>ZwQueryInformationToken
DKG>Эти функции используются для получения имени файла запущеного процеса по заданому PID и
DKG>SID юзера запустившего его.

По поводу PID-SID Вам ответили в соседней ветке. Держать список процессов IMHO оптимальный вариант.
Да пребудет с тобою сила
Re[6]: Выполнить код в PASSIVE_LEVEL.
От: DimanKGKZ  
Дата: 28.01.07 07:54
Оценка:
Здравствуйте, TarasCo, Вы писали:


TC>По поводу PID-SID Вам ответили в соседней ветке. Держать список процессов IMHO оптимальный вариант.


Схемку такой работы не нарисуете? Что есть мапа ?
В своем же драйвере организовать перехват создания/унмичтожения процессов с помощью PsSetCreateProcessNotifyRoutine() ?
А как будут общаться filter-hook callback function и функция перхвата создания/процессов? Если есть такой способ через ту самую мапу,
почемубы тогда не отлавливать создание/уничтожение процессов, а выполнить в этом месте

ZwOpenProcess
ZwQueryInformationProcess
ZwOpenProcessToken
ZwQueryInformationToken
а за одно и
ZwCreateFile
ZwDeviceIoControlFile

Дело в том что кроме списка процессов необходимо еще и знать какие TCP, UDP порты они занял.
А если процесс закрыл порт и через полчаса открыл другой? Есть способ отловить?

Как же поток на irgl=2 синхронизировать с потоком на irql=0?
Re[6]: Выполнить код в PASSIVE_LEVEL.
От: DimanKGKZ  
Дата: 30.01.07 15:45
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>Здравствуйте, DimanKGKZ, Вы писали:


DKG>>ZwCreateFile

DKG>>ZwDeviceIoControlFile
DKG>>Эти функции используются для получения структур MIB_TCP_RAW и MIB_UDP_RAW от TCPIP драйвера
DKG>>посылая ему IOCTL_TCP_QUERY_INFORMATION_EX.

TC>Это можно заменить на посылку IRP соответствующему устройству. Работать будет на DISPATCH_LEVEL


Если из одного драйвера послать IRP на DISPATCH_LEVEL другому драйверу, то функция обработки IRP пакетов
во втором драйвере тоже будет работать на DISPATCH_LEVEL ?
Re[7]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 31.01.07 07:12
Оценка:
Здравствуйте, DimanKGKZ, Вы писали:

DKG>во втором драйвере тоже будет работать на DISPATCH_LEVEL ?


Ну естественно. При вызове IoCallDriver IRP прямиком попадет в диспетчерский обработчик. Если до вызова IoCallDriver IRQL = DISPATCH_LEVEL, то понизиться он никак не может.
Да пребудет с тобою сила
Re[7]: Выполнить код в PASSIVE_LEVEL.
От: onyx2 Украина  
Дата: 31.01.07 10:28
Оценка:
Здравствуйте, DimanKGKZ, Вы писали:

DKG>В своем же драйвере организовать перехват создания/унмичтожения процессов с помощью PsSetCreateProcessNotifyRoutine() ?

можно

DKG>А как будут общаться filter-hook callback function и функция перхвата создания/процессов?

Вот тут-то и засада.
Вы из filter-hook callback function не можете привязаться к конкретному процессу, чтобы определить кто послал/принял пакет, потому как для incoming packets там случайный контекст; хотя для outgoing packets там вроде верный контекст, кто передает, того и контекст. — я это уже говорил.
В общем нет общего идентификатора, по которому можно связать очередь процессов и процессов, которые осуществляют передау данных по сети...
Хотя стоп! подождите... В принципе, для TCP и UDP можно по адресам и портам.
1. По хорошему, нужен TDI filter.
2. Но по плохому подойдет и посылка IRP (IOCTL_TCP_QUERY_INFORMATION_EX) к \Device\Tcp (TarasCo говорил). Получите таблицу tcp соединений. Осуществите поиск в таблице на предмет наличия требуемого адреса и порта (т.е. тот адрес и порт, котрые пришли в пакете) в таблице tcp. Если найдете, то pid тоже известен из табл. tcp. Ну а если pid, известен, то это дело легко можно связать со списком процессов который вы создаете с помощью PsSetCreateProcessNotifyRoutine.

DKG>А если процесс закрыл порт и через полчаса открыл другой? Есть способ отловить?


TDI — для w2k, wxp, w2k3; WFP — Vista. Но в Vista какой-то бок, там по этому callback'у FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4 можно отлавливать момент создания адресного объекта/соединения, но как отлавливать момент его закрытия неизвестно.
www.cubik.biz
Re[8]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 31.01.07 11:50
Оценка:
Здравствуйте, onyx2, Вы писали:

O>TDI — для w2k, wxp, w2k3; WFP — Vista. Но в Vista какой-то бок, там по этому callback'у FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4 можно отлавливать момент создания адресного объекта/соединения, но как отлавливать момент его закрытия неизвестно.


Я думаю, на уровне фильтрации ресурсов это невозможно, но можно на уровне фильтрации потоков данных. Тогда в classifyFn можно задать контекст через вызов FwpsFlowAssociateContext0, который будет потом передан в flowDeleteFn — так наверное можно отследить завершение например устанвленного соединения.
Да пребудет с тобою сила
Re[9]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 31.01.07 11:54
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>Я думаю, на уровне фильтрации ресурсов это невозможно, но можно на уровне фильтрации потоков данных. Тогда в classifyFn можно задать контекст через вызов FwpsFlowAssociateContext0, который будет потом передан в flowDeleteFn — так наверное можно отследить завершение например устанвленного соединения.


FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4
FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6

Я сам не пробовал
Да пребудет с тобою сила
Re[10]: Выполнить код в PASSIVE_LEVEL.
От: onyx2 Украина  
Дата: 31.01.07 12:40
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4

TC>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6

TC>Я сам не пробовал :)


А я пробовал. Данные callback'и отхватывают момент установки соединения (ну это понятно, даже название соответствующее).
А вот disconnect'а как такового нет. Его можно определить в callback'е FWPM_LAYER_STREAM_V4/FWPM_LAYER_STREAM_V6 по приходящим в него флагам. Что-то типа этого:
void CoutTcpClassifyStream(
    IN const FWPS_INCOMING_VALUES0* inFixedValues,
    IN const FWPS_INCOMING_METADATA_VALUES0* inMetaValues,
    IN OUT void* layerData,
    IN const FWPS_FILTER0* filter,
    IN UINT64 flowContext,
    OUT FWPS_CLASSIFY_OUT0* classifyOut
    )
{
    FWPS_STREAM_CALLOUT_IO_PACKET0* streamPacket = (FWPS_STREAM_CALLOUT_IO_PACKET0*)layerData;

    do {
        if (!streamPacket || !streamPacket->streamData) { break; }

            if ( (streamPacket->streamData->flags & FWPS_STREAM_FLAG_SEND_DISCONNECT) || 
               (streamPacket->streamData->flags & FWPS_STREAM_FLAG_SEND_ABORT) ) {
            //disconnect on send
        }

        if ( (streamPacket->streamData->flags & FWPS_STREAM_FLAG_RECEIVE_DISCONNECT) || 
               (streamPacket->streamData->flags & FWPS_STREAM_FLAG_RECEIVE_ABORT) ) {            
            //disconnect on receive
        }        
        
    } while(0);

    if (classifyOut) {
        classifyOut->actionType = FWP_ACTION_CONTINUE;
        classifyOut->flags = 0;
    }
}



TC>Я думаю, на уровне фильтрации ресурсов это невозможно, но можно на уровне фильтрации потоков данных. Тогда в classifyFn можно задать контекст через вызов FwpsFlowAssociateContext0, который будет потом передан в flowDeleteFn — так наверное можно отследить завершение например устанвленного соединения.


Я много callback'ов протестировал и единственный callback для которого flowdeleteFn имеет значение это FWPM_LAYER_STREAM. В принципе и там можно ловить disconnect. Т.е. получается когда в stream'е происходит disconnect, то затем автоматически вызывается flowDeleteFn для stream'а.

Connect/Disconnect удалось как-то отловить.
А вот Open/Close addr. object не удалось (то что было в TDI — IRP_MJ_CREATE/IRP_MJ_CLOSE). И никаких идей нет.

В общем, не нравится мне ихний WFP.
www.cubik.biz
Re[11]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 31.01.07 13:10
Оценка:
Здравствуйте, onyx2, Вы писали:

TC>>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4

TC>>FWPS_LAYER_ALE_FLOW_ESTABLISHED_V6

TC>>Я сам не пробовал


O>А я пробовал. Данные callback'и отхватывают момент установки соединения (ну это понятно, даже название соответствующее).

O>А вот disconnect'а как такового нет.

Я имел в виду другое. В этом месте вызвать FwpsFlowAssociateContext0. А момент окончания потока отслеживать из flowDeleteFn.
Да пребудет с тобою сила
Re[8]: Выполнить код в PASSIVE_LEVEL.
От: DimanKGKZ  
Дата: 31.01.07 14:58
Оценка:
А возможен ли такой вариант?
Работа на
1. двухпроцессорной машине
или
2. гипертрэдинг

Кол-бэк функция застывает на своем DISPATCH_LEVEL и ждет ответа от другого потока
пока второй процессор будет выполнять его на PASSIVE_LEVEL?

Интеренсно, как это вобще реализовать?
Re[9]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 31.01.07 16:44
Оценка:
Здравствуйте, DimanKGKZ, Вы писали:

DKG>Интеренсно, как это вобще реализовать?


Реализовать то это не сложно, но это полный пипец производительности. Даже не так, вот так — ПОЛНЫЙ ПИПЕЦ.
Да пребудет с тобою сила
Re[10]: Выполнить код в PASSIVE_LEVEL.
От: DimanKGKZ  
Дата: 01.02.07 03:47
Оценка:
Здравствуйте, TarasCo, Вы писали:

TC>Здравствуйте, DimanKGKZ, Вы писали:


DKG>>Интеренсно, как это вобще реализовать?


TC>Реализовать то это не сложно, но это полный пипец производительности. Даже не так, вот так — ПОЛНЫЙ ПИПЕЦ.


Подскажите пожалуйста, как реализовать можно. Думаю пипец большой не будет, ну хотябы потому,
что задержка будет не большая... я так думаю , судя по dbgviewr-у. Даже если и будет тормозить,
так ему и надо. Это будет у компа основная обязанность.
Re[11]: Выполнить код в PASSIVE_LEVEL.
От: TarasCo  
Дата: 01.02.07 08:49
Оценка:
Здравствуйте, DimanKGKZ, Вы писали:

DKG>Подскажите пожалуйста, как реализовать можно. Думаю пипец большой не будет, ну хотябы потому,

DKG>что задержка будет не большая... я так думаю , судя по dbgviewr-у. Даже если и будет тормозить,
DKG>так ему и надо. Это будет у компа основная обязанность.

Можете попробывать так:
1. В обработчике который потенциально может находиться на DISPATCH_LEVEL, но должен ждать код на PASSIVE_LEVEL запретить прерывания:
__asm cli
2. Крутиться в цикле, проверяя некий флаг
3. Флаг проверять с помощью InterlockedCompareExchange
4. После установки флага разрешить прерывания и продолжить выполнение.

В потоке, который будет делать вспомогательные действия после их выполнения установить флаг с помощью любой Interlocked функции.

Только врядли это все будет хорошо работать, IMHO возможен вариант дедлока и пока Вы это все отладите — Вы поседеете, а XP никто использовать уже не будет. Может Вам сразу — под Vista, там все что Вам нужно уже предусмотрено разработчиками.
Да пребудет с тобою сила
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.