I am following the example code from this page to create a sandbox application that launches Windows executable files with limited permissions: https://docs.microsoft.com/en-us/previous-versions/dotnet/framework/code-access-security/how-to-run-partially-trusted-code-in-a-sandbox?redirectedfrom=MSDN
I have changed the example code so that instead of running a specific assembly in a specific path (and including that assembly as a dependency of the sandbox program), I run an executable selected by the user. The code is:
AppDomainSetup adSetup = new AppDomainSetup();
adSetup.ApplicationBase = Path.GetFullPath(filepath);
string sandboxContainingFilepath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase).Substring(6);
PermissionSet permSet = new PermissionSet(PermissionState.None);
permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
permSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.AllAccess, sandboxContainingFilepath));
StrongName fullTrustAssembly = typeof(AppLoader).Assembly.Evidence.GetHostEvidence<StrongName>();
AppDomain newDomain = AppDomain.CreateDomain("AppLoader", null, adSetup, permSet, fullTrustAssembly);
ObjectHandle handle = Activator.CreateInstanceFrom(
newDomain, typeof(AppLoader).Assembly.ManifestModule.FullyQualifiedName,
typeof(AppLoader).FullName
);
AppLoader newDomainInstance = (AppLoader)handle.Unwrap();
string filename = new DirectoryInfo(filepath).Name;
newDomainInstance.ExecuteUntrustedCodeFromPath(Path.GetFullPath(filepath));
...
private void ExecuteUntrustedCodeFromPath(string filepath)
{
ProcessStartInfo startInfo = new ProcessStartInfo(filepath);
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
try
{
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
catch (Exception ex)
{
new PermissionSet(PermissionState.Unrestricted).Assert();
Console.WriteLine("SecurityException caught:\n{0}", ex.ToString());
CodeAccessPermission.RevertAssert();
Console.ReadLine();
}
}
The second block replaces the method ExecuteUntrustedCode() in the example. When using that method, I find that if the untrusted assembly reads from a file it doesn't have permission for, a SecurityException is thrown, and otherwise it is able to run with no exception. This is my goal for my altered version of the code.
However, when running a selected executable in this way, I get the following exception:
SecurityException caught:
System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=...' failed.
at System.StubHelpers.StubHelpers.DemandPermission(IntPtr pNMD)
at Microsoft.Win32.NativeMethods.CreateProcess(String lpApplicationName, StringBuilder lpCommandLine, SECURITY_ATTRIBUTES lpProcessAttributes, SECURITY_ATTRIBUTES lpThreadAttributes, Boolean bInheritHandles, Int32 dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, STARTUPINFO lpStartupInfo, PROCESS_INFORMATION lpProcessInformation)
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at Trustworthy_ACW_1.AppLoader.ExecuteUntrustedCodeFromPath(String filepath) in ...\AppLoader.cs:line 79
The action that failed was:
Demand
The type of the first permission that failed was:
System.Security.Permissions.SecurityPermission
The first permission that failed was:
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=..."
version="1"
Flags="UnmanagedCode"/>
The demand was for:
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=..."
version="1"
Flags="UnmanagedCode"/>
The granted set of the failing assembly was:
<PermissionSet class="System.Security.PermissionSet"
version="1">
<IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=..."
version="1"
Read="...\bin\Debug"
Write="...\bin\Debug"
Append="...\bin\Debug"
PathDiscovery="...\bin\Debug"/>
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=..."
version="1"
Flags="Execution"/>
</PermissionSet>
In case it makes a difference, I did notice that the URL of the failed assembly is my sandbox application, not the target executable. I can add the UnmanagedCode permission, but if I do that, no exception is thrown if the target executable reads from a file outside of the /bin folders I gave it permission for. I have confirmed that it is reading from this file by having it print the output. What do I need to do to make my sandbox application discriminate between allowed and disallowed filepaths to read/write for the executable at the selected filepath?