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

发布于 2024-07-26 23:09:42 字数 2372 浏览 4 评论 0原文

我有一些 IO 代码可以读取 try..catch 中的流。 它捕获 IOException 并调用 System.Runtime.InteropServices .Marshal.GetHRForException() 在 catch 内,尝试根据 HResult 采取不同的操作。 像这样的东西:

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

程序集已签名并标记为 AllowPartiallyTrustedCallersAttribute。

但是在 ASP.NET 中使用 trust="medium" 运行此代码时,出现此异常: 有

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 编译时抛出 - 正确吗? (堆栈跟踪显示了我的方法,但我 99% 确定没有发生 IO 异常)
  3. 如果是这样,有没有办法让我在部分信任环境中改变行为,这样我就不会调用 GetHRForException (非托管代码)哪里不允许? 换句话说,如何让 JIT 在编译时成功,同时在运行时评估代码是否应该调用 GetHRForException()? 像这样的事情:

catch (IOException ioexc1)
{
   if (!OkToCallUnmanaged())
       throw ioexc1; 

   uint hr = (uint) Marshal.GetHRForException(ioexc1);
   if (hr == ...) 
      do_one_thing();
   else
      do_another();
}

我认为有一个运行时机制可以测试权限是否可用,但一直找不到它。


编辑:是这篇博客文章< /a> 答案是? Microsoft 的 ShawnFa 表示,您不能对受 LinkDemand 保护的方法执行 try ... catch(SecurityException)。 如果 MethodA() 调用 MethodB(),并且 MethodB() 被 LinkDemand 标记为完全信任,则将检查 LinkDemand 并使用 MethodA is Jit'ed。 因此,为了避免 SecurityException,我需要将 Marshal.GetHRForException 提取到一个单独的方法中。 那是对的吗?

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

I have some IO code that reads a stream within a try..catch. It catches IOException and calls System.Runtime.InteropServices.Marshal.GetHRForException()
within the catch, in an attempt to take different actions based on the HResult. Something like this:

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

The assembly is signed and marked with AllowPartiallyTrustedCallersAttribute.

But running this code within ASP.NET with trust="medium", I get this exception:

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

A couple questions:

  1. I think the exception is occurring because GetHRForException calls into unmanaged code, which is not permitted in medium trust. Correct?
  2. This exception is being thrown, not at the time of execution of GetHRForException, but at the time the method is being JIT'ed - Correct? (The stacktrace shows my method, but I am 99% certain that an IO exception has not occurred)
  3. If so, is there a way for me to vary the behavior in a partial trust environment, so that I don't call the GetHRForException (unmanaged code) where it is not permitted? In other words, how can I allow the JIT to succeed at compile time, while also evaluating at runtime whether the code should call GetHRForException()? Something like this:

catch (IOException ioexc1)
{
   if (!OkToCallUnmanaged())
       throw ioexc1; 

   uint hr = (uint) Marshal.GetHRForException(ioexc1);
   if (hr == ...) 
      do_one_thing();
   else
      do_another();
}

I think there is a runtime mechanism for testing if permissions are available, but haven't been able to find it.


EDIT: Is this blog article the answer? ShawnFa of Microsoft says that you cannot do a try ... catch(SecurityException) around a method protected by a LinkDemand. If MethodA() calls MethodB(), and MethodB() is marked with LinkDemand for full trust, then the LinkDemand is checked with MethodA is Jit'ed. Therefore to avoid the SecurityException, I need to extract Marshal.GetHRForException into a separate method. Is that correct?

Applied to my code, MethodA() might be the code that calls Read, and then in the catch tries to call GetHRForException(). GetHRForException is MethodB(). The LinkDemand is evaluated when MethodA() is JIT'd. (This LinkDemand fails in my medium-trust ASP.NET scenario). If I move the GetHRForException into a new method, MethodC(), and conditionally call MethodC() only after an imperative permission.Demand() succeeds, theoretically I should be able to avoid the SecurityException at JIT time, because MethodC() will be JIT'd only after the permission.Demain() succeeds.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

溺孤伤于心 2024-08-02 23:09:42

所需的方法是 SecurityPermission.IsUnrestricted()< /a>. 它返回 true 或 false 指示是否允许该权限。 它不像 SecurityPermission.Demand()。 我将 IsUnresticted 与 SecurityPermissionFlag.UnmanagedCode 结合使用来查看是否允许程序集调用非托管代码,然后仅在允许的情况下调用非托管代码。

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

这是一些示例代码:

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));
}

The method required is SecurityPermission.IsUnrestricted(). It returns a true or false indicating whether the permission is allowed or not. It does not demand a permission, as does SecurityPermission.Demand(). I use IsUnresticted with SecurityPermissionFlag.UnmanagedCode to see if the assembly is allowed to call unmanaged code, and then call the unmanaged code only if allowed.

There is one additional twist. The JIT compiler, when compiling a method, checks for CodeAccessPermission LinkDemands on any method called my the method to be compiled. Marshal.GetHRForException() is marked with a LinkDemand. Hence, my method that calls Marshal.GetHRForException() will throw an uncatchable SecurityException at the time of JIT compile, when run in a restricted environment, like ASP.NET with medium trust. Therefore, we must never JIT the method that calls Marshal.GetHRForException() in that case, which means I need to break out Marshal.GetHRForException() into a separate method in my code that is called (and thus JITted) only when UnmanagedCode is unrestricted.

Here's some example code:

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));
}
笑饮青盏花 2024-08-02 23:09:42
  1. 是 - 中等信任度不允许调用非托管代码。 允许它的唯一信任级别是完全信任。
  2. 这取决于。 CAS 需求可以在运行时发生,但托管环境也可以继续徘徊并寻找它无法执行的操作。
  3. 您可以测试是否可以通过使用 CAS 需求和 安全权限

提出 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.
}
  1. Yes - medium trust will not allow calls into unmanaged code. The only trust level that allows it is full trust.
  2. It depends. CAS demands can take place at runtime, but the hosting environment can also go on a wander and look for things it can't do.
  3. You can test to see if you can make a call to unmanaged code by using a CAS demand with an instance of SecurityPermission.

The code to make a CAS demand looks like this

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.
}
酒废 2024-08-02 23:09:42

是否 System.Runtime.InteropServices.Marshal.GetHRForException () 得到你通过检查异常类型得不到的东西吗? 看起来它使用了静态映射。

Does System.Runtime.InteropServices.Marshal.GetHRForException() get you anything you can't get by checking the type of exception? It looks like it uses a static mapping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文