Сообщений 0    Оценка 0        Оценить  
Система Orphus

Работа с TrustedBSD в Mac OS X

Автор: Ставонин Александр Владимирович
Опубликовано: 06.12.2012
Исправлено: 10.12.2016
Версия текста: 1.1

Все мы давно привыкли к разграничению доступа к приложениям и файлам на наших компьютерах на основе избирательного управления доступом (Discretionary Access Control или DAC). Обычно подобная система выглядит как ограниченный в правах пользователь, имеющий доступ к ряду строго определенных ресурсов (файлам, приложениям и т.д.), и администратор, обладающий полным доступом ко всем ресурсам системы.

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

Тем не менее, довольно часто возникают ситуации, когда разграничение прав на основе DAC становится недостаточным, причем не только в случае с корпоративными, но и домашними пользователями. Так, типичной ситуацией с корпоративными пользователями является использование систем предотвращения утечек информации (Data Loss Prevention или DLP), доступа к управлению которым пользователь, даже обладающий правами администратора, иметь не должен. Отличным примером недостаточности DAC как для корпоративных, так и для домашних пользователей могут послужить антивирусы и межсетевые экраны. К примеру, довольно известный Flashback.C OS X Trojan попросту удалял встроенный антивирус Apple из автозагрузки, чему немало способствовал тот факт, что создаваемый на Mac OS X пользователь по умолчанию обладает правами администратора и является sudoer-ом.

Собственно, идея написания этой статьи как раз и родилась из общения с компанией, занимающейся разработкой DLP-систем, которая хотела защитить свое детище от удаления пользователями с правами администратора на компьютерах под управлением Mac OS X.

К счастью, подобная задача довольно легко решается в Mac OS X, так как система имеет встроенные средства для реализации разграничения доступа на основе мандатного управления доступом (Mandatory Access Control или MAC). В общем случае под MAC понимается разграничение доступа к объектам, основанное на назначении метки конфиденциальности для информации, содержащейся в объектах, и выдаче разрешений на обращение к информации такого уровня конфиденциальности. Таким образом, в случае с MAC, вне зависимости от того, кто обращается к ресурсу, простой пользователь или администратор, появляется прекрасная возможность отфильтровать попытку доступа и пресечь ее при необходимости.

Существует довольно большое количество реализаций концепции MAC на разных платформах. Так, в случае Linux это будет SELinux и AppArmor, в Solaris — Solaris Trusted Extensions, ну а в BSD или Mac OS X — TrustedBSD. В рамках данной статьи речь пойдет исключительно о работе с версией TrustedBSD для Mac OS X.

Фреймворк TrustedBSD на Mac OS X появился довольно давно, и основная масса интерфейсов доступна, начиная с версии 10.5. Сам фреймворк довольно активно используется Apple как в Mac OS X, так и в iOS для изоляции приложений посредством «песочницы». К сожалению, уже существующая «песочница» не позволяет защитить приложение от пользователя, и нацелена на защиту пользователя от приложения, так что для решения описанной выше проблемы не подходит. Но это ничуть не мешает воспользоваться TrustedBSD и написать расширение для него.

СОВЕТ

Документация Apple, посвященная TrustedBSD, крайне скудна, и при поиске информации лучше всего использовать «FreeBSD Architecture Handbook», в которой приводится качественное описание TrustedBSD. В целом, интерфейсы, предоставляемые TrustedBSD для Mac OS X и FreeBSD, схожи, но обычно имеют несколько отличающиеся имена. К примеру, функция обратного вызова mpo_vnode_check_open (которая будет использоваться в примере чуть ниже) в случае с FreeBSD будет называться mpo_check_vnode_open. Это несколько затрудняет работу с фреймворком, так как приходится угадывать имена интерфейсов, но позволяет получить более полную картину происходящего.

При помощи TrustedBSD можно фильтровать практически все события, возникающие в процессе работы приложения. Фильтруемые события можно условно разделить на несколько групп:

Хотя данный список не является исчерпывающим, он охватывает основную массу возможностей, предоставляемых TrustedBSD, и позволяет получить представления о возможностях фреймворка.

Теперь можно перейти к практической части и реализовать TrustedBSD-расширение, обеспечивающее ограничение доступа к определенным файлам. Написание подобного расширения не потребует каких-то особых знаний и умений, достаточно создать шаблонный драйвер при помощи Xcode, так как расширения TrustedBSD представляют собой не что иное, как kext-модули, и реализовать пару обработчиков.

СОВЕТ

Данная статья не рассматривает вопросы, связанные с созданием, загрузкой, выгрузкой драйверов для Mac OS X или обеспечением взаимодействия между драйвером и пространством пользователя. Если эти вопросы в новинку, то стоит ознакомиться с великолепным введением в разработку драйверов для Mac OS X, «Kernel Extension Programming Topics», которое можно найти на сайте developers.apple.com.

Непосредственная работа с фреймворком TrustedBSD очень проста. Дело в том, что разработчику доступны всего две функции: mac_policy_register и mac_policy_unregister, которые отвечают за регистрацию и дерегистрацию политик, соответственно.

Для регистрации политик необходимо заполнить две структуры: mac_policy_conf и mac_policy_ops. Структура mac_policy_ops хранит в себе указатели на пользовательские функции обратного вызова, используемые для обработки возникающих событий. В структуру mac_policy_conf помещается служебная информация о конфигурации политики: имя политики, указатель на структуру mac_policy_conf, флаги, управляющие возможностью выгрузки политики, и т.д.

Удобнее всего выполнять действия, связанные с инициализацией политик, из точки входа драйвера, а дерегистрацию – при его завершении. Таким образом, в рассматриваемом примере код инициализации будет предельно прост.

      // Заполним структуру указателями на функции обратного вызова.
      static
      struct mac_policy_ops mac_ops ={
  .mpo_policy_initbsd  = mac_policy_initbsd,    // инициализация политики
  .mpo_vnode_check_open = mac_policy_open,      // обработчик открытия файла
  .mpo_vnode_check_unlink = mac_policy_unlink,  // обработчик удаления файла};
}

// А также структуру, содержащую информацию о нашей политике.staticstruct mac_policy_conf mac_policy_conf = 
{
  .mpc_name         = "protect_demo",
  .mpc_fullname       = "Protect demo!",
  .mpc_labelnames     = NULL,
  .mpc_labelname_count  = 0,
  .mpc_ops        = &mac_ops,
  .mpc_loadtime_flags   = MPC_LOADTIME_FLAG_UNLOADOK, // Политика ВЫГРУЖАЕМА!
  .mpc_field_off      = NULL,  .mpc_runtime_flags    = 0
};

// Указатель на зарегистрированную политику. // Необходим для дерегистрации политики.static mac_policy_handle_t mac_handle;  // Точка входа драйвераint PolicyKext_start(void * d)
{
  // В случае успешного выполнения функции mac_policy_register // в переменную mac_handle будет записан указатель // на зарегистрированную политику.// Зарегистрируем политику.return mac_policy_register(&mac_policy_conf, &mac_handle, d); 
}

Дерегистрация политики осуществляется еще проще.

      // Точка выхода драйвера.int PolicyKext _stop()
{
  return mac_policy_unregister(mac_handle); // Дерегистрируем политику.
}

Стоит также обратить внимание на функцию обратного вызова mac_policy_initbsd. Данная функция вызывается после того, как политика была загружена и инициализирована, и в нашем случае представляет собой просто заглушку. Если же возникает необходимость в размещении в mac_policy_initbsd дополнительной логики, важно помнить о том, что при загрузке политик, на старте операционной системы, данная функция будет вызвана до старта процесса kernel_task (самый первый процесс, PID которого всегда равно 0). Вызов функции wait из mac_policy_initbsd запрещен, прочие вызовы рекомендуется делать с осторожностью.

Нельзя обойти стороной такой важный вопрос, как выгрузка политик. Очевидно, что в процессе разработки политики должны быть выгружаемыми, а в версии, включенной в финальный продукт, наоборот, не выгружаемыми (за редкими исключениями). Чтобы политика была выгружаемой, при ее регистрации необходимо установить в поле mpc_loadtime_flags структуры mac_policy_conf значение MPC_LOADTIME_FLAG_UNLOADOK. Для запрета выгрузки политики данное поле должно быть инициализировано 0. Это не единственно возможные значения флага, и за более подробной информацией стоит обратиться к документации.

Теперь осталось совсем немного, необходимо написать обработчики следующего вида для событий открытия и удаления файлов:

В обоих случаях наибольший интерес представляет собой структура vnode – vp, содержащая информацию об объекте, к которому пытаются получить доступ. Довольно много полезной информации можно извлечь и из структуры kauth_cred_t, например, эффективный и реальный идентификаторы и группы пользователя.

Заключительный шаг – получить информацию об имени текущего процесса, его PID и имя файла, к которому обращаются. Для этого понадобятся следующие функции:

Пора переходить к примерной реализации обработчиков, описанных выше:

      static
      int is_file_accessible(struct vnode *vp)
{
    constchar *vname = NULL;
    char cbuf[MAXCOMLEN+1];
    int retvalue = 0;
    
    if (vp == NULL) // В ряде случаев отсутствие информации о ноде нормально,// поэтому разрешаем продолжить выполнение функции.return (retvalue);
    vname = vnode_getname(vp);
    if(vname) // Имя нода не пустое
    {
        // И идет попытка получить// доступ к конфигурационному файлу, отвечающему за запуск антивирусаif(strcasecmp(vname, "com.apple.xprotectupdater.plist") == 0)
        {
            proc_selfname(cbuf, sizeof(cbuf));
            // и процесс обращающийся к файлу не является 
            // системой обновления антивирусаif (strcasecmp(cbuf,"XProtectUpdater")) 
            {
                retvalue = EPERM; // Доступ необходимо заблокировать.
            }
        }
        vnode_putname(vname); // Очистим запрошенное ранее имя нода
    }
    return(retvalue);
}

staticint mac_policy_open(
kauth_cred_t cred, 
  struct vnode *vp, struct label *label, 
  int acc_mode)
{
    return is_file_accessible(vp);
}

staticint mac_policy_unlink(
kauth_cred_t cred, 
  struct vnode *dvp, struct label *dlabel, struct vnode *vp,
  struct label *label, struct componentname *cnp)
{
    return is_file_accessible(vp);
}

Как видно из данных примеров, реализация расширения для TrustedBSD не является чем-то сложным или запутанным. При этом такое расширение позволяет легко контролировать практически все аспекты выполнения процессов на компьютере.

Использованная литература:


    Сообщений 0    Оценка 0        Оценить