The following code exists in LogEntry.cs in the enterprise log application application block:
private bool UnmanagedCodePermissionAvailable { get { if (!unmanagedCodePermissionAvailableInitialized) { // check whether the unmanaged code permission is available to avoid three potential stack walks bool internalUnmanagedCodePermissionAvailable = false; SecurityPermission unmanagedCodePermission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode); // avoid a stack walk by checking for the permission on the current assembly. this is safe because there are no // stack walk modifiers before the call. if (SecurityManager.IsGranted(unmanagedCodePermission)) { try { unmanagedCodePermission.Demand(); internalUnmanagedCodePermissionAvailable = true; } catch (SecurityException) { } } this.UnmanagedCodePermissionAvailable = internalUnmanagedCodePermissionAvailable; } return this.unmanagedCodePermissionAvailable; } set { this.unmanagedCodePermissionAvailable = value; unmanagedCodePermissionAvailableInitialized = true; } }
A function is called before calling any of several P / Invoke calls to retrieve various information to help populate the LogEntry structure. If "UnmanagedCodePermission" is not available, then the corresponding LogEntry property is set to a string indicating this ("XXX is not available").
For example, LogEntry wants to get the Win32 thread id and uses the Win32 function, GetCurrentThreadId, called by P / Invoke to get it. Before calling GetCurrentThreadId, it checks if "access to idle code" is available. If so, he makes a call; if not, it is not. Something like that:
private void InitializeWin32ThreadId() { if (this.UnmanagedCodePermissionAvailable) { try { this.Win32ThreadId = LogEntryContext.GetCurrentThreadId(); } catch (Exception e) { this.Win32ThreadId = string.Format( CultureInfo.CurrentCulture, Properties.Resources.IntrinsicPropertyError, e.Message); } } else { this.Win32ThreadId = string.Format(CultureInfo.CurrentCulture, Properties.Resources.IntrinsicPropertyError, Properties.Resources. LogEntryIntrinsicPropertyNoUnmanagedCodePermissionError); } }
From what I understand, admittedly not enough, calls to unmanaged code (like P / Invoke) are not always possible due to security / permissions / trust. Having this check to make sure that unmanaged code calls are possible allows you to equally protect all unmanaged calls.
When I compile this code, I get a warning on this line:
if (SecurityManager.IsGranted(unmanagedCodePermission))
Here is a warning:
System.Security.SecurityManager.IsGranted (System.Security.IPermission) 'is deprecated:' IsGranted is deprecated and will be removed in a future version of the .NET Framework. Instead, use the PermissionSet property for AppDomain or Assembly.
(Note that I am creating this on .Net 4.0 using VS2010).
So, looks IsGranted obsolete. I looked at the PermissionSet property for AppDomain and Assembly, and it was unclear how to do the same check.
In the case of LogEntry, it seems that this information is not critical, so it is not considered a critical failure if unmanaged permission is not available. Consider the following questions from the same point of view. That is, if uncontrolled access to the code is not available, this is not a huge deal, I can live without information.
Finally, a couple of questions:
Is it good to try to protect calls from unmanaged code (e.g. P / Invoke)? Sometimes, always, never?
If it is a good idea to protect these challenges, is this a reasonable model for this? Is there a better way?
What would be the correct (i.e. not obsolete) way to do an equivalent .Net 4.0 check?