Dela via


Process Requires FullTrust

The Process class has a LinkDemand and an InheritenceDemand for FullTrust on it.  This means that if your assembly is not fully trusted, it will be unable to kick off new Processes or get information about running processes.  One implication is that assemblies which do not have SkipVerification permission will not be able to work with this class.  Normally that's fine, since most partial trust assemblies will be coming from the Internet or Local Intranet zones.  However, there are some cases where you want your assembly to have everything but SkipVerification.

One instance that you would want to be running without SkipVerification is the case where you're dynamically generating code.  Applications which emit code via Reflection.Emit should run without SkipVerification to help to ensure that they're emitting correct code.  Since you can't Deny SkipVerification with the effects you'd want, the way most people go about achieving this goal is using a RequestRefuse for SkipVerification.  In the dynamic assembly case, this leads you to the unintuitive way that the declarative security parameters are handled, which often means that the emitting assembly will be outfitted with a RequestRefuse for SkipVerification as well.

Now you're in a position where you're unable to use the Process class, even though the only reason you're not running in FullTrust is that you wanted to ensure that your code generation logic is correct.  How can you enable the Process scenario again?

The easiest pattern is to create an intermediate assembly, which is FullTrust and acts as a proxy to the Process class.  This intermediate assembly would satisfy the LinkDemand, and allow its callers to use the features it's wrapping.  The danger here is that this assembly will need to be APTCA since the calling code will be partially trusted.  Combine that with the fact that this assembly's whole purpose in life is to remove a security check from some classes, and you've got an elevation of privilege issue waiting to happen.  Obviously you want to prevent that, and a good first step is regulating acccess to the assembly.  First of all, don't put it into the GAC unless your design requires it -- this limits the availability of the code to partial trust.  Second, you should have the assembly demand some sort of permission in exchange for removing the FullTrust demand ... for instance, you could have a LinkDemand for a StrongNameIdentityPermission that your application would be granted.  (Note that we don't care about FullTrust Means FullTrust here, since that only applies to FullTrust callers, and they have access to the wrapped code anyway.)  Finally, you might consider making the assembly Transparent with the SecurityCritical attribute, and then explicitly marking the methods which wrap the FullTrust methods as being Critical.  This prevents you from accidentally raising the call stack privileges where you didn't mean to.

Although I focused on Process here (since it seems to be the most common FullTrust demand that people run into), this pattern applies to other FullTrust demands that you want to allow partial trust code access to.

  1. Wrap the FullTrust methods, using an Assert if you're wrapping a full demand.
  2. Demand something from the calling assembly in exchange for removing the demand
  3. Make the assembly transparent, and only mark your elevation wrappers as critical
  4. Apply APTCA, but do not put the assembly in the GAC unless you have to

Comments

  • Anonymous
    December 16, 2005
    I've been trying to accomplish something like you suggest here, using a fully trusted assembly as a proxy so that a partially trusted caller can access the Process class to get a list of active processes. The problem is that it doesn't work. Reqeusts from partially trusted callers fail with a decidedly unhelpful "Request Failed" message.

    If I add other methods to the assembly to perform other types privledged tasks (e.g. file IO) they work fine. This leads me to believe that the basic configuration of the assembly is ok, but missing something extra to be able to access the Process object. Any idea what that might be?

    Here is the full code from the fully trusted assembly:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Diagnostics;
    using System.Security;
    using System.Security.Permissions;

    [assembly: AllowPartiallyTrustedCallers]

    namespace ProcessUtil
    {
    public class ProcessList
    {
    [PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
    public static List<string> GetList()
    {
    List<string> list = new List<string>();
    Process[] processes = Process.GetProcesses();
    foreach (Process proc in processes)
    list.Add(proc.ProcessName);

    return list;
    }

    }
    }
  • Anonymous
    December 16, 2005
    What's the callstack of the failure? I assume it's a SecurityException correct?
  • Anonymous
    December 18, 2005
    Correct. It is a security exception:

    System.Security.SecurityException was unhandled by user code
    Message="Request failed."
    Source="ProcessUtil"
    StackTrace:
    at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Assembly asm, PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh, SecurityAction action, Object demand, IPermission permThatFailed)
    at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Object assemblyOrString, PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh, SecurityAction action, Object demand, IPermission permThatFailed)
    at System.Security.CodeAccessSecurityEngine.CheckSetHelper(PermissionSet grants, PermissionSet refused, PermissionSet demands, RuntimeMethodHandle rmh, Object assemblyOrString, SecurityAction action, Boolean throwException)
    at System.Security.CodeAccessSecurityEngine.CheckSetHelper(CompressedStack cs, PermissionSet grants, PermissionSet refused, PermissionSet demands, RuntimeMethodHandle rmh, Assembly asm, SecurityAction action)
    at ProcessUtil.ProcessList.GetList()
    at _Default.ProcessesLinkButton_Click(Object sender, EventArgs e)
    at System.Web.UI.WebControls.LinkButton.OnClick(EventArgs e)
    at System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument)
    at System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
    at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
    at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
    at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
  • Anonymous
    December 19, 2005
    Actually, I have to revise my position. Nothing requiring full trust worked when called from a partially trusted client. The file IO was working only if the file was in the web path.

    Eventually got this to work by completely scraping the fully trusted assembly, re-building it from scratch, then instead of messing about with caspol or .Net config tool, I just added the assembly to the GAC. While this got the code to work, I don't want this particular assembly in the GAC. I've tried using caspol -af myAssembly.dll to get around this, but to no avail.
  • Anonymous
    January 07, 2006
    You now mention that the intermediate assembly shouldn't be put in the GAC unless absolutely necessary for the design. I agree with that in principle. The trouble is, putting in the GAC seems to be the only way to get this logic to work. I'd be grateful if you could explain what one has to do to the intermediate assembly (besides adding to the GAC) to get it running. Or maybe if you have some insight as to why adding it to the GAC does help. I've read volumes of documentation and tried as many ways as I could find to elevate the assembly to full trust but nothing seems to do the trick.
  • Anonymous
    January 09, 2006
    The intermediate assembly would have to be in the same path as your partial trust assembly. This would work in the case I described above, where you RequestRefuse some permission but would be FullTrust anyway. But if your app started out partial trust, then the GAC is the only way to go.

    Make sure that once it's in the GAC that you demand some permission before just removing the FullTrust demand!

    -Shawn