在部分信任环境中调用Marshal.GetHRForException(SecurityPermission)

时间:2009-07-12 14:20:53

标签: .net asp.net security code-access-security partial-trust

我有一些IO代码在try..catch中读取流。它捕获IOException并调用System.Runtime.InteropServices.Marshal.GetHRForException() 在捕获中,试图根据HResult采取不同的行动。像这样:

try 
{
    stream.Read(...);
}
catch (IOException ioexc1)
{
   uint hr = (uint) Marshal.GetHRForException(ioexc1);
   if (hr == ...) 
      do_one_thing();
   else
      do_another();
}

程序集已签名并标有AllowPartiallyTrustedCallersAttribute

但是使用trust =“medium”在ASP.NET中运行此代码,我得到了这个例外:

Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

几个问题:

  1. 我认为发生异常是因为GetHRForException调用非托管代码,这在中等信任中是不允许的。正确的吗?
  2. 抛出此异常,而不是在执行GetHRForException时,但是当方法正在进行JIT时 - 正确吗? (stacktrace显示我的方法,但我99%确定没有发生IO异常)
  3. 如果是这样,有没有办法让我改变部分信任环境中的行为,这样我就不会在不允许的地方调用GetHRForException(非托管代码)?换句话说,如何允许JIT在编译时成功,同时还在运行时评估代码是否应该调用GetHRForException()?这样的事情:

  4. catch (IOException ioexc1)
    {
       if (!OkToCallUnmanaged())
           throw ioexc1; 
    
       uint hr = (uint) Marshal.GetHRForException(ioexc1);
       if (hr == ...) 
          do_one_thing();
       else
          do_another();
    }
    

    我认为有一种运行时机制可用于测试权限是否可用,但无法找到它。


    编辑this blog article是答案吗?微软的ShawnFa表示你不能对受LinkDemand保护的方法进行try ... catch(SecurityException)。如果MethodA()调用MethodB(),并且MethodB()用LinkDemand标记为完全信任,则检查LinkDemand,方法A是Jit'ed。因此,为了避免SecurityException,我需要将Marshal.GetHRForException提取到一个单独的方法中。那是对的吗?

    应用于我的代码,MethodA()可能是调用Read的代码,然后在catch中尝试调用GetHRForException()。 GetHRForException是MethodB()。当MethodA()是JIT时,将评估LinkDemand。 (此LinkDemand在我的中等信任ASP.NET方案中失败)。如果我将GetHRForException移动到一个新方法,MethodC(),并且只有在命令权限.Demand()成功之后才有条件地调用MethodC(),理论上我应该能够在JIT时避免SecurityException,因为MethodC()将是只有在permission.Demain()成功之后才进行JIT。

3 个答案:

答案 0 :(得分:3)

所需方法为SecurityPermission.IsUnrestricted()。它返回true或false,指示是否允许该权限。它不像<{3}}那样要求权限。我使用IsUnresticted和SecurityPermissionFlag.UnmanagedCode来查看是否允许程序集调用非托管代码,然后仅在允许时调用非托管代码。

还有一个额外的转折点。 JIT编译器在编译方法时,会在任何称为我要编译的方法的方法上检查CodeAccessPermission LinkDemands。 Marshal.GetHRForException()标有LinkDemand。因此,调用Marshal.GetHRForException()的方法将在JIT编译时抛出无法捕获的SecurityException,此时在受限制的环境中运行,例如具有中等信任的ASP.NET。因此,在这种情况下,我们必须永远不要JIT调用Marshal.GetHRForException()的方法,这意味着我需要将Marshal.GetHRForException()分解为我的代码中的一个单独的方法,该方法只有在UnmanagedCode被调用时才被调用(因此被JITted)不受限制。

以下是一些示例代码:

internal void DoTheThing()
{
    try
    {
        DoSomethingThatMayCauseAnException();
    }
    catch (System.IO.IOException ioexc1)
    {
        // Check if we can call GetHRForException, 
        // which makes unmanaged code calls.
        var p = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
        if (p.IsUnrestricted())
        {
            uint hresult = _HRForException(ioexc1);
            if (hresult == 0x80070021)  // ERROR_LOCK_VIOLATION
                TakeActionOnLockViolation();  // maybe notify the user
            else
                throw new Exception("Cannot handle", ioexc1);
        }
        else
        {
            // The permission is restricted. Therefore, we cannot call
            // GetHRForException, and cannot do the subtle handling of
            // ERROR_LOCK_VIOLATION.  Just bail.
            throw new Exception("Cannot handle", ioexc1);
        }
    }
}

// This method must remain separate, and must not be marked with a LinkDemand for
// UnmanagedCode.
//
// Marshal.GetHRForException() is needed to do special exception handling for
// the read.  But, that method requires UnmanagedCode permissions, and is marked
// with LinkDemand for UnmanagedCode.  In an ASP.NET medium trust environment,
// where UnmanagedCode is restricted, will generate a SecurityException at the
// time of JIT of the method that calls a method that is marked with LinkDemand
// for UnmanagedCode. The SecurityException, if it is restricted, will occur
// when this method is JITed.
//
// The Marshal.GetHRForException() is factored out of DoTheThing in order to
// avoid the SecurityException at JIT compile time. Because _HRForException is
// called only when the UnmanagedCode is allowed, .NET never
// JIT-compiles this method when UnmanagedCode is disallowed, and thus never
// generates the JIT-compile time exception.
//
private static uint _HRForException(System.Exception ex1)
{
    return unchecked((uint)System.Runtime.InteropServices.Marshal.GetHRForException(ex1));
}

答案 1 :(得分:1)

  1. 是 - 中等信任不允许调用非托管代码。允许它的唯一信任级别是完全信任。
  2. 这取决于。 CAS需求可以在运行时进行,但托管环境也可以继续漫游并寻找它无法做的事情。
  3. 您可以通过使用SecurityPermission实例的CAS需求来测试是否可以调用非托管代码。
  4. 制作CAS需求的代码如下所示

    SecurityPermission permission = new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
    try
    {
      permission.Demand();
      // Got it, away we go
    }
    catch (SecurityException)
    {
      // Could not get permission to make unmanaged code calls
      // React accordingly.
    }
    

答案 2 :(得分:0)

通过检查异常类型,System.Runtime.InteropServices.Marshal.GetHRForException()能为您提供任何无法获得的信息吗?看起来它使用静态映射。