<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>Marcus' Blog</title>
    <link>http://www.heege.net/blog/</link>
    <description>Random thoughts about C++/CLI, .NET/Native interop and other topics</description>
    <copyright>Marcus Heege</copyright>
    <lastBuildDate>Fri, 09 Oct 2009 16:53:23 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.7.5016.2</generator>
    <managingEditor>marcus@heege.net</managingEditor>
    <webMaster>marcus@heege.net</webMaster>
    <item>
      <trackback:ping>http://www.heege.net/blog/Trackback,guid,62340fe1-8ab5-443a-b49e-2b37bbf15c24.aspx</trackback:ping>
      <pingback:server>http://www.heege.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.heege.net/blog/PermaLink,guid,62340fe1-8ab5-443a-b49e-2b37bbf15c24.aspx</pingback:target>
      <title>Dangers of /clr and /clr:pure in sandboxed execution scenarios: Thread-promotion can bypass the sandbox!</title>
      <guid>http://www.heege.net/blog/PermaLink,guid,62340fe1-8ab5-443a-b49e-2b37bbf15c24.aspx</guid>
      <link>http://www.heege.net/blog/PermaLink,guid,62340fe1-8ab5-443a-b49e-2b37bbf15c24.aspx</link>
      <pubDate>Fri, 09 Oct 2009 16:53:23 GMT</pubDate>
      <description>    &lt;p&gt;
   &lt;span&gt;One of the benefits of managed code is sandboxed execution: To avoid that malicious
   code is executed by plug-ins, an application does not need to use a separate language
   with restricted features. Plug-ins can be written in any .NET language, because the
   host can execute them in a sandbox with restricted permissions. Implementing a library
   that can be called by sandboxed code requires the infamous AllowPartiallyTrustedCallers
   attribute. With this attribute, you explicitly state that you are confident that your
   library does not have security vulnerabilities. If your library has to interoperate
   with native code, you should surely know about a pitfall that can easily allow a user
   of your library to bypass the sandbox. This potential vulnerability can be caused
   by a CLR interop feature called &lt;i&gt;thread promotion&lt;/i&gt;. In this post, I will explain
   this pitfall and how to avoid it in your libraries. However, before you can understand
   the impacts of thread promotion for CAS, I have to explain a little bit more about
   sandboxing first.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;To execute code in a sandbox, the CLR offers an API called the &lt;/span&gt; &lt;a href="http://msdn.microsoft.com/en-us/library/ms130766.aspx"&gt; &lt;span&gt;simple
   sandboxing API&lt;/span&gt;&lt;/a&gt;&lt;span&gt;. This API creates a new AppDomain in which only assemblies
   form the GAC and a set of explicitly specified assemblies are executed with full-trust
   permissions. All other assemblies are executed with permissions specified in a permission-set
   that is passed to this API.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;Obviously, the permission-set that is granted to plug-ins should not contain
   several permissions. These include the skip-verification permission which allows you
   to execute code that is not proven to be type-safe and the permission to execute unmanaged
   code. Both permissions could be used to bypass the sandbox. The more permissions an
   app grants to a sandbox, the more features can be used by the plug-in. In my opinion,
   most sandboxes should only have the permission to execute code. All other features
   it needs should be provided by custom libraries that the host application implements.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;Many libraries that are called by plug-ins have to call native code. If the
   native code called by such a library uses threads that have not executed managed code
   so far (native-only threads) or if you use technologies that can automatically switch
   to other threads (like COM), you have to consider &lt;i&gt;thread promotion&lt;/i&gt;. Thread
   promotion is done when a native-only thread invokes a native-&amp;gt;mananaged thunk.
   Normally, native-&amp;gt;managed thunks simply stay in the AppDomain that the managed
   thread is executing. (Due to the &lt;i&gt;.retainappdomain&lt;/i&gt; flag of the &lt;i&gt;.vtfixup&lt;/i&gt; metadata
   in the assembly manifest.) However, when a native-&amp;gt;managed thunk promotes a native-only
   thread to a managed thread, it has to pick an AppDomain. Because in this case the
   CLR does not have any information about which AppDomain is supposed to execute the
   managed function, the thread starts its managed life in the default AppDomain (the
   first AppDomain, which is created automatically when the CLR starts). Typically the
   default AppDomain executes all assemblies with full-trust. Therefore, the managed
   code executes with full-trust permissions now. If the libraries code calls back into
   the plug-in e. g. via a delegate, an event or via a virtual function call, the plug-in
   is now executing with full-trust permissions and not in its sandbox any more.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;The following code demonstrates this unintended switch to the default AppDomain.
   Notice that in main, a new AppDomain called child is created and that the method Program::ExecuteInChildDomain
   is called in this new AppDomain. ExecuteInChildDomain calls a native function fNative
   and passes a pointer to a native callback method named fNativeCallback. Now fNative
   creates a new native thread which invokes a managed function. When created, the new
   thread is a native-only thread. When the thunk is invoked to call the managed function,
   the native-only thread is promoted to a managed thread that executes in the default
   domain, not in the child domain that created the thread.&lt;/span&gt;
