Product SiteDocumentation Site

14.5. Introdução ao SELinux

14.5.1. Princípios

SELinux (Security Enhanced Linux) é um sistema de controle de acesso obrigatório construído sobre a interface LSM (Linux Security Modules) do Linux. Na prática, o kernel consulta o SELinux antes de cada chamada do sistema para saber se o processo está autorizado a fazer a operação dada.
SELinux utiliza um conjunto de regras - conhecidas coletivamente como uma política - para autorizar ou proibir as operações. Essas regras são difíceis de criar. Felizmente, duas diretivas padrão (targeted e strict) são fornecidas para evitar a maior parte do trabalho de configuração.
Com o SELinux, a gestão dos direitos é completamente diferente do sistema Unix tradicional. Os direitos de um processo depende de seu contexto de segurança. O contexto é definido pela identidade do usuário que iniciou o processo, o papel e o domínio que o usuário realizada naquele momento. Os direitos realmente dependem do domínio, mas transições entre os domínios são controladas pelos papéis. Finalmente, as transições possíveis entre os papéis dependem da identidade.
Contextos de segurança e usuários Unix

Figura 14.3. Contextos de segurança e usuários Unix

Na prática, durante o login, ao usuário é atribuído um contexto de segurança padrão (dependendo das funções que eles devem ser capazes de endossar). Isto define o domínio corrente e, assim, o domínio que todos os novos processos filho irao transportar. Se você quiser alterar o papel atual e seu domínio associado, você deve chamar newrole-r role_r -t domain_t (normalmente há apenas um único domínio permitido para uma determinada função, o parâmetro -t pode, assim, muitas vezes, ser deixado de fora). Este comando autentica você pedindo que você digite sua senha. Este recurso proíbe programas mudarem automaticamente os papéis. Tais mudanças só podem acontecer se forem expressamente permitidas pela política SELinux.
Obviamente, os direitos não se aplicam a todos os objetos (arquivos, diretórios, soquetes, dispositivos, etc.). Eles podem variar de objeto para objeto. Para conseguir isso, cada objeto é associado a um tipo (isto é conhecido como etiquetagem). Direitos de domínio são, portanto, expressos com conjuntos de operações (não) permitidos sobre os tipos (e, indiretamente, em todos os objetos que são etiquetados com o tipo de dado).
Por padrão, um programa herda seu domínio do usuário que o iniciou, mas políticas SELinux padrões esperam que muitos programas importantes sejam executados em domínios dedicados. Para conseguir isso, estes executáveis são marcados com um tipo específico (por exemplo ssh) é marcado com ssh_exec_t, e quando o programa é iniciado, ele muda automaticamente no domínio ssh_t). Este mecanismo de transição automática de domínio torna possível conceder apenas os direitos necessários para cada programa. É um princípio fundamental do SELinux.
Transicoes automaticas entre dominios

Figura 14.4. Transicoes automaticas entre dominios

14.5.2. Configurando o SELinux

O suporte SELinux é construído nos kernels padroes fornecidos pelo Debian. As principais ferramentas de suporte Unix SELinux sem quaisquer modificações. É, assim, relativamente fácil, habilitar SELinux.
O comando apt install selinux-basics selinux-policy-default irá instalar automaticamente os pacotes necessários para configurar um sistema SELinux.
O pacote selinux-policy-default contém um conjunto de regras padrão. Por padrão, essa política só restringe o acesso a alguns serviços amplamente expostos. As sessões de usuários não estão restritas e, portanto, é improvável que o SELinux iria bloquear as operações legítimas do usuário. No entanto, isso faz aumentar a segurança dos serviços do sistema rodando na máquina. Para configurar uma política corresponde à antigo regra "strict", você só tem que desativar o módulo unconfined (gerenciamento de módulos está detalhada ainda nesta seção).
Uma vez que a política tenha sido instalada, você deve marcar todos os arquivos disponíveis (o que significa atribuir-lhes um tipo). Esta operação deve ser iniciada manualmente com fixfiles relabel.
O sistema SELinux agora está pronto. Para habilitá-lo, você deve adicionar o parâmetro selinux=1 security=selinux para o kernel Linux. O parâmetro audit=1 habilita o log SELinux que registra todas operações negadas. Finalmente, o parâmetro enforcing=1 traz as regras para aplicação: sem ele SELinux funciona no modo padrão permissive onde as ações negadas são registradas, mas ainda executadas. Você deve, portanto, modificar o arquivo de configuração do GRUB para anexar os parâmetros desejados. Uma maneira fácil de fazer isso é modificar a variável GRUB_CMDLINE_LINUX em /etc/default/grub e executar update-grub. SELinux estará ativo após uma reinicialização.
É interessante notar que o script selinux-activate automatiza as operações e força uma rotulagem na próxima inicialização (o que evita criacao de novos arquivos não-rotulados enquanto o SELinux ainda não estiver ativo, e enquanto a rotulagem estiver acontecendo).

