質問

try..catch 内のストリームを読み取る IO コードがいくつかあります。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();
}

アセンブリには署名され、次のマークが付けられています AllowPartiallyTrustedCallers属性.

ただし、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 処理時にスローされます。正しいですか?(スタックトレースは私のメソッドを示していますが、IO 例外が発生していないことは 99% 確信しています)
  3. その場合、部分信頼環境での動作を変更して、許可されていない GetHRForException (アンマネージ コード) を呼び出さないようにする方法はありますか?言い換えれば、コードが GetHRForException() を呼び出す必要があるかどうかを実行時に評価しながら、コンパイル時に JIT を成功させるにはどうすればよいでしょうか?このようなもの:

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

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

アクセス許可が利用可能かどうかをテストするためのランタイムメカニズムがあると思いますが、それを見つけることができませんでした。


編集:は このブログ記事 答え?Microsoft の ShawnFa 氏は、試すことはできないと言っています...LinkDemand によって保護されたメソッドに関する catch(SecurityException)。MethodA() が MethodB() を呼び出し、MethodB() が完全信頼の LinkDemand でマークされている場合、LinkDemand は MethodA が Jit'ed であるかどうかチェックされます。したがって、SecurityException を回避するには、Marshal.GetHRForException を別のメソッドに抽出する必要があります。あれは正しいですか?

私のコードに適用すると、MethodA() は Read を呼び出し、キャッチで GetHRForException() を呼び出そうとするコードである可能性があります。GetHRForException は MethodB() です。LinkDemand は、MethodA() が JIT されるときに評価されます。(この LinkDemand は、中程度の信頼性の ASP.NET シナリオでは失敗します)。GetHRForException を新しいメソッド MethodC() に移動し、命令的 Permission.Demand() が成功した後にのみ条件付きで MethodC() を呼び出すと、理論的には JIT 時に SecurityException を回避できるはずです。 JIT は、permission.Demain() が成功した後にのみ行われます。

役に立ちましたか?

解決

必要な方法は、 SecurityPermission.IsUnrestricted(). 。権限が許可されているかどうかを示す true または false を返します。そうではありません 要求 許可、同様に SecurityPermission.Demand(). 。IsUnrestricted を SecurityPermissionFlag.UnmanagedCode とともに使用して、アセンブリがアンマネージ コードの呼び出しを許可されているかどうかを確認し、許可されている場合にのみアンマネージ コードを呼び出します。

さらにもう一つ工夫があります。JIT コンパイラは、メソッドをコンパイルするときに、コンパイル対象のメソッドと呼ばれるすべてのメソッドで CodeAccessPermission LinkDemands をチェックします。Marshal.GetHRForException() は LinkDemand でマークされます。したがって、Marshal.GetHRForException() を呼び出すメソッドは、中程度の信頼性を持つ ASP.NET などの制限された環境で実行すると、JIT コンパイル時にキャッチ不能な SecurityException をスローします。したがって、この場合、Marshal.GetHRForException() を呼び出すメソッドを決して JIT してはなりません。つまり、UnmanagedCode が有効な場合にのみ、Marshal.GetHRForException() をコード内で呼び出される (したがって JIT される) 別のメソッドに分割する必要があります。無制限。

コード例を次に示します。

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. その中に信頼することはできませんの呼び出しでポリシーのコードです。の信頼レベルが可能です。
  2. それはその時々です。CAS要求することでランタイム時において、そのホスティング環境で行うことで歩くと見することはできないます。
  3. テストできます。できるかどうかが呼び出されるようにしてくださポコードを使用CAS需要のインスタンス SecurityPermission.

このコードを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.
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top