&lt;/p&gt;
&lt;p style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;"&gt;
   &lt;span style="color:green;"&gt;// DangersOfNativThreadsInSandboxedAppDomains.cpp : main
   project file.&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:green;"&gt;// cl /clr DangersOfNativThreadsInSandboxedAppDomains.cpp&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:green;"&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;#include&lt;/span&gt;&lt;span &gt; &lt;span style="color:#A31515"&gt;&amp;lt;windows.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:#A31515;"&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;typedef&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; (&lt;span style="color:blue"&gt;__stdcall&lt;/span&gt;*PFN_NATIVECALLBACK)();&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;_stdcall&lt;/span&gt; fNative(PFN_NATIVECALLBACK
   pfnCallback);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;_stdcall&lt;/span&gt; fNativeCallback();&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;DWORD WINAPI ThreadMain(LPVOID pfnCallback);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;using&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;namespace&lt;/span&gt; System;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;ref&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;class&lt;/span&gt; Program&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;internal&lt;/span&gt;&lt;span &gt;:&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;static&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; DumpAppDomainInfo(String^
   method)&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;AppDomain^ current = AppDomain::CurrentDomain;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Console::WriteLine(&lt;span style="mso-tab-count:1"&gt; &lt;/span&gt; &lt;span style="color:#A31515"&gt;&amp;quot;Method:
   {0}, AppDomain: {1}&amp;quot;&lt;/span&gt;,&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;method,&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;current-&amp;gt;IsDefaultAppDomain()
   ? &lt;span style="color:#A31515"&gt;&amp;quot;(default AppDomain)&amp;quot;&lt;/span&gt; &lt;/span&gt; 
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;:
   current-&amp;gt;FriendlyName);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;static&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; Main()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Program::DumpAppDomainInfo(&lt;span style="color:#A31515"&gt;&amp;quot;Program::Main&amp;quot;&lt;/span&gt;);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;AppDomain^ child = AppDomain::CreateDomain(&lt;span style="color:#A31515"&gt;&amp;quot;childDomain&amp;quot;&lt;/span&gt;);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;child-&amp;gt;DoCallBack(&lt;span style="color:blue"&gt;gcnew&lt;/span&gt; CrossAppDomainDelegate(&amp;amp;ExecuteInChildDomain));&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;static&lt;/span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; ExecuteInChildDomain()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Program::DumpAppDomainInfo(&lt;span style="color:#A31515"&gt;&amp;quot;Program::ExecuteInChildDomain&amp;quot;&lt;/span&gt;);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;fNative(&amp;amp;fNativeCallback);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;};&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span &gt; main()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;Program::Main();&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;__stdcall&lt;/span&gt; ManagedFunctionCalledByNativeCallback()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;Program::DumpAppDomainInfo(&lt;span style="color:#A31515"&gt;&amp;quot;::ManagedFunctionCalledByNativeCallback&amp;quot;&lt;/span&gt;);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;#pragma&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;unmanaged&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;DWORD WINAPI ThreadMain(LPVOID pfnCallback);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;_stdcall&lt;/span&gt; fNative(PFN_NATIVECALLBACK
   pfnCallback)&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; &lt;span style="color:green"&gt;// this new thread starts as
   a native-only thread and gets promoted&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; &lt;span style="color:green"&gt;// when the new thread calls
   a managed function for the first time&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;HANDLE hThread = ::CreateThread(NULL, 0, &amp;amp;ThreadMain,
   pfnCallback, 0, 0);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;::WaitForSingleObject(hThread, 1000);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;::CloseHandle(hThread);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;DWORD WINAPI ThreadMain(LPVOID pfnCallback)&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; ((PFN_NATIVECALLBACK)pfnCallback)();&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;return&lt;/span&gt; 0;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span &gt; &lt;span style="color:blue"&gt;_stdcall&lt;/span&gt; fNativeCallback()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; ManagedFunctionCalledByNativeCallback();&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;Now that we know about the problem, it is time to think about a solution: How
   can a native library that calls managed functions from native code ensure that its
   managed functions end up in the right application domain? There are two fundamentally
   different approaches that I would like to mention here: one that is based on an explicit
   switch of the application domain, and another one that is based on a switch that the
   CLR can do implicitly. &lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;Explicitly switching application domains can be done either via AppDomain::DoCallback
   or with helper functions defined in a Visual C++ header file called &amp;lt;msclr/appdomain.h&amp;gt;.
   This header defines several overloads of a function called call_in_appdomain, each
   of these functions take the identifier of the application id you want to call and
   a function pointer. Various overloads exist for the different calling conventions
   and for different numbers of arguments. To use this, you could modify your implementation
   of fNative as follows: &lt;/span&gt; 
