Extending the AppDomain to Unmanaged Code


Extending the AppDomain to Unmanaged Code

Unmanaged code requires special handling if you want to make access secure. The problem is that you can’t guarantee the actions of the unmanaged code because you can’t control it using the same security system as the rest of your .NET application. In fact, giving your code permission to access unmanaged code of any type can prove detrimental to any security plan you have in place.

Tip

Microsoft recommends sorting your unmanaged code into three classes to make classification easier. You can use the unsafe moniker for code that shouldn’t run except under strict supervision. The native moniker denotes code that runs when the caller has the SecurityPermissionFlag.UnmanagedCode permission. Use the safe moniker only when the code is so safe there’s no chance that anyone could use it for nefarious reasons. Learn more about this naming scheme at http://msdn.microsoft.com/library/en-us/cpguide/html/cpconnamingconventionforunmanagedcodemethods.asp.

The following sections show two techniques for working with unmanaged code. The first shows a technique for working with functions within a DLL. The second shows how to call external applications.

Working with External Functions

The Win32 API provides a wealth of functionality not found in the .NET Framework. Microsoft will eventually incorporate some of the function, but they’ve already said that some functionality will never appear in the .NET Framework. Consequently, your need to access the Win32 API will decrease as the .NET Framework becomes more mature, but won’t ever go completely away. With this in mind, Listing 6.6 shows one technique for calling external functions. (This listing shows only the essential elements of the code. You can find the complete listing in the \Chapter 06\C#\TestNativeMethods or \Chapter 06\VB\TestNativeMethods folder of the source code located on the Sybex Web site.)

Listing 6.6 Calling External Functions

start example
private void btnTest_Click(object sender, System.EventArgs e) {    // Create a new permission and deny access to it.    SecurityPermission Perm;    Perm = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);    Perm.Deny();    // A call to native methods, even those marked safe, should fail.    try    {       Safe.Beep(2000,1000);    }    catch (SecurityException SE)    {       MessageBox.Show(SE.Message);    }    // This call sends the native code access outside the current method    // and could succeed.    try    {       DoMakeSound();    }    catch (SecurityException SE)    {       MessageBox.Show(SE.Message);    } } private void DoMakeSound() {    // Grant permission to make calls to unmanaged code.    SecurityPermission Perm;    Perm = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);    Perm.Assert();    // This call will succeed.    try    {       Safe.Beep(1000, 1000);    }    catch (SecurityException SE)    {       MessageBox.Show(SE.Message);    } }
end example

In this case, the ability to call unmanaged code resides within a single secure function. The btnTest_Click() method begins by creating a SecurityPermission object that contains the SecurityPermissionFlag.UnmanagedCode flag and denying itself this permission. When the btnTest_Click() method calls the Win32 API Beep() function, the call fails. The code then calls on the DoMakeSound() method.

The DoMakeSound() method also creates a SecurityPermission object that contains the SecurityPermissionFlag.UnmanagedCode flag. In this case, it asserts the permission. A call to the Win32 API Beep() function succeeds, even though the caller, btnTest_Click(), lacks the required permission. As you can see, this example also demonstrates the power and potential problems of the Assert() method. However, the Assert() call would still fail if security conditions warranted the action—CLR can’t grant rights that don’t exist. For example, the application user could have a security restriction that would prevent this program from working.

Working with External Programs

The example in Listing 6.7 shows how to work with external programs. In this case, the code creates a copy of Notepad and tells it to open a file named Temp.TXT on the C: drive. You could use a technique similar to the one shown in Listing 6.6 for this task, but the example shows how to keep the program in a separate AppDomain to increase security. (The two listings in this section form one program and only show essential elements of each module. You can find a complete listing in the \Chapter 06\C#\UnmanagedAppDomain or \Chapter 06\VB\UnmanagedAppDomain folder of the source code located on the Sybex Web site.)

Listing 6.7 Accessing External Programs

start example
private void btnTest_Click(object sender, System.EventArgs e) {    AppDomainSetup       APS;        // Domain setup information.    Evidence             EV;         // New evidence for the domain.    AppDomain            LoadApp;    // The application domain.    String               WinDir;     // Windows directory.    String[]             Args;       // Application arguments.    // Get the Windows directory.    WinDir =       Environment.GetFolderPath(Environment.SpecialFolder.System);    WinDir = WinDir.Substring(0, WinDir.LastIndexOf("\\") + 1);    // Define the arguments.    Args = new String[2];    Args.SetValue(WinDir + "Notepad.EXE", 0);    Args.SetValue(@"C:\Temp.TXT", 1);    // Create the domain setup information.    APS = new AppDomainSetup();    APS.ApplicationName = "UnmanagedApp";    // Get evidence for the domain.    EV = AppDomain.CurrentDomain.Evidence;    EV.AddHost(new       SecurityPermission(SecurityPermissionFlag.UnmanagedCode));    // Create the application domain.    LoadApp = AppDomain.CreateDomain("RunApp", EV, APS);    // Run the program.    LoadApp.ExecuteAssembly(       Application.StartupPath + @"\RunApp.EXE", EV, Args); }
end example

The code begins by creating a pointer to the Notepad.EXE file location. It places this information and the name of the file you want to open in a string array named Args. The code will pass these two arguments to the safety class.

As with any AppDomain coding task, you should define the AppDomainSetup and Evidence objects for the new AppDomain. Notice that the permissions for the new AppDomain include the ability to run unmanaged code. Once the code creates the new AppDomain, it uses the ExecuteAssembly() method to call the RunApp application. Listing 6.8 shows the contents of this program.

Listing 6.8 Using the Process.Start() Method

start example
namespace RunApp {    [SecurityPermissionAttribute(SecurityAction.Assert,       Flags=SecurityPermissionFlag.UnmanagedCode)]    class RunWinApp    {       [STAThread]       [SuppressUnmanagedCodeSecurity()]       static void Main(String[] Args)       {          // Determine the number of arguments. If the number of          // arguments is one or two, then use the Process.Start()          // method to run the application.  Otherwise, throw an error.          switch (Args.Length)          {             case 0:                throw new                   ArgumentException("Provide 1 or 2 array arguments.");             case 1:                Process.Start(Args.GetValue(0).ToString());                break;             case 2:                Process.Start(Args.GetValue(0).ToString(),                              Args.GetValue(1).ToString());                break;             default:                throw new                   ArgumentException("Provide 1 or 2 array arguments.");          }       }    } }
end example

The Main() method uses the [SuppressUnmanagedCodeSecurity()] attribute to ensure it can run unmanaged code, even if the caller lacks this ability. The code begins by testing the number of arguments. This is an important check for the Process.Start() method because you could end up with problems such as an uncontrolled program crash otherwise, which is always an invitation to a crash. To make this program completely secure, you’d also validate the arguments supplied by the caller. The “Checking the Data Range” section of Chapter 3 provides some ideas of what to check in this area. Once the program determines that the number of arguments is correct, it calls Process.Start() and starts Notepad with the requested file loaded.




.Net Development Security Solutions
.NET Development Security Solutions
ISBN: 0782142664
EAN: 2147483647
Year: 2003
Pages: 168

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net