Slx

Материал из ALT Linux Wiki

Selinux + Xorg + ScreenShot

Цель: обезопасить приложения которые работают в защищенном режиме от снятия отпечатка окна. В среде Xorg screenshot можно сделать различными способами. Например, один из способов использовать утилиту `import' из пакета ImageMagic. Чтобы сделать screenshot всего экрана нужно вызвать утилиту из командной строки с следующими параметрами:

$ import -window root image.jpg


import

  • Работа утилиты `import' сводится к обращению к Xorg-серверу с запросом R073 X11:GetImage

Весь список доступных запросов которые можно сделать к Xorg серверу можно просмотреть: http://cgit.freedesktop.org/xorg/xserver/tree/dix/protocol.txt Большинство этих запросов можно ограничить (отклонить) средствами XACE/SELinux поддержкой в Xorg и соответствующими правилами в SeLinux политике. Но при таком подходе графические приложения становятся неработоспособными. В нашем случае нужно чтобы window manager, работая на незащищенном уровне, мог управлять защищенными приложениями.

  • В политике SeLinux добавленно правило:
mlsconstrain x_drawable { read blend }
         ((l1 dom l2)
         or
         t1 == mlstrustedsubject);

Это правило говорит что для класса x_drawable можно вызвать метод read только если выполняется правило Белла — Лападулы. Но данное правило не позволет огранчить от создания screenshot защищенного приложения. Почему? Далее следует ответ. Конечно, Xorg сервер откажет в обслуживании X11:GetImage если мы запросил картинку конкретно для защищенного окна. Приложение получит отказ в обслуживании с ошибкой доступа BadAccess. Но проблема кроется в том что при снятии отпечатка окошка мы не делаем запрос о получении картинки с защищенного окна. Мы делаем запрос или к контейнеру который содержит это окно, либо к Root Window в системе Xorg. Контейнер для окошка - это тоже окно, с незащищенным уровнем доступа. И соответственно с него можно снять отпечаток. Root Window окно тоже имееющее нулевой уровень защиты.


В ALT Linux пошли следующем путем. Припустим есть некий клиент, который будет делать запрос к Xorg серверу о получении картинки некого окна. У клиента есть свой уровень доступа. Далее срабатывает следующий алгоритм: При запросе к Xorg серверу на получение картинки для окошка происходит углубление по всему дереву окон которые являются дочерними к запрашиваемому. Если доступ для клиента, сделавшего запрос к дочернему окошку запрещен согласно политике SeLinux, тогда такое дочернее окошко закрашивается в черный цвет. При этом необходимо учесть, что над (выше) дочерним окошком может быть другое дочернее окошко, которое его частично перекрывает. В таком случае вычисляется только видимая часть дочернего окошка по отношению к запрашиваемому и окошек-братьев находящихся выше по дереву.


ksnapshot

При использовании kde4-ksnapshot для снятия отпечатка экрана используется другой запрос к Xorg серверу. А именно X11:CopyArea. Обработка этого запроса производится аналогично X11:GetImage.

Следует учитывать вытекающие моменты:

  • при холостом работе SELinux (т.е. в режиме permissive) ограничения срабатывать не будут и пользователь сможет снять отпечаток секретного окна.
  • При нарушении прав доступа будет создано audit сообщение:

avc: denied { read } for request=X11:CopyArea comm=/usr/bin/ksnapshot resid=200000e restype=WINDOW scontext=generic_u:generic_r:generic_t:s0-s5:c0.c15 tcontext=generic_u:object_r:login_t:s3 tclass=x_drawable

  • Остается возможность снять отпечаток защищенного окна, для этого нужно import/ksnapshot запустить с уровнем который гарантирует доступ к защищаемым приложениям.


Патч для запросов X11:GetImage & X11:CopyArea находится: http://git.altlinux.org/people/stanv/packages/?p=xorg-server.git;a=commit;h=4faafa948450751081c4939aa5a908099fa4a5cb


Composite

У сервер Xorg есть возможность использовать extension Composite.