&lt;/p&gt;
&lt;p style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;"&gt;
   &lt;span &gt;DWORD WINAPI ThreadMain(LPVOID pvCallbackInfo);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;struct&lt;/span&gt;&lt;span&gt; CallbackInfo&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;PFN_NATIVECALLBACK pfnCallback;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;int&lt;/span&gt; appDomainId;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;};&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;void&lt;/span&gt;&lt;span&gt; &lt;span style="color:blue"&gt;_stdcall&lt;/span&gt; fNative(PFN_NATIVECALLBACK
   pfnNativeCallback)&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;DWORD appDomainId;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;HRESULT hr = msclr::_detail::get_clr_runtime_host()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;-&amp;gt;GetCurrentAppDomainId(&amp;amp;appDomainId);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;hr; &lt;span style="color:green"&gt;// error handling ignored
   for simplicity here&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:green;"&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;CallbackInfo callbackInfo = { pfnNativeCallback, appDomainId
   };&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; &lt;span style="color:green"&gt;// this newly create thread
   starts as a native-only thread and gets &lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; &lt;span style="color:green"&gt;// promoted when the new thread
   calls a managed function for the first time&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;HANDLE hThread = ::CreateThread(NULL, 0, &amp;amp;ThreadMain,
   &amp;amp;callbackInfo , 0, 0);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;::WaitForSingleObject(hThread, 1000);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;::CloseHandle(hThread);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;DWORD WINAPI ThreadMain(LPVOID pvCallbackInfo)&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;CallbackInfo* pCallbackInfo = (CallbackInfo*)pvCallbackInfo;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;msclr::call_in_appdomain(pCallbackInfo-&amp;gt;appDomainId, &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;pCallbackInfo-&amp;gt;pfnCallback);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;return&lt;/span&gt; 0;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;}&lt;/span&gt;&lt;code&gt;&lt;span style="font-size:10.0pt;mso-fareast-font-family:Calibri;mso-fareast-theme-font:minor-latin;mso-ansi-language:EN-US"&gt; &lt;/span&gt;&lt;/code&gt; &lt;span&gt;&lt;/span&gt; 
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;This implementation passes not only the function pointer of the callback function
   to the thread, but a pointer to a structure that contains the callback function pointer
   as well as an integer value identifying the callback application domain. The thread
   then uses this information to invoke the callback function in the right application
   domain.&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;span&gt;As I mentioned, there is a second approach which makes sure that the CLR automatically
   marshals the call to the right application domain. This approach is based on a method
   that you have probably used before. It is called &lt;/span&gt; &lt;a href="http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal.getdelegateforfunctionpointer(VS.85).aspx"&gt; &lt;span&gt; Marshal::GetDelegateForFunctionPointer&lt;/span&gt;&lt;/a&gt;&lt;span style="mso-ansi-language:EN-US"&gt;.
   This method generates a thunk that can be called by native code via a function pointer.
   Notice that in contrast to other thunks, this thunk is aware of the application domain
   where it was created. Therefore, it can automatically switch to the right application
   domain even when this thunk is called by a thread that has just been promoted to a
   managed thread. The following code shows how to use this method:&lt;/span&gt;
