Not a kernel guy

… in the Windows kernel team

Wednesday, January 30, 2008

Пикник на обочине или не ходите, дети, в DllMain гулять, а то ноги оторвёт.

Точка входа в DLL, так же как и точка входа в программу, - это очень специальное место. Зона. В Зоне действуют свои правила касательно того, что можно делать, а что делать нельзя. В Зоне можно инициализировать локальные данные DLL, можно создавать критические секции. В Зоне нельзя динамически загружать другие Модули или создавать потоки. Любой Сталкер знает и следует правилам Зоны. Все остальные рано или поздно нарушают правила и расплачиваются за это.

Что делает Зону особенной? Иные утверждают, что во всем виноват Загрузчик. Загрузчик единственный, кто понимает язык зависимостей между модулями. Он говорит с модулями, загружает их и вызывает из точки входа. Но Загрузчик слаб. Он не в силах совладать с Модулями, нарушающими правила Зоны.

Модули коварны и злы. Они стремятся окружить себя другими Модулями, от которых они зависят. Они любят создавать циклические зависимости между собой. Они загружают другие DLL в ответ на DLL_PROCESS_ATTACH и вызывают функции из непроинициализированных Модулей. Модули пытаются замаскировать и приумножить свое коварство. Они прикрываются статусом “Delay-Loaded DLL” и расставляют ловушки в конструкторах и деструкторах статических объектов.

Это люди сделали их такими. Люди нарушили правила Зоны. И теперь они расплачиваются за это каждый раз, когда идут в Зону.

На прошлой неделе произошел очередной несчастный случай. Access Violation прошил насквозь lodctr.exe:

А всё из-за того, что loadperf решил, что ему всё можно и попытался зарегистрировать источник событий для Event Log прямо из DllMain. Этот фокус ему удавался до поры до времени, пока advapi32 не стала “Delay-Loaded” . Как только это произошло, вызов RegisterEventSourceW стал приводить к её загрузке, что поломало граф зависимостей Загрузчика и вылилось в попытку использования неинициализированной критической секции в rpcrt4 до того, как была вызвана точка входа rpcrt4!DllMain.

Кто будет следующей жертвой?

P.S. Сслылка по теме: http://msdn2.microsoft.com/en-us/library/ms682583.aspx

Posted at 9:01 pm •

RSS feed | Trackback URI

14 Comments »

[...] from blog.not-a-kernel-guy.com. Filed under: Программирование, Юмор, [...]

 
Comment by Alexey — January 30, 2008 @ 11:43 pm

Здравсвуйте, Алексей.
А у MS есть какие-нибудь анализаторы (как с уязвимостями) которые бы отслеживали подобные моменты?
>пока advapi32 не стала “Delay-Loaded”
а почему она такой стала?

Comment by Not a kernel guy — January 31, 2008 @ 9:46 am

А у MS есть какие-нибудь анализаторы (как с уязвимостями) которые бы отслеживали подобные моменты?

Есть, но от них мало пользы. Чтобы от них был толк, нужно сначала разорвать все явные кольцевые зависимости (статически связанные DLL), а затем вручную найти все случаи когда из DllMain явно или опосредованно вызывается LoadLibrary. Только после этого такой инструмент будет полезен, так как с его помощью можно будет отлавливать “нарушителей”.

Потытки разорвать все кольцевые зависимости делаются уже давно. Вернее это не попытки даже, а не слабого размера проекты. Но с наскока это не решается - слишком много кода затрагивается. Ситуация постоянно улучшается, но до идеала еще топать и топать.

а почему она такой стала?

Эксперименты с черной магией.

 
 
Comment by yenox — February 2, 2008 @ 11:58 am

Душещипательно.

Вообще все эти игрища с бубном вокруг Disable/EnableThreadLibraryCalls и проч. в свое время много крови попортили. и seh_translator, который если не путаю ничего иначе чем в DLL_PROCESS_ATTACH не работает.

Не люблю Winapi - слишком много trade-off в нем видимо наделали, теперь все это наружу торчит….

Comment by Not a kernel guy — February 2, 2008 @ 6:17 pm

_set_se_translator это совсем другой коленкор. Совать его в DLL не очень разумно. Как по мне так им вообще лучше не пользоваться.

Comment by yenox — February 4, 2008 @ 9:54 am

а как жить без него? __finally{} и try… finally{} вместе не живут, вроде бы

Comment by Not a kernel guy — February 4, 2008 @ 8:43 pm

Живут, просто в разных функциях. _set_se_translator просто устанавливает фильтр, который будет вызван из самого верхнего (считаем, что стек растет вниз) __try/__except. Никто не мешает обернуть свой поток в __try/__except и воспользоватться там аналогичным фильтром.

Причина по которой не стоит использовать _set_se_translator в DLL - это то, что он устанавливает глобальный фильтр для всех потоков, а DLL , по определению, всему потоками не владеет.

Comment by Not a kernel guy — February 4, 2008 @ 10:25 pm

Причина по которой не стоит использовать _set_se_translator в DLL - это то, что он устанавливает глобальный фильтр для всех потоков, а DLL , по определению, всему потоками не владеет.

Вернее даже не так. DLL владеет только частью стека потока, т.е. начиная с того момента, как была вызвана функция этой DLL. А _set_se_translator влияет на весь поток.

Comment by yenox — February 5, 2008 @ 2:51 am

Я так понимаю, что веселье начинается, когда выгружаешь dll, а в потоке где-то затем произойдет SEHовское исключение?

Comment by Not a kernel guy — February 5, 2008 @ 8:35 am

Ага. Еще могут быть всякие нехорошие эффекты, когда код главного модуля рассчитывает поймать SEH исключение, а тут мы на белом коне ему подсовываем C++ исключение.

 
 
 
 
 
 
 
Comment by .net lover — February 3, 2008 @ 2:38 pm

Оффтопик.

А вы на какой позиции в MS? Senior или Junior?

Это к тому, что довольно периодично проскакивают сообщения о наборах программистов в Фирму (src — blogs.gotdotnet.ru ). Но после вашего блога, начинаешь сомневаться в проф. пригодности :)

И какой у вас опыт вообще? CV где-то можно посмотреть? :)

Comment by Not a kernel guy — February 3, 2008 @ 3:29 pm

Не приходите к нам, пожалуйста. У нас всё плохо.

P.S. (c) privet.com

 
 
Comment by Shrike — February 4, 2008 @ 1:42 pm

Описанное как-то касается .net кода?

Comment by Not a kernel guy — February 4, 2008 @ 8:37 pm

Напрямую - нет, так как .NET все эти тонкости от программиста скрывает.

 
 

Your Comment (smaller | larger)

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress