Разрешение UnmanagedCode. Что это? - PullRequest
6 голосов
/ 30 августа 2010

Следующий код существует в LogEntry.cs в блоке приложения ведения журналов в Enterprise Library:

private bool UnmanagedCodePermissionAvailable
{
  get
  {
    if (!unmanagedCodePermissionAvailableInitialized)
    {
      // check whether the unmanaged code permission is available to avoid three potential stack walks
      bool internalUnmanagedCodePermissionAvailable = false;
      SecurityPermission unmanagedCodePermission = 
                  new SecurityPermission(SecurityPermissionFlag.UnmanagedCode);
      // avoid a stack walk by checking for the permission on the current assembly. this is safe because there are no
      // stack walk modifiers before the call.
      if (SecurityManager.IsGranted(unmanagedCodePermission))
      {
        try
        {
          unmanagedCodePermission.Demand();
          internalUnmanagedCodePermissionAvailable = true;
        }
        catch (SecurityException)
        { }
      }

      this.UnmanagedCodePermissionAvailable = 
          internalUnmanagedCodePermissionAvailable;
    }

    return this.unmanagedCodePermissionAvailable;
  }
  set
  {
    this.unmanagedCodePermissionAvailable = value;
    unmanagedCodePermissionAvailableInitialized = true;
  }
}

Функция вызывается перед выполнением любого из нескольких вызовов P / Invoke для получения различной информации, чтобы помочь заполнитьструктура LogEntry.Если «UnmanagedCodePermission» недоступен, то соответствующему свойству LogEntry присваивается строка, обозначающая это («XXX не доступен»).

Например, LogEntry хочет получить идентификатор потока Win32 и используетФункция Win32, GetCurrentThreadId, вызывается P / Invoke для ее получения.Перед вызовом GetCurrentThreadId он проверяет, доступно ли «разрешение не измененного кода».Если это так, он делает вызов, если нет, то нет.Примерно так:

private void InitializeWin32ThreadId()
{
  if (this.UnmanagedCodePermissionAvailable)
  {
    try
    {
      this.Win32ThreadId = LogEntryContext.GetCurrentThreadId();
    }
    catch (Exception e)
    {
      this.Win32ThreadId = string.Format(
                                  CultureInfo.CurrentCulture,
                                  Properties.Resources.IntrinsicPropertyError,
                                  e.Message);
    }
  }
  else
  {
    this.Win32ThreadId = string.Format(CultureInfo.CurrentCulture,
                Properties.Resources.IntrinsicPropertyError,
                Properties.Resources.
                LogEntryIntrinsicPropertyNoUnmanagedCodePermissionError);
  }
}

Из того, что я понимаю, что, по общему признанию, не так много, выполнение вызовов неуправляемого кода (например, P / Invoke) не всегда возможно из-за безопасности / разрешений / доверия.С помощью этой проверки, чтобы увидеть, возможны ли неуправляемые вызовы кода, можно единообразно защитить все неуправляемые вызовы.

Когда я компилирую этот код, я получаю предупреждение в этой строке:

          if (SecurityManager.IsGranted(unmanagedCodePermission))

Вот предупреждение:

System.Security.SecurityManager.IsGranted (System.Security.IPermission) 'устарело: «IsGranted устарело и будет удалено в будущем выпуске.NET Framework.Пожалуйста, используйте вместо этого свойство PermissionSet для AppDomain или Assembly.

(обратите внимание, что я строю это на .Net 4.0 с использованием VS2010).

Итак, похоже, IsGranted устарел.Я посмотрел на свойство PermissionSet для AppDomain и Assembly, и было неясно, как именно выполнить одну и ту же проверку.

В случае LogEntry, похоже, эта информация не критична, поэтому она не являетсясчитается критической ошибкой, если неуправляемое разрешение недоступно.Рассмотрим следующие вопросы с той же точки зрения.То есть, если разрешение неуправляемого кода недоступно, это не так уж сложно, я могу жить без информации.

Наконец, пара вопросов:

  1. Является ли хорошей идеей попытаться защитить вызовы от неуправляемого кода (например, P / Invoke)?Иногда, всегда, никогда?

  2. Если это хорошая идея для защиты этих вызовов, является ли это разумным шаблоном для этого?Есть ли лучший способ?

  3. Каков будет правильный (то есть не устаревший) способ сделать эквивалентную проверку в .Net 4.0?

1 Ответ

8 голосов
/ 31 августа 2010

До .NET 4 Code Access Security (CAS) была моделью безопасности, используемой .NET Fx.Идея состояла в том, чтобы определить, что код может делать, основываясь на доказательствах, и не позволять делать это другими вещами (SandBoxing).Например, код, присутствующий на вашем локальном компьютере по умолчанию, получает полное доверие (по сути, он может делать все что угодно), а код, поступающий из Интернета, будет иметь сценарий с ограниченными разрешениями (частичное доверие).

IMO, если вы пишете код, которыйвряд ли вы будете работать в частично доверенной среде, тогда вы можете не беспокоиться об этом.Однако для частично доверенных сборок:

  1. Если они могут сообщить своему хосту (например, IE), какие разрешения ему нужны, тогда хост может решить, предоставлять ли их на основе политики безопасности и т. Д. Или хост может запросить пользователяи позволить ему переопределить.Или администратор узнает разрешение, установленное путем проверки сборки, и он может решить обновить политику, чтобы разрешить его.
  2. В случае, если хост не предоставляет необходимого разрешения коду, код может проверить его и обработать его изящно, а негенерация в исключение безопасности.

Таким образом, приведенный выше код иллюстрирует способы достижения этого до .NET 4. В .NET 4 появилась новая модель безопасности, которая более проста в использовании.См. эту & эту статью для получения дополнительной информации.

...