&lt;/p&gt;
&lt;p style="font-size:10.0pt;font-family:&amp;quot;Courier New&amp;quot;;"&gt;
   &lt;span &gt;[System::Runtime::InteropServices::UnmanagedFunctionPointer(&lt;/span&gt;
   &lt;br /&gt;
   &lt;span &gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;System::Runtime::InteropServices::CallingConvention::StdCall)]&lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;&lt;span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; CallbackDelegate();&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;static&lt;/span&gt;&lt;span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; ManagedCallback()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;Program::DumpAppDomainInfo(&lt;span style="color:#A31515"&gt;&amp;quot;Program::ManagedCallback&amp;quot;&lt;/span&gt;);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;}&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:blue;"&gt;static&lt;/span&gt;&lt;span&gt; &lt;span style="color:blue"&gt;void&lt;/span&gt; ExecuteInChildDomain()&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;{&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;Program::DumpAppDomainInfo(&lt;span style="color:#A31515"&gt;&amp;quot;Program::ExecuteInChildDomain&amp;quot;&lt;/span&gt;);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;CallbackDelegate^ cb = &lt;span style="color:blue"&gt;gcnew&lt;/span&gt; CallbackDelegate(&amp;amp;ManagedCallback);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;span style="color:blue"&gt;using&lt;/span&gt; System::Runtime::InteropServices::Marshal;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; &lt;span style="color:green"&gt;// this call generates a thunk
   that can be called by native code&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;IntPtr fnPtr = Marshal::GetFunctionPointerForDelegate(cb);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;fNative((PFN_NATIVECALLBACK)fnPtr.ToPointer());&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;
   &lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;
   &lt;/span&gt;
   &lt;br /&gt;
   &lt;span style="color:green;"&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;// the delegate’s lifetime determines
   the lifetime of the generated thunk&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt; &lt;span style="color:green"&gt;// =&amp;gt; keep the delegate alife
   as long as native code needs the thunk&lt;/span&gt;&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;&lt;span &gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt; &lt;span&gt;GC::KeepAlive(cb);&lt;/span&gt;
   &lt;br /&gt;
   &lt;span&gt;}&lt;/span&gt;
   &lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
   In this post I have explained an issue that you have to understand if you want to
   write assemblies that use C++/CLI interop and allow partially trusted callers at the
   same time. In one of my next posts I will describe a safty net that you can implement
   in your pluggable application that ensures that no undesired bypassing of the sandbox
   can occur even if your plugin uses assemblies that are not aware of this issue. 
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.heege.net/blog/aggbug.ashx?id=62340fe1-8ab5-443a-b49e-2b37bbf15c24"&gt;</description>
      <category>C++/CLI</category>
    </item>
    <item>
      <trackback:ping>http://www.heege.net/blog/Trackback,guid,d3b405c1-73d4-4d04-934f-3e2ee2b5f589.aspx</trackback:ping>
      <pingback:server>http://www.heege.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.heege.net/blog/PermaLink,guid,d3b405c1-73d4-4d04-934f-3e2ee2b5f589.aspx</pingback:target>
      <title>Deploying native DLLs with managed wrapper assemblies into the GAC</title>
      <guid>http://www.heege.net/blog/PermaLink,guid,d3b405c1-73d4-4d04-934f-3e2ee2b5f589.aspx</guid>
      <link>http://www.heege.net/blog/PermaLink,guid,d3b405c1-73d4-4d04-934f-3e2ee2b5f589.aspx</link>
      <pubDate>Wed, 30 Sep 2009 16:47:19 GMT</pubDate>
      <description>&lt;p&gt;
   Recently, a customer came up with a straightforward deployment problem:
