Почему SafeHandle.DangerousGetHandle () "Опасный"? - PullRequest
6 голосов
/ 06 декабря 2011

Впервые я буду использовать SafeHandle.

Мне нужно вызвать этот метод P / Invoke, для которого требуется UIntPtr.

    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern int RegOpenKeyEx(
      UIntPtr hKey,
      string subKey,
      int ulOptions,
      int samDesired,
      out UIntPtr hkResult);

Этот UIntPtr будет производным от класса RegistryKey .NET. Я буду использовать описанный выше метод для преобразования класса RegistryKey в IntPtr, чтобы я мог использовать приведенный выше P / Invoke:

        private static IntPtr GetRegistryKeyHandle(RegistryKey rKey)
        {
            //Get the type of the RegistryKey
            Type registryKeyType = typeof(RegistryKey);

            //Get the FieldInfo of the 'hkey' member of RegistryKey
            System.Reflection.FieldInfo fieldInfo =
                registryKeyType.GetField("hkey", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            //Get the handle held by hkey
            if (fieldInfo != null)
            {
                SafeHandle handle = (SafeHandle)fieldInfo.GetValue(rKey);

                //Get the unsafe handle
                IntPtr dangerousHandle = handle.DangerousGetHandle();                
                return dangerousHandle;
            }
}

Вопросы:

  1. Есть ли лучший способ написать это без использования «небезопасных» ручек?
  2. Почему опасные ручки опасны?

Ответы [ 2 ]

4 голосов
/ 06 декабря 2011

RegistryKey имеет свойство handle. Так что вы можете использовать

private static IntPtr GetRegistryKeyHandle(RegistryKey rKey)
{
    return rKey.Handle.DangerousGetHandle;
}

Это потенциально опасно, потому что указатель, который вы получаете, может больше не быть действительным, когда вы его используете. Цитата MSDN

Использование метода DangerousGetHandle может представлять угрозу безопасности, поскольку, если дескриптор был помечен как недействительный с помощью SetHandleAsInvalid, DangerousGetHandle по-прежнему возвращает исходное, потенциально устаревшее значение дескриптора. Возвращенная ручка также может быть переработана в любой момент. В лучшем случае это означает, что ручка может внезапно перестать работать. В худшем случае, если дескриптор или ресурс, который представляет дескриптор, подвергается воздействию ненадежного кода, это может привести к атаке безопасности повторного использования на повторно используемый или возвращенный дескриптор. Например, ненадежный абонент может запросить данные по только что возвращенному дескриптору и получить информацию для совершенно несвязанного ресурса. См. Методы DangerousAddRef и DangerousRelease для получения дополнительной информации об безопасном использовании методов DangerousGetHandle.

3 голосов
/ 06 декабря 2011

То, что вы делаете, на самом деле опасно.Используемый вами объект RegistryKey может быть собран и завершен сборщиком мусора во время использования IntPtr.Что делает значение дескриптора недействительным, что делает ваш код случайным сбоем.Ну, ладно, случайный сбой не совсем опасен, но он открывает дверь для атаки с повторным использованием ручки, если вы фактически держите ручку в течение длительного периода времени.Режим случайного сбоя должен быть достаточным, чтобы побудить вас что-то с этим сделать.

Сделайте так, чтобы ваше объявление pinvoke выглядело так:

[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
internal static extern int RegOpenKeyEx(SafeRegistryHandle key, string subkey, 
    int options, int sam, out SafeRegistryHandle result);

Так что вы можете последовательно использовать класс-оболочку safe handle,Отрегулируйте код отражения соответствующим образом.

...