Deadlock при вызове NtGetContextThread

Тема в разделе "WASM.NT.KERNEL", создана пользователем sergegers, 20 мар 2011.

  1. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    Возникла проблема. В драйвере вызываю NtGetContextThread и происходит блокировка. Это выглядит так:
    В dispatch функции я создаю системный поток и останавливаюсь

    Код (Text):
    1.                            
    2.  
    3. ::LARGE_INTEGER Timeout;
    4. Timeout.QuadPart = -10000 * 100 * 10000;
    5. status = ::KeWaitForSingleObject(
    6.                    SettingThread,
    7.                    ::Executive,
    8.                    ::UserMode,                          
    9.                    TRUE,
    10.                    &Timeout
    11. );
    12.  
    13. DbgPrint("%s\n", OsrNTStatusToString(status));
    В потоке я вызываю NtGetContextThread, она вызывает PsGetContextThread, а та отправляет APC основному потоку и тоже останавливается на KeWaitForSingleObject - deadlock.

    Почему так происходит? Ведь я поставил wait функцию в основном потоке с параметрами WaitMode = UserMode и Alertable = TRUE. То есть APC должна приходить.
     
  2. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    APC слать надо через ZwQueueApcThread.
     
  3. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    вы невнимательно прочитали вопрос. я сам не шлю APC. Я вызываю NtGetContextThread, она соответственно PsGetContextThread, а та KeInitializeApc, KeInsertQueueApc, KeWaitForSingleObject.
    это код, который работал в user mode. по некоторым причинам мне пришлось перенести его в kernel mode. где я допустил промах?
     
  4. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Ты пытаешься вызвать NtGetContextThread() для того потока, в контексте которого вызвана dispatch-функция, я правильно понимаю? Т.е. в dispatch-функции ты получаешь хендл потока-инициатора запроса, создаёшь ядерный поток, передавая ему хендл целевого потока, и ждёшь его завершения. В ядерном потоке вызываешь NtGetContextThread() для потока-инициатора IRP-запроса и убиваешься. Всё верно?
     
  5. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Поэтому и не работает, PsGetContextThread шлет ядерную apc, которая никакого отношения к alertable не имеет.

    Непонятно как это вобще работало.
     
  6. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    совершенно верно
     
  7. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    работало, но соответственно в user mode я создавал user mode поток, вызывал там GetThreadContext, а в основном потоке ждал на WaitForSingleObject
     
  8. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    А, ну тогда я действительно неверно понял. Вобщем при previous mode == UserMode при обработке ядерной апк ( той самой которая была послана из PsGetContextThread ) и если normal routine нулевая, то проверяется может ли быть доставлена юзермодному алертабле потоку, видимо поэтому и работало. При переносе в ядро prev mode изменился и соот-но работать перестало.
     
  9. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Вобщем, я советую выкинуть эту возню с APC и ждать на эвенте например.
     
  10. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    но мне нужен CONTEXT, я же не просто так жду

    может, вместо NtGetContextThread вызвать сразу PsGetContextThread с параметром UserMode?
     
  11. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Можно попробовать ( только поток зареференсить не забыть, а то он умереть может ненароком ).
    А вобще желательно целиком задачу описать, помоему все это както криво выглядит, а посоветовать как сделать нормально немогу, т.к. незнаю условий задачи.
     
  12. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    надо получать и менять контекст потока приложения (т.е. вызывать GetThreadContext и SetThreadContext), причём надо обрабатывать случай пропатченной IAT. для меня наиболее удобно было бы сделать это в драйвере, но раз прямое перенесение кода в kernel мод вызывает столько сложностей, то, видимо, я перепишу эти GetThreadContext и SetThreadContext через sysenter
     
  13. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Во-первых, зачем вообще нужен отдельный ядерный поток, чтобы получить контекст текущего потока, - не понятно. Как насчёт вызвать NtGetContextThread() прямо в dispatch-функции, передав ей NtCurrentThread() в качестве хендла потока? Во-вторых, PsGetContextThread() шлёт ядерную APC, а ядерные APC никак не влияют на поведение функции KeWaitForSingleObject(), независимо от параметров. Т.е. если ты хотел таким образом добиться выхода из KeWaitForSingleObject(), то это была изначально нерабочая идея. В документации об этом сказано, кстати. И, в-третьих, если функция PsGetContextThread() повисла на ожидании, следовательно, её APC не была доставлена. В твоём случае, похоже, это связано с тем, что Previous Mode потока, который запросил информацию о контексте, == KernelMode.
     
  14. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    Хороший вопрос.
    Это пришло из описания функции SetThreadContext

    То есть, я останавливаю поток и работаю с контекстом. Если запрашивается контекст текущего потока, то создаётся отдельный, основной останавливается, и оттуда запрашиватся контекст. Так было в user mode. В kernel mode я временно снял остановку потока, а сейчас думаю, что для текущего потока можно, наверное, не выполнять это условие. сам поток не сможет изменить контекст, а если его будет менять какой-то другой поток, то саспенд не поможет.

    ну разумеется, APC не была доставлена.


    выскажите пожалуйста ваши соображения, по поводу бессаспендного запроса контекста текущего потока
     
  15. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Т.е. задача свелась к suspend thread, get/set context, resume thread, для этого не нужны никакие системные потоки и apc, нужно просто вызвать эти апи.
    Что касается получения контекста без суспенда - получить его ( именно его, а не измененный другими контекст ) можно лишь в трап фрейме(и судя по всему это вобще здесь не нужно).
     
  16. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    вы видимо не прочли про пропатченный IAT

    это расшифруйте пожалуйста. мне нужен консистентный контекст - то есть, чтобы не случилось так, что я начал считывать или устанавливать контекст, произошло переключение потоков и контекст изменился
     
  17. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    sergegers

    А как IAT относится к контексту потока?

    Suspend Thread, потом установка контекста. После суспенда он в списке ожидания планировщика находится, ни о каком переключении речи тут идти не может.
     
  18. sergegers

    sergegers New Member

    Публикаций:
    0
    Регистрация:
    8 июн 2008
    Сообщения:
    172
    вы предложили вызывать GetThreadContext & SetThreadContext, а они пропатчены. почему я и перелез в ядро

    так я и спрашиваю, можно ли сделать для текущего потока KeGetContextThread/KeSetContextThread без саспенда. видимо, тогда удастся обойтись без отдельного кернелмодного потока для запроса контекста, и тогда PreviousMode потока будет UserMode (хотя это тоже надо прояснить). по предположению x64 это позволит избежать зависания в PsGetContextThread
     
  19. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Нельзя, да и сама подобная задача довольно бессмысленна.
     
  20. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Ну, устанавливать контекст без остановки потока нельзя, это однозначно. А про получение см. ниже.

    Избежать-то, конечно, поможет, но какой в этом смысл для тебя? Контекст же уже не будет актуален к моменту возврата из PsGetContextThread(). Или тебе консистентность важнее, чем актуальность?