&lt;/p&gt;
&lt;i&gt;I want to deploy an assembly that wraps a native DLL in the GAC. Deploying the
wrapped native assembly in System32 is to error prone, deploying the wrapped assembly
in WinSxS is too much of an overhead. How can I ensure that the managed wrapper can
load the native assembly?&lt;/i&gt; 
&lt;p&gt;
   I have thought about a solution to this problem some times, but I have to admit, even
   though my first idea was right, so far I never found the time to prove that my guess
   really works. Today I took the time to take a closer look at the solution.
&lt;/p&gt;
&lt;p&gt;
   Here is was my initial idea: 
&lt;p&gt;
   From inspecting mscorlib with ILDASM, I knew that an assembly can have links to other
   files.
&lt;/p&gt;
&lt;p&gt;
   &lt;code&gt; .assembly mscorlib&lt;br /&gt;
   {&lt;br /&gt;
   … attributes ignored here …&lt;br /&gt;
   .file nometadata sortkey.nlp&lt;br /&gt;
   .hash = (6E 30 2E 50 36 FB 60 2C 8E 50 C0 83 54 8B CC EA)&lt;br /&gt;
   .file nometadata sorttbls.nlp&lt;br /&gt;
   .hash = (F9 04 A8 31 CD FB 23 72 95 63 5D 14 9A A0 66 8E)&lt;br /&gt;
   … other .file entries ignored here …&lt;br /&gt;
   .mresource public sortkey.nlp&lt;br /&gt;
   {&lt;br /&gt;
   .file sortkey.nlp at 0x00000000&lt;br /&gt;
   }&lt;br /&gt;
   .mresource public sorttbls.nlp&lt;br /&gt;
   {&lt;br /&gt;
   .file sorttbls.nlp at 0x00000000&lt;br /&gt;
   }&lt;br /&gt;
   } &lt;/code&gt;
&lt;/p&gt;
Furthermore you can see that the files are installed together with mscorlib.dll in
the GAC:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; dir c:\Windows\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089&lt;br /&gt;
   4.550.656 mscorlib.dll&lt;br /&gt;
   262.148 sortkey.nlp&lt;br /&gt;
   20.320 sorttbls.nlp&lt;br /&gt;
   … other files ignored here …&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
&gt;
My assumption was that if you can install native DLLs in the same way in the GAC,
they can be magically found when needed. Creating assemblies with .file references
is easy. Assume the following simple native DLLs:&lt;br /&gt;
nativedll2.cpp, compile with CL /LD /EHs nativedll2.cpp&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; #include 
   &lt;iostream&gt;
      &lt;br /&gt;
      using namespace std;&lt;br /&gt;
      &lt;br /&gt;
      void __declspec(dllexport) fNative2()&lt;br /&gt;
      {&lt;br /&gt;&lt;&lt; "fNative2 called." &lt;&lt; endl;&lt;br/&gt;
      cout }&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
nativedll.cpp, compile with CL /LD /EHs nativedll.cpp&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; #include 
   &lt;iostream&gt;
      &lt;br /&gt;
      #include 
      &lt;windows.h&gt;
         &lt;br /&gt;
         &lt;br /&gt;
         using namespace std;&lt;br /&gt;
         &lt;br /&gt;
         #pragma comment(lib, "nativeDll2.lib")&lt;br /&gt;
         void __declspec(dllimport) fNative2();&lt;br /&gt;
         &lt;br /&gt;
         void __declspec(dllexport) fNative()&lt;br /&gt;
         {&lt;br /&gt;&lt;&lt; "fNative called." &lt;&lt; endl;&lt;br/&gt;
         cout fNative2();&lt;br /&gt;
         }&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