14.5.3. Gerenciando um Sistema SELinux

A política do SELinux é um conjunto modular de regras, e sua instalação detecta e permite automaticamente todos os módulos relevantes com base nos serviços já instalados. O sistema é assim imediatamente operacional. No entanto, quando um serviço é instalado após a política do SELinux, você deve ser capaz de habilitar manualmente o módulo correspondente. Esse é o propósito do comando semodule. Além disso, você deve ser capaz de definir as funções que cada usuário pode endossar, e isso pode ser feito com o comando semanage.
Estes dois comandos podem assim ser usados para modificar a atual configuração do SELinux, que é armazenada em /etc/selinux/default/. Ao contrário de outros arquivos de configuração que você pode encontrar em /etc/, todos esses arquivos não devem ser alterados manualmente. Você deve usar os programas concebidos para este proposito.

14.5.3.1. Gerenciando Modulos SELinux

Módulos SELinux disponíveis são armazenados no diretorio /usr/share/selinux/default/. Para habilitar um desses módulos na configuração atual, você deve usar semodule-i module.pp.bz2. A extensão pp.bz2 significa pacote política (compactada com bzip2).
A removecao de um módulo a partir da configuração atual é feita com semodule -r module. Finalmente, o comando semodule -l listas os modulos que estao atualmente instalados. Também mostra seus números de versão. Môdulos podem ser seletivamente habilitados com semodule -e e desabilitados com semodule -d.
# semodule -i /usr/share/selinux/default/abrt.pp.bz2
# semodule -l
abrt    1.5.0   Disabled
accountsd       1.1.0   
acct    1.6.0   
[...]
# semodule -e abrt
# semodule -d accountsd
# semodule -l
abrt    1.5.0
accountsd       1.1.0   Disabled
acct    1.6.0   
[...]
# semodule -r abrt
# semodule -l
accountsd       1.1.0   Disabled
acct    1.6.0   
[...]
semodule imediatamente carrega a nova configuração, a menos que você use sua opção -n . É interessante notar que o programa atua por padrão na configuração atual (que é indicada pela variavel SELINUXTYPE em /etc/selinux/config), mas que você pode modificar outra, especificando-a com a opcao opção-s.

14.5.3.2. Gerenciando Identidades

