【问题标题】:Catching AccessViolation in .NET 4. Good or bad?在 .NET 4 中捕获 AccessViolation。好还是坏?
【发布时间】:2012-08-31 16:05:49
【问题描述】:

文件中有 SECURITY_IDENTIFIER 结构类型的对象。我需要从此结构中获取所有者 SID。为此,我调用GetSecurityDescriptorOwner WinAPI 函数并创建System.Security.Principal.SecurityIdentifier(它具有以 IntPtr 作为参数的重载)

问题是文件中的这个结构有时会被破坏,所以我从 GetSecurityDescriptorOwner 得到的指针是无效的。它不是 IntPtr.Zero,它是无效的,所以当我创建 SecurityIdentifier 类型的对象时,我得到了 AccessViolationException,这在 .NET 4 中无法通过简单的 try-catch 捕获。

我知道允许捕获此类异常的属性,所以我暂时使用它,但我不喜欢这种解决方案。不建议捕获损坏状态异常 (CSE),但我没有看到任何其他解决方案。这个 WinAPI 函数返回给我无效的指针,我看不到任何方法来检查它的有效性。有什么想法吗?

更新

WinAPI

BOOL WINAPI GetSecurityDescriptorOwner(
  _In_   PSECURITY_DESCRIPTOR pSecurityDescriptor,
  _Out_  PSID *pOwner,
  _Out_  LPBOOL lpbOwnerDefaulted
);

外部定义

[DllImport("Advapi32.dll")]
static extern bool GetSecurityDescriptorOwner(
   IntPtr pSecurityDescriptor,
   out IntPtr owner,
   out bool defaulted);

更新

private static SecurityIdentifier GetSecurityIdentifier()
{
    // Allocate managed buffer for invalid security descriptor structure (20 bytes)
    int[] b = new int[5] {1, 1, 1, 1, 1};

    // Allocate unmanaged memory for security descriptor 
    IntPtr descriptorPtr = Marshal.AllocHGlobal(b.Length);

    // Copy invalid security descriptor structure to the unmanaged buffer
    Marshal.Copy(b, 0, descriptorPtr, b.Length);

    IntPtr ownerSid;
    bool defaulted;

    if (GetSecurityDescriptorGroup(descriptorPtr, out ownerSid, out defaulted))
    {
        // GetSecurityDescriptorGroup returns true, but `ownerSid` is `1`
        // Marshal.GetLastWin32Error returns 0 here
        return new SecurityIdentifier(ownerSid);
    }

    return null;
}

此代码有时会从 SecurityIdentifier 构造函数中抛出 Corrupted State Exceptions。有什么解决办法吗?

【问题讨论】:

  • 你能给我那个 API 方法的外部定义吗?因为也许你应该使用某种 SafeHandle 而不是 IntPtr。 SafeHandle 得到 IsInvalid。
  • 这是一种在其中存储安全描述符的自定义文件格式吗?如果是这样,您为什么要花时间尝试处理这个损坏的描述符,而不是首先修复损坏它的任何东西?
  • 这不是定制的。这是HIVE文件。我正在从 SK 记录中提取 SECURITY_IDENTIFIER。我无法修复它,我不需要这样做。我真的不知道它为什么会损坏,它只是在处理大量数据时有时会发生。

标签: c# .net exception error-handling corrupted-state-exception


【解决方案1】:

你试过打电话给IsValidSecurityDescriptor吗?

[DllImport("Advapi32.dll")]
static extern bool IsValidSecurityDescriptor(IntPtr pSecurityDescriptor);


if (IsValidSecurityDescriptor(descriptorPtr) && 
    GetSecurityDescriptorOwner(descriptorPtr, out ownerSid, out defaulted))
{
     return new SecurityIdentifier(ownerSid);
}

【讨论】:

  • 并非如此。我只找到了 SeValidSecurityDescriptor,上面写着callers of SeValidSecurityDescriptor cannot assume that a returned TRUE implies that the given security descriptor necessarily has valid contents。这个更好看。谢谢。我会尝试发布反馈。
  • 谢谢。看起来这行得通。我肯定会添加这个函数调用,但是我可以删除[HandleProcessCorruptedStateExceptions] 属性并确保它不会因为损坏的安全描述符结构返回true,并且我不会再遇到同样的问题吗?据我从 MSDN 看到的,它说 function checks the validity of the components that are present in the security descriptor, It does not verify whether certain components are present. 我真的不明白这是什么意思。
  • @axe - 很高兴它有帮助。我对内部结构知之甚少,无法确保您不会再遇到同样的问题。你只能吸着看……
  • 谢谢。我认为这是正确的解决方案。我添加了 try-catch 块以防万一,但基于我执行的测试IsValidSecurityDescriptor 有效。再次感谢。
【解决方案2】:

更新:

试试这个:

    [DllImport("Advapi32.dll")]
    static extern bool GetSecurityDescriptorOwner(
       [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)]
       Int32[] securityDescriptor,
       [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1)] 
       out Byte[] owner,
       out Boolean defaulted);


    [DllImport("Advapi32.dll")]
    static extern bool IsValidSecurityDescriptor(
        [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U4)] 
        Int32[] securityDescriptor);

    private static SecurityIdentifier GetSecurityIdentifier()
    {
        // Allocate managed buffer for invalid security descriptor structure (20 bytes)
        Int32[] b = new[] { 1, 1, 1, 1, 1 };

        Byte[] ownerSid;
        bool defaulted;

        if (IsValidSecurityDescriptor(b) &&
            GetSecurityDescriptorOwner(b, out ownerSid, out defaulted))
        {
            return new SecurityIdentifier(ownerSid, 0);
        }

        return null;
    }

    static void Main()
    {
        for (Int32 index = 0; index < 1000; index++)
        {
            SecurityIdentifier identifier = GetSecurityIdentifier();
            String text = identifier == null ? "(none)" : identifier.Value;
            Console.WriteLine(text);
        }

        Console.ReadKey();
    }

【讨论】:

  • 谢谢。明天早上我会测试它并发布反馈。
  • 这是我使用 SafeHandle Cannot marshal 'parameter #2': Ref and out SafeHandle parameters cannot be abstract. 得到的
  • 我不关心错误类型。这些文件很可能已损坏,我只需要获取可能获取的信息。如果出现错误,我只需要编写日志条目并忽略它。问题是 GetSecurityDescriptorOwner 有时会返回 true,但会给出无效的指针。我能够在本地重现此内容,请参阅更新后的示例。
  • 你可能可以使用 SafeFileHandle 代替 SafeHandle,我没有意识到它是 out 参数。除非 IsValidSecurityDescriptor 解决方案当然不起作用。 :)
  • 我可以使用 SafeFileHandle 调用函数,但它并没有太大帮助。它仍然说句柄是有效的,但是当我使用指针时会崩溃。我目前正在使用测试数据运行应用程序,看起来 IsValidSecurityDescriptor 有帮助,尚未完成,但仍然没有崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
  • 2010-11-20
相关资源
最近更新 更多