A wrapper assembly for nativedll.cpp can be created with this source code&lt;br /&gt;
testasm.dll:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; using namespace System;&lt;br /&gt;
   &lt;br /&gt;
   #pragma comment(lib, "nativedll.lib")&lt;br /&gt;
   void __declspec(dllimport) fNative();&lt;br /&gt;
   &lt;br /&gt;
   public ref class Test&lt;br /&gt;
   {&lt;br /&gt;
   public:&lt;br /&gt;
   void DoSth()&lt;br /&gt;
   {&lt;br /&gt;
   Console::WriteLine("Test.DoSth called. Calling native DLL now.");&lt;br /&gt;
   fNative();&lt;br /&gt;
   }&lt;br /&gt;
   };&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
To compile it with the two native DLLs as linked files, use the following command
line:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; cl /LD /clr testasm.cpp /link /keyfile:..\keyfile.snk /assemblylinkresource:nativedll.dll
   /assemblylinkresource:nativedll2.dll&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice that the linker flag /assemblylinkresource adds the .file entries to the assembly
manifest:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; .file nometadata nativedll.dll&lt;br /&gt;
   .hash = (EA 16 B4 08 D1 C4 D2 C0 77 CB 00 C7 93 A0 85 4A 41 BC F2 52 )&lt;br /&gt;
   .file nometadata nativedll2.dll&lt;br /&gt;
   .hash = (9D D1 39 D0 4C F9 08 7E 33 2F CD D2 8B C3 3E 55 BD E1 81 27 )&lt;br /&gt;
   .mresource public nativedll.dll&lt;br /&gt;
   {&lt;br /&gt;
   .file nativedll.dll at 0x00000000&lt;br /&gt;
   }&lt;br /&gt;
   .mresource public nativedll2.dll&lt;br /&gt;
   {&lt;br /&gt;
   .file nativedll2.dll at 0x00000000&lt;br /&gt;
   }&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
Given that the DLL is signed, it can be placed into the GAC:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; Gacutil –i testasm.dll&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
Notice the .hash metadata for each .file entry. According to my tests, this metadata
is not used for assembly validation (e. g. via SN.EXE –v testasm.dll), but during
the installation of the assembly into the GAC. If you modify a linked file before
adding the assembly to the GAC, GACUtil will report the following error:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; Failure adding assembly to the cache: One or more modules were streamed in
   which did not match those specified by the manifest. The hash of one or more modules
   found does not match the hash recorded in the manifest.&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
Inspecting the assembly’s GAC_32 subdirectory after successfully installing it to
the GAC shows the following files:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; 105.472 nativedll.dll&lt;br /&gt;
   105.472 nativedll2.dll&lt;br /&gt;
   24.064 testasm.dll&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
Obviously, the native DLLs are now installed into the GAC. The interesting question
is: Are they really loaded from the GAC? The answer is yes. To prove this, use the
following simple client application:&lt;br /&gt;
&lt;br /&gt;
Testapp.cpp (should be in a different directory)&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; using namespace System;&lt;br /&gt;
   &lt;br /&gt;
   int main()&lt;br /&gt;
   {&lt;br /&gt;
   Console::WriteLine("calling Test.DoSth now");&lt;br /&gt;
   Test t;&lt;br /&gt;
   t.DoSth();&lt;br /&gt;
   Console::WriteLine("Press enter to stop app");&lt;br /&gt;
   Console::ReadLine();&lt;br /&gt;
   }&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
You can compile this file with the following command line:&lt;br /&gt;
&lt;div style="margin-left:20pt; margin-top:10pt;"&gt;
   &lt;code&gt; cl /clr testapp.cpp /FU …relative path to testasm.dll …&lt;br /&gt;
   &lt;/code&gt;
&lt;/div&gt;
&lt;br /&gt;
Executing testapp.exe should work even when nativedll.dll and nativedll2.dll are not
in a location that LoadLibrary normally uses; they are loaded from the GAC. If you
want to verify this, compile all sources as shown, run testapp.exe and attach a debugger
while the app is waiting at Console::ReadLine. In the debugger, you can see where
dependent DLLs are loaded from (via the WinDBG command “lm –v” or the VS modules window). 
&lt;br /&gt;
&lt;img width="0" height="0" src="http://www.heege.net/blog/aggbug.ashx?id=d3b405c1-73d4-4d04-934f-3e2ee2b5f589"&gt;</description>
      <category>C++/CLI</category>
    </item>
  </channel>
</rss>