Toda vez que um usuário faz logon, eles se atribui uma identidade SELinux. Esta identidade define os papéis que eles serão capazes de endossar. Estes dois mapeamentos (do usuário para a identidade e de esta identidade para papéis) são configuráveis com o comando semanage.
Você deve definitivamente ler a página de manual semanage(8), mesmo se a sintaxe do comando tende a ser semelhante para todos os conceitos que são geridos. Você vai encontrar opções comuns a todos os sub-comandos: -a para adicionar, -d para excluir, -m para modificar, -l para listar, e -t para indicar um tipo (ou domínio).
semanage login -l lista o atual mapeamento entre identificadores de usuário e identidades SELinux. Os usuários que não têm entrada explícita obter a identidade indicado na entrada __default__. O comando semanage login -a -s user_u user irá associar a identidade user_u ao determinado usuário. Finalmente,semanage login -d user exclui a entrada de mapeamento atribuído a este usuário.
# semanage login -a -s user_u rhertzog
# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         SystemLow-SystemHigh *
rhertzog             user_u               SystemLow            *
root                 unconfined_u         SystemLow-SystemHigh *
system_u             system_u             SystemLow-SystemHigh *
# semanage login -d rhertzog
semanage user -l lista o mapeamento entre as identidades de usuários do SELinux e papéis permitidos. Adicionar uma nova identidade requer definir os papéis correspondentes e um prefixo de marcação que é usado para designar um tipo de arquivo pessoal (/home/usuário/*). O prefixo deve ser escolhido entre user, o staff, e o sysadm. O prefixo "staff" resulta em arquivos do tipo "staff_home_dir_t". Criar uma nova identidade de usuário SELinux é feita com semanage usuário -a -R papéis -P prefixo identidade. Finalmente, você pode remover uma identidade de usuário SELinux com semanage usuário -d identidade.
# semanage user -a -R 'staff_r user_r' -P staff test_u
# semanage user -l

                Labeling   MLS/       MLS/                          
SELinux User    Prefix     MCS Level  MCS Range             SELinux Roles

root            sysadm     SystemLow  SystemLow-SystemHigh  staff_r sysadm_r system_r
staff_u         staff      SystemLow  SystemLow-SystemHigh  staff_r sysadm_r
sysadm_u        sysadm     SystemLow  SystemLow-SystemHigh  sysadm_r
system_u        user       SystemLow  SystemLow-SystemHigh  system_r
test_u          staff      SystemLow  SystemLow             staff_r user_r
unconfined_u    unconfined SystemLow  SystemLow-SystemHigh  system_r unconfined_r
user_u          user       SystemLow  SystemLow             user_r
# semanage user -d test_u

14.5.3.3. Gerenciamento de arquivos Contextos, Portas e booleanos

Cada módulo SELinux fornece um conjunto de regras de rotulagem de arquivos, mas também é possível adicionar regras de rotulagem personalizadas para atender a um caso específico. Por exemplo, se você deseja que o servidor web para seja capaz de ler arquivos dentro da hierarquia de arquivos /srv/www/, você pode executar semanage fcontext-a-t httpd_sys_content_t "/srv/www(/.*)? " seguido de restorecon -R /srv/www/. O comando anterior registra as novas regras de rotulagem e redefine o último dos tipos de arquivos de acordo com as atuais regras de rotulagem.
Da mesma forma, portas TCP/UDP são rotuladas de uma forma que garante que apenas os daemons correspondentes podem ouvir nelas. Por exemplo, se você quiser que o servidor web seja capaz de escutar na porta 8080, você deve executar semanage port -m -t http_port_t -p tcp 8080.
Alguns módulos do SELinux exportar opções booleanas que você pode alterar para alterar o comportamento das regras padrão. O utilitário getsebool pode ser usado para inspecionar as opções (getseboolboolean exibe uma opção, e getsebool -a todas elas). O comando setsebool boolean value muda o valor atual de uma opção booleana. A opcao -P faz a mudança permanente, isso significa que o novo valor passa a ser o padrão e será mantido entre as reinicializações. O exemplo abaixo servidores web concede acesso para diretórios home (isto é útil quando os usuários têm sites pessoais em ~/public_html/).
# getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off
# setsebool -P httpd_enable_homedirs on
# getsebool httpd_enable_homedirs 
httpd_enable_homedirs --> on

14.5.4. Adaptando as Regras

Uma vez que a política do SELinux é modular, pode ser interessante para desenvolver novos módulos para (possivelmente personalizar) aplicações que não os possuem. Estes novos módulos, então, completarao a política de referência.
Para criar novos módulos, o pacote selinux-policy-dev é necessário, bem como selinux-policy-doc. Este último contém a documentação das regras padrão (/usr/share/doc/selinux-policy-doc/html/) da amostra e arquivos que podem ser usados como modelos para criar novos módulos. Instale estes arquivos e os estude mais de perto:
$ cp /usr/share/doc/selinux-policy-doc/Makefile.example Makefile
$ cp /usr/share/doc/selinux-policy-doc/example.fc ./
$ cp /usr/share/doc/selinux-policy-doc/example.if ./
$ cp /usr/share/doc/selinux-policy-doc/example.te ./
O arquivo .te é o mais importante. Ele define as regras. O arquivo .fc define os arquivos de contextos", isto é, os tipos atribuídos a arquivos relacionados a este módulo. Os dados dentro do arquivo .fc são utilizados durante a etapa de rotulagem do arquivo. Finalmente, o arquivo if define a interface do módulo: é um conjunto de "funções públicas" que outros módulos podem usar para interagir adequadamente com o módulo que você está criando.

14.5.4.1. Escrevendo um arquivo .fc

Lendo o exemplo a seguir deve ser suficiente para compreender a estrutura de tal arquivo. Você pode usar expressões regulares para atribuir o mesmo contexto de segurança de vários arquivos, ou até mesmo uma árvore de diretórios.

Exemplo 14.2. arquivo example.fc

# myapp executavel tera:
# label: system_u:object_r:myapp_exec_t
# MLS sensibilidade: s0
# MCS categorias: <nenhuma>

/usr/sbin/myapp         --      gen_context(system_u:object_r:myapp_exec_t,s0)

14.5.4.2. Escrevendo um arquivo .if

No exemplo abaixo, a primeira interface ("myapp_domtrans") controla quem pode executar o aplicativo. O segundo ("myapp_read_log") concede direitos de leitura nos arquivos de log do aplicativo.
Cada interface deve gerar um conjunto válido de regras que podem ser incorporadas em um arquivo .te. Você deve, portanto, declarar todos os tipos que você utiliza (com a macro gen_require), e usar diretivas padrão de concessão de direitos. Note, no entanto, que você pode usar interfaces fornecidas por outros módulos. A próxima seção irá dar mais explicações sobre a forma de expressar esses direitos.

Exemplo 14.3. Arquivo example.if

## <summary>Myapp exemple de politica</summary>
## <desc>
##      <p>
##              Mais um texto descritivo sobre myapp.  A tag <desc>
##              tambem pode usar <p>, <ul>, e <ol>
##              tags html para formatacao;
##      </p>
##      <p>
##              Esta politica suporta as seguintes myapp caracteristicas:
##              <ul>
##              <li>Caracteristica A</li>
##              <li>Caracteristica B</li>
##              <li>Caracteristica C</li>
##              </ul>
##      </p>
## </desc>
#

########################################
## <sumario>
##      Executar uma transição de domínio para executar myapp.
## </sumario>
## <param name="domain">
##      Domínio permitiu a transição.
## </param>
#
interface(`myapp_domtrans',`
        gen_require(`
                type myapp_t, myapp_exec_t;
        ')

        domtrans_pattern($1,myapp_exec_t,myapp_t)
')

########################################
## <summary>
##      Ler arquivos de log myapp.
## </summary>
## <param name="domain">
##      Domínio permitiu ler os arquivos de log.
## </param>
#
interface(`myapp_read_log',`
        gen_require(`
                type myapp_log_t;
        ')

        logging_search_logs($1)
        allow $1 myapp_log_t:file r_file_perms;
')

14.5.4.3. Escrevendo um Arquivo .te

De uma olhada no arquivo example.te:
policy_module(myapp,1.0.0) 1

########################################
#
# Declaracoes
#

type myapp_t; 2
type myapp_exec_t;
domain_type(myapp_t)
domain_entry_file(myapp_t, myapp_exec_t) 3

type myapp_log_t;
logging_log_file(myapp_log_t) 4

type myapp_tmp_t;
files_tmp_file(myapp_tmp_t)

########################################
#
# Politica local Myapp 
#

allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; 5

allow myapp_t myapp_tmp_t:file manage_file_perms;
files_tmp_filetrans(myapp_t,myapp_tmp_t,file)

1

O modulo deve ser identificado pelo seu nome e numero da versao. Esta diretiva é requerida.

2

Se o módulo introduz novos tipos, deve declará-los com as directivas como este. Não hesite em criar tantos tipos quantas forem necessários em vez de conceder muitos direitos inúteis.

3

Estas interfaces definem o tipo myapp_t como uma área processo que deve ser utilizada por qualquer executável rotulado com myapp_exec_t. Implicitamente, isso adiciona um atributo exec_type sobre esses objetos, que por sua vez permite que outros módulos de concessão de direitos para executar esses programas: por exemplo, o módulo userdomain, permite que os processos com domínios user_t, staff_t e sysadm_t execute os. Os domínios de outras aplicações confinadas não terão direitos para executar los, a menos que as regras lhes concedem direitos semelhantes (este é o caso, por exemplo, do dpkg com o seu domínio dpkg_t).

4

logging_log_file é uma interface fornecida pela política de referência. Ela indica que os arquivos marcados com o tipo de dado são arquivos de log que deveriam beneficiar das regrassociadas (por exemplo concedem direitos ao logrotate para que possa manipulá los).

5

O diretiva permicao é a diretiva de base utilizada para autorizar uma operação. O primeiro parâmetro é o domínio processo que tem a permissao para executar a operação. A segunda define o objeto que um processo do domínio anterior pode manipular. Este parâmetro é a forma "tipo: classe" onde tipo é o seu tipo SELinux e classe descreve a natureza do objeto (arquivo, diretório, socket, fifo, etc.) Finalmente, o último parâmetro descreve as permissões (as operações permitidas).
As permissões são definidas como o conjunto de operações permitidas e segue este modelo: { operacao1operacao2}. No entanto, você também pode usar macros que representam as permissões mais úteis. O /usr/share/selinux/devel/include/support/obj_perm_sets.spt os lista.
A página web a seguir fornece uma lista relativamente exaustiva de classes de objetos e permissões que podem ser concedidas.
Agora você só tem que encontrar o conjunto mínimo de regras necessárias para assegurar que o aplicativo de destino ou serviço funcione corretamente. Para conseguir isso, você deve ter um bom conhecimento de como o aplicativo funciona e de que tipo de dados ele gerencia e/ou gera.
No entanto, uma abordagem empírica é possível. Uma vez que os objetos relevantes são rotuladas corretamente, você pode usar o aplicativo no modo permissivo: as operações que seriam proibidos são registrados, mas ainda tem sucesso. Ao analisar os logs, você pode agora identificar as operações de permissao. Aqui esta um exemplo de uma tal entrada de log:
avc:  denied  { read write } for  pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1
Para melhor entender esta mensagem, vamos estudá la peça por peça.

Tabela 14.1. Análise de um rastreamento SELinux

MensagemDescricao
avc: deniedUma operação foi negada.
{ read write }Esta operação exigiu permissões de leitura e escrita.
pid=1876O processo com PID 1876 executou a operacao (ou tentou executa la).
comm="syslogd"O processo foi um exemplo do programa syslogd.
name="xconsole"O objeto alvo foi nomeado xconsole. Às vezes, você pode também ter uma variável “path” — com o caminho completo — como opção.
dev=tmpfsO dispositivo que hospeda o objeto de destino é um tmpfs (um sistema de arquivos em memória). Para um disco real, você poderia ver a partição que hospeda o objeto (por exemplo: "sda3").
ino=5510O objeto esta identificado pelo inode numero 5510.
scontext=system_u:system_r:syslogd_t:s0Este é o contexto de segurança do processo que executou a operação.
tcontext=system_u:object_r:device_t:s0Este é o contexto de segurança do objeto destino.
tclass=fifo_fileO objeto destino é um arquivo FIFO.
Ao observar essa entrada de log, é possível construir uma regra que permite esta operação. Por exemplo: allow syslogd_t device_t:fifo_file { read write }. Este processo pode ser automatizado, e é exatamente o que o comando audit2allow oferece (do pacote policycoreutils). Esta abordagem só é útil se os vários objetos já estão corretamente rotulados de acordo com o que deve ser confinado. Em qualquer caso, você terá que analisar cuidadosamente as regras geradas e as validar de acordo com o seu conhecimento da aplicacao. Efetivamente, essa abordagem tende a conceder mais direitos do que são realmente necessários. A solução adequada é muitas vezes criar novos tipos de concessão de direitos apenas sobre esses tipos. Acontece também de uma operação negada não ser fatal para a aplicação, neste caso pode ser melhor adicionar uma regra "dontaudit" para evitar a entrada de log, apesar da efetiva negação.

14.5.4.4. Compilando os Arquivos

Uma vez que os 3 arquivos (example.if, example.fc, e example.te) correspondem às suas expectativas para as novas regras, basta executar make NAME=devel para gerar um módulo no arquivo example.pp file> (você pode o carregar imediatamente com semodule -i example.pp). Se vários módulos são definidos, make irá criar todos os arquivos correspondentes .pp.