Для отключения extension Composite нужно в каталоге /etc/X11/xorg.conf.d/ создать файл с содержимым:

Section "Extensions"
	    Option "Composite" "Disable"
EndSection

Чтобы посмотреть какие еще мы может отключить extension:

# Xorg -extension ?
[mi] Extension "?" is not recognized
[mi] Only the following extensions can be run-time disabled:
[mi]    Generic Events
[mi]    Composite
[mi]    DAMAGE
[mi]    DOUBLE-BUFFER
[mi]    DPMS
[mi]    GLX
[mi]    MIT-SCREEN-SAVER
[mi]    MIT-SHM
[mi]    RANDR
[mi]    RENDER
[mi]    SECURITY
[mi]    X-Resource
[mi]    XFIXES
[mi]    XINERAMA
[mi]    SELinux
[mi]    XTEST
[mi]    XVideo

Кратко говоря, работа extension composite сводится к постоянному хранению полных отпечатков (Pixmap) для заданных окошек. Полных тут имеется в виду, отпечаток для окна будет полным, даже если его перекрывает другое окошко, или если оно частично находится вне зоны отображения. Детально: http://cgit.freedesktop.org/xorg/proto/compositeproto/tree/compositeproto.txt

Или кратко на английском: The Composite extension for X causes an entire sub-tree of the window hierarchy to be rendered to an off-screen buffer. Applications can then take the contents of that buffer and do whatever they like. The off-screen buffer can be automatically merged into the parent window or merged by external programs, called compositing managers.

Для каких окошек хранить pixmap говорит composite manager. Но в тоже самое время любое другое приложение может указать другой/свой набор окошек для которых следует хранить pixmap. Composite никакого отношения к OpenGL не имеет. Этот extension только хранит полные pixmap для заданных окошек.

Получается что при активном Composite можно опять запросить pixmap окна. Но закрасить дочерние защищенные окошки уже не так просто.

Composite используется в связке с composite manager. Composite manager в случае KDE выступает kwin.

При создании/запуска любого приложения kwin:

  • создает новый контейнер для нового приложения (кнопочки закрыть, свернуть, рамку, итд…).
  • делает ReParrent нового приложения в этот контейнер.
[    73.087] (WW) avc:  denied  { blend } for request=X11:ReparentWindow comm=kwin resid=700000e restype=WINDOW scontext=generic_u:generic_r:generic_t:s0-s5:c0.c15 tcontext=generic_u:object_r:login_t:s3 tclass=x_drawable

При доступном Composite + GLX kwin также:

  • Говорит Composite следить за новым контейнером и предоставлять PixMap.
  • Отображает все контейнеры через специальное окно overlay и glx.

Т.е. при закраске окон мы получим закрашенные области в для активных окон на экране всегда.

Дальше, я спросил может ли kwin одновременно управлять окошками которые были redirected и которые остались обычными. На что я получил ответ "нет". Детали переписки: http://lists.kde.org/?l=kwin&m=137701781430595&w=2 За то узнал что для kwin можно на лету отключить использование composite: Shift-Alt-F12

И того при наличии активного composite можно сделать снимок окна с защищенными под-окошками.

ksnapshot запрашивает снимок нужного ему окна у kwon через dubs: /usr/share/kde4/services/kwin/screenshot.desktop

Я пробовал делать для защищенных окошек UnRedirect на что Kwin себя плохо реагировал.


Дополнительная информация для разработчиков

  • Xorg для контроля доступа используется фреймфорк XACE.
  • XSELinux - это модуль для XACE.
  • Для XACE можно написать свой модуль.
  • Для XACE возможна одновременная работа нескольких модулей.
  • Доступ будет разрешен только если все модули XACE разрешат данное действие.

Для SeLinux пишется политика, на основе которой работает Userspace Objects Manager. Возможные действия которые позволяет контролировать XACE: http://www.x.org/archive/X11R7.5/doc/security/XACE-Spec.html#resource_access_hook

Модуль XSELinux транслирует эти действия в свои которые определены для классов-Selinux. Например в xorg-server/Xext/xselinuxint.h

static struct security_class_mapping map[] = {
   {"x_drawable",
    {"read",                   /* DixReadAccess */
     "write",                  /* DixWriteAccess */


Самым сложным моментом является сопоставление классов Selinux и X resource class. Сложность заключается в том, что сложно понять сущность класса SeLinux и ресурсов X resource class. Так же сложно понять какой X-ресурс нужно ограничить чтобы получить желаемый результат.

Классы для Xorg в SeLinux: http://selinuxproject.org/page/ObjectClassesPerms#X_Server_Object_Classes

XSelinux определяет xorg-server/Xext/xselinuxint.h :

/* Security class constants */                                                  
#define SECCLASS_X_DRAWABLE     1                                               
#define SECCLASS_X_SCREEN       2                                               
#define SECCLASS_X_GC           3                                               
#define SECCLASS_X_FONT         4                                               
#define SECCLASS_X_COLORMAP     5                                               
#define SECCLASS_X_PROPERTY     6                                               
#define SECCLASS_X_SELECTION        7                                           
#define SECCLASS_X_CURSOR       8                                               
#define SECCLASS_X_CLIENT       9                                               
#define SECCLASS_X_POINTER      10                                              
#define SECCLASS_X_KEYBOARD     11                                              
#define SECCLASS_X_SERVER       12                                              
#define SECCLASS_X_EXTENSION        13                                          
#define SECCLASS_X_EVENT        14                                              
#define SECCLASS_X_FAKEEVENT        15                                          
#define SECCLASS_X_RESOURCE     16       


Ресурсы Х определены как в xorg-server/include/resource.h

#define RC_DRAWABLE    ((RESTYPE)1<<30)  == 1073741824
/* types for Resource routines */                                               
                                                                               
#define RT_WINDOW   ((RESTYPE)1|RC_DRAWABLE)                                    
#define RT_PIXMAP   ((RESTYPE)2|RC_DRAWABLE)                                    
#define RT_GC       ((RESTYPE)3)                                                
#undef RT_FONT                                                                  
#undef RT_CURSOR                                                                
#define RT_FONT     ((RESTYLE)4)                                                
#define RT_CURSOR   ((RESTYPE)5)                                                
#define RT_COLORMAP ((RESTYPE)6)                                                
#define RT_CMAPENTRY    ((RESTYPE)7)                                            
#define RT_OTHERCLIENT  ((RESTYPE)8|RC_NEVERRETAIN)                             
#define RT_PASSIVEGRAB  ((RESTYPE)9|RC_NEVERRETAIN)                             
#define RT_LASTPREDEF   ((RESTYPE)9)                                            
#define RT_NONE     ((RESTYPE)0)


Трансляция X ресурса в класс SeLinux происходит в xorg-server/Xext/xselinux_label.c

security_class_t                                                                
SELinuxTypeToClass(RESTYPE type)                                                
{                                                                               
    void *tmp;                                                                  
                                                                               
    tmp = SELinuxArrayGet(&arr_types, type & TypeMask);                         
    if (!tmp) {                                                                 
        unsigned long class = SECCLASS_X_RESOURCE;                              
                                                                                
        if (type & RC_DRAWABLE)                                                 
            class = SECCLASS_X_DRAWABLE;                                        
        else if (type == RT_GC)                                                 
            class = SECCLASS_X_GC;                                              
        else if (type == RT_FONT)                                               
            class = SECCLASS_X_FONT;
...

Далее следует цепочка при скриншоте с помощью команды `import':

libX11-> XGetImage -> X11:GetImage -> DoGetImage (dispatch.c") -> dixLookupDrawable -> dixLookupResourceByClass -> XaceHook(XACE_RESOURCE_ACCESS, DixReadAccess) -> SELinuxResource -> SELinuxDoCheck()


Например запрос на разрешение делегирования окошка в юрисдикцию Composite происходит как xorg-server/composite/compext.c:

   VERIFY_WINDOW(pWin, stuff->window, client,                                  
                 DixSetAttrAccess | DixManageAccess | DixBlendAccess);

Написать правило для политики SeLinux для ограничения класса `x_drawable' на метод `blend' смысла нету. Загадка на сообразительность: почему?

/usr/include/X11/X.h
typedef XID Window;
typedef XID Drawable;
include/pixmap.h:74:typedef struct _Drawable *DrawablePtr;
./include/pixmapstr.h:55:typedef struct _Drawable {
./include/windowstr.h:128:typedef struct   {


Для тестирования работы политики полезно иметь модуль SeLinux со следующим содержимым:

# cat test.te
policy_module(test, 1.0.25)
 	gen_require(`
			attribute unconfineddomain;
			attribute domain;
			attribute file_type;
			attribute x_instance;
 			')
gen_bool(x_test, true)
	if (x_test) {
#		auditallow domain self:x_resource *;
#		auditallow domain self:x_screen *;
#		auditallow domain self:x_application_data *;
#		auditallow domain self:{ x_gc } *;
#		auditallow domain self:x_property *;
#		auditallow domain x_instance:x_property *;
#		auditallow domain x_instance:x_event *;
#		auditallow domain self:x_gc *;
 		auditallow domain self:x_drawable { read blend };
	}
# vim:expandtab ts=4 sw=4 tw=0


Полезные ссылки


Screenshot

привет скриншота с рабочего стола, на котором есть засекреченное окно


XORG

seapplet

  1. seapplet - специальный апплет изначально написан для KDE4. Исполнитель qwest@.
  2. Апплет позволяет указать в каком контексте безопасности необходимо запускать следующее приложение.
  3. Служит только как указатель выбранного статуса пользователем. К запуску самих приложений отношения не имеет.
  4. При отсутствии SeLinux иконка становится не активная.
  5. Автоматически загружается для каждого пользователя при старте графической среды.

KDE4

  1. timonbl4@ внес изменения в KDE4 для запуска приложений в нужном контексте.
  2. В момент запуска приложений идет опрос статуса у апплета seapplet
  3. В конечном итоге все сводится к запуску приложения через вспомогательную утилиту /usr/bin/slrun (stanv@)
  4. Нужно убедится что в KDE4 отключено сохранения сессий. Так как нету возможности корректно востановить контекст не закрытых приложений в новой сессии.

DBUS

  1. При запуске приложения проверятся есть ли запущенный демон D-BUS для текущей сессии.
  2. Для каждого контекста безопасности (уровня/набора категорий) создается своя копия демона D-BUS.
  3. В рамках X сессии для каждого контекста присутствует только один экземпляр демона D-BUS.
  4. Параметры доступа к демону D-BUS (DBUS_SESSION_BUS_PID, DBUS_SESSION_BUS_ADDRESS) сохраняются в PROPERTY для root окна XORG. Чтобы предотвратить повторный запуск демона.
  5. PROPERTY окон для каждого контекста безопасности доступны только для приложений с нужным контекстом безопасности. Поэтому установка и чтения PROPERTY root окна должна происходить в нужном контексте.
  6. Установку PROPERTY и запуск демона D-BUS производит скрипт /usr/bin/slrun2
  7. В политике безопасности для класса dbus ограниченна передача сообщений. Сообщения могут передаваться только между приложениями с одинаковым контекстом безопасности. См. policy/mls.in

SLRUN

  1. Вспомогательные скрипты slrun и slrun созданы специально для запуска приложений в XORG
  2. slrun запускает slrun2 в нужном контексте безопасности.
  3. запуск slrun2 идет через утилиту newrole
  4. при запуске newrole идет обращение в PAM.
  5. В конфигурации PAM указано, какие дополнительные каталоги нужно создать. См. /etc/security/alt.newrole
  6. slrun2 подготавливает окружение. выставляет необходимые переменные, проверяет наличие демона D-BUS на данном контексте безопасности, и запускает его в случае отсутствия.


xsession-errors

  1. Для набора приложений, выполняющихся на одном контексте безопасности логи пишутся в файл /tmp/.private/<USER>/<MLS>/.xsession-errors\:<DISPLAY>
  2. STDOUT/STDERR переопределяется в slrun2