1

try..catch 内でストリームを読み取る IO コードがいくつかあります。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でマークされています。

しかし、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 によって保護されたメソッドの周りで try ... catch(SecurityException) を実行できないと述べています。MethodA() が MethodB() を呼び出し、MethodB() が完全信頼の LinkDemand でマークされている場合、LinkDemand は MethodA が Jit されているかどうかでチェックされます。したがって、SecurityException を回避するには、Marshal.GetHRForException を別のメソッドに抽出する必要があります。あれは正しいですか?

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

4

3 に答える 3

3

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

追加のねじれが 1 つあります。JIT コンパイラは、メソッドをコンパイルするときに、コンパイルされるメソッドと呼ばれるメソッドの CodeAccessPermission LinkDemands をチェックします。Marshal.GetHRForException() は LinkDemand でマークされています。したがって、Marshal.GetHRForException() を呼び出すメソッドは、ASP.NET のように信頼度が中程度の制限された環境で実行すると、JIT コンパイル時にキャッチできない SecurityException をスローします。したがって、その場合、Marshal.GetHRForException() を呼び出すメソッドを決して JIT してはなりません。つまり、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));
}
于 2009-07-20T17:56:38.403 に答える
1
  1. はい - 中程度の信頼では、アンマネージ コードへの呼び出しは許可されません。それを許可する唯一の信頼レベルは、完全な信頼です。
  2. 場合によります。CAS の要求は実行時に発生する可能性がありますが、ホスティング環境もさまよい、実行できないことを探す可能性があります。
  3. SecurityPermissionのインスタンスで 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.
}
于 2009-07-12T14:32:50.823 に答える
0

System.Runtime.InteropServices.Marshal.GetHRForException ()は、例外のタイプをチェックすることによって取得できないものを取得しますか?静的マッピングを使用しているようです。

于 2009-07-13T01:40:03.103 に答える