Introdução ao SELinux - Parte 2: Arquivos e processos

ChicoFedora
editado julho 2021 em Servidores

Introdução

Na primeira parte da série SELinux , vimos como habilitar e desabilitar o SELinux e como alterar algumas configurações de política usando valores booleanos. Nesta segunda parte, falaremos sobre contextos de segurança de arquivos e processos.

Para atualizar sua memória do tutorial anterior, um contexto de segurança de arquivo é um tipo e um contexto de segurança de processo é um domínio.

Nota
Os comandos, pacotes e arquivos mostrados neste tutorial foram testados no CentOS 7. Os conceitos permanecem os mesmos para outras distribuições.

Neste tutorial, estaremos executando os comandos como usuário root, a menos que seja indicado de outra forma. Se você não tiver acesso à conta root e usar outra conta com privilégios sudo, precisará preceder os comandos com o sudo.

Criando contas de usuário de teste

Primeiro, vamos criar quatro contas de usuário para demonstrar os recursos do SELinux à medida que avançamos.

• joao
• pedro
• maria
• ana

Você deve estar logado com o usuário root . Vamos executar o seguinte comando para adicionar a conta joao :

$ useradd joao

Em seguida, executamos o comando “passwd” para criar/alterar sua senha:

$ passwd joao

A saída solicitará uma nova senha. Uma vez fornecida, a conta estará pronta para o login:

Changing password for user regularuser.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.

Vamos criar as outras contas também:

$ useradd pedro
$ passwd pedro
$ useradd maria
$ passwd maria
$ useradd ana
$ passwd ana

SELinux para processos e arquivos

O objetivo do SELinux é proteger como os processos acessam arquivos em um ambiente Linux. Sem o SELinux, um processo ou aplicativo como o Apache será executado no contexto do usuário que o iniciou. Portanto, se o seu sistema for comprometido por um aplicativo não autorizado que esteja sendo executado no usuário root, o aplicativo poderá fazer o que quiser, pois o root possui direitos abrangentes em todos os arquivos.

O SELinux tenta dar um passo adiante e eliminar esse risco. Com o SELinux, um processo ou aplicativo terá apenas os direitos necessários para funcionar e NADA mais. A política do SELinux para o aplicativo determinará a quais tipos de arquivos ele precisa acessar e a quais processos ele pode fazer a transição. As políticas do SELinux são escritas por desenvolvedores de aplicativos e enviadas com a distribuição Linux que a suporta. Uma política é basicamente um conjunto de regras que mapeia processos e usuários aos seus direitos.

Começamos a discussão desta parte do tutorial, entendendo o significado dos contextos e domínios do SELinux .

A primeira parte da segurança coloca um rótulo em cada entidade no sistema Linux. Um rótulo é como qualquer outro atributo de arquivo ou processo (proprietário, grupo, data de criação etc.); mostra o contexto do recurso. Então, o que é um contexto? Simplificando, um contexto é uma coleção de informações relacionadas à segurança que ajuda o SELinux a tomar decisões de controle de acesso. Tudo em um sistema Linux pode ter um contexto de segurança: uma conta de usuário, um arquivo, um diretório, um daemon ou uma porta podem ter seus contextos de segurança. No entanto, o contexto de segurança vai significar coisas diferentes para diferentes tipos de objetos.

Contextos de arquivos do SELinux

Vamos começar entendendo os contextos de arquivo do SELinux. Vejamos a saída de um comando ls -l regular no diretório /etc.

$ ls -l /etc/*.conf

Isso nos mostrará uma saída familiar:

... 
-rw-r--r--. 1 root root    19 Aug 19 21:42 /etc/locale.conf
-rw-r--r--. 1 root root   662 Jul 31  2013 /etc/logrotate.conf
-rw-r--r--. 1 root root  5171 Jun 10 07:35 /etc/man_db.conf
-rw-r--r--. 1 root root   936 Jun 10 05:59 /etc/mke2fs.conf
...

Simples, certo? Vamos agora adicionar o -Z:

$ ls -Z /etc/*.conf

Agora temos uma coluna extra de informações após a propriedade do usuário e do grupo:

...
-rw-r--r--. root root system_u:object_r:locale_t:s0    /etc/locale.conf
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/logrotate.conf
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/man_db.conf
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/mke2fs.conf
...

Esta coluna mostra os contextos de segurança dos arquivos. Diz que um arquivo foi rotulado com seu contexto de segurança quando você tem essas informações disponíveis. Vamos dar uma olhada em um dos contextos de segurança.

-rw-r--r--. root    root  system_u:object_r:etc_t:s0       /etc/logrotate.conf

O contexto de segurança é esta parte:

system_u:object_r:etc_t:s0

Existem quatro partes e cada parte do contexto de segurança é separada por dois pontos (:). A primeira parte é o contexto do usuário do SELinux para o arquivo. Discutiremos os usuários do SELinux mais tarde, mas, por enquanto, podemos ver que é system_u. Cada conta de usuário do Linux é mapeada para um usuário do SELinux e, nesse caso, o usuário raiz que possui o arquivo é mapeado para o usuário system_u SELinux. Esse mapeamento é feito pela política do SELinux.

A segunda parte especifica a função SELinux , que é object_r . Para revisar as funções do SELinux, consulte o primeiro artigo do SELinux.

O mais importante aqui é a terceira parte, o tipo de arquivo listado aqui como etc_t . Esta é a parte que define a que tipo de arquivo ou diretório pertence. Podemos ver que a maioria dos arquivos pertence ao tipo etc_t no /etc, você pode pensar no tipo como uma espécie de "grupo" ou atributo para o arquivo: é uma maneira de classificar o arquivo.

Também podemos ver que alguns arquivos podem pertencer a outros tipos, como o locale.conf que tem um tipo locale_t. Mesmo quando todos os arquivos listados aqui tiverem o mesmo usuário e proprietário do grupo, seus tipos poderão ser diferentes.

Como outro exemplo, vamos verificar os contextos de tipo para diretórios pessoais do usuário:

$ ls -Z /home

Os diretórios pessoais terão um tipo de contexto diferente: user_home_dir_t

drwx------. maria      maria      unconfined_u:object_r:user_home_dir_t:s0      maria
drwx------. root           root           system_u:object_r:lost_found_t:s0 lost+found
drwx------. joao    joao    unconfined_u:object_r:user_home_dir_t:s0      joao
drwx------. restricteduser ana unconfined_u:object_r:user_home_dir_t:s0      ana
drwx------. switcheduser   switcheduser   unconfined_u:object_r:user_home_dir_t:s0      pedro
drwx------. sysadmin       sysadmin       unconfined_u:object_r:user_home_dir_t:s0      sysadmin

A quarta parte do contexto de segurança, s0, tem a ver com segurança multinível ou MLS. Basicamente, essa é outra maneira de aplicar a política de segurança do SELinux e essa parte mostra a sensibilidade do recurso (s0). Falaremos brevemente sobre sensibilidade e categorias posteriormente. Para a maioria das configurações completas do SELinux, os três primeiros contextos de segurança são mais importantes.

Contextos do processo SELinux

Vamos agora falar sobre os contextos de segurança do processo.
Inicie os serviços Apache e SFTP. Instalamos esses serviços no primeiro tutorial do SELinux.

$ systemctl start httpd
$ systemctl start vsftpd 

Podemos executar o ps comando com alguns sinalizadores para mostrar os processos Apache e SFTP em execução no nosso servidor:

$ ps -efZ | grep 'httpd\|vsftpd'

Mais uma vez, o sinalizador -Z é usado para exibir os contextos do SELinux. A saída mostra o usuário executando o processo, o ID do processo e o ID do processo pai:

 system_u:system_r:httpd_t:s0            root        7126    1       0 16:50 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0            apache      7127    7126    0 16:50 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0            apache      7128    7126    0 16:50 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0            apache      7129    7126    0 16:50 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0            apache      7130    7126    0 16:50 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0            apache      7131    7126    0 16:50 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:ftpd_t:s0-s0:c0.c1023 root        7209    1       0 16:54 ?        00:00:00 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 7252 2636  0 16:57 pts/0 00:00:00 grep --color=auto httpd\|vsftpd

O contexto de segurança é esta parte:

 system_u:system_r:httpd_t:s0

O contexto de segurança possui quatro partes: usuário, função, domínio e sensibilidade. O usuário, a função e a sensibilidade funcionam exatamente como os mesmos contextos para os arquivos (explicados na seção anterior). O domínio é exclusivo para processos.

No exemplo acima, podemos ver que alguns processos estão em execução no domínio httpd_t, enquanto um está em execução no domínio ftpd_t.

Então, o que o domínio está fazendo pelos processos? Isso fornece ao processo um contexto para execução. É como uma bolha em torno do processo que a limita. Diz ao processo o que pode e o que não pode fazer. Esse confinamento garante que cada domínio do processo possa atuar apenas em certos tipos de arquivos e nada mais.

Usando esse modelo, mesmo que um processo seja invadido por outro usuário ou processo malicioso, o pior que pode fazer é danificar os arquivos aos quais ele tem acesso. Por exemplo, o daemon vsftp não terá acesso aos arquivos usados por, por exemplo, sendmail ou samba. Essa restrição é implementada no nível do kernel: é aplicada à medida que a política do SELinux é carregada na memória e, portanto, o controle de acesso se torna obrigatório.

Convenções de nomenclatura

Antes de prosseguirmos, aqui está uma observação sobre a convenção de nomenclatura do SELinux. Os usuários do SELinux possuem o sufixo "_u", as funções com o sufixo "_r" e os tipos (para arquivos) ou domínios (para processos) com o sufixo "_t".

Como os processos acessam recursos

Até agora, vimos que arquivos e processos podem ter contextos diferentes e que são restritos a seus próprios tipos ou domínios. Então, como um processo é executado? Para executar, um processo precisa acessar seus arquivos e executar algumas ações neles (abrir, ler, modificar ou executar). Também aprendemos que cada processo pode ter acesso apenas a certos tipos de recursos (arquivos, diretórios, portas, etc.).

O SELinux estipula essas regras de acesso em uma política. As regras de acesso seguem uma estrutura padrão de instrução allow:

 allow  : {  };

Já falamos sobre domínios e tipos. Classe define o que o recurso realmente representa (arquivo, diretório, link simbólico, dispositivo, portas, cursor etc.)

Aqui está o que essa declaração de permissão genérica significa:

• Se um processo é de determinado domínio
• E o objeto de recurso que está tentando acessar é de certa classe e tipo
• Então permita o acesso
• Senão negar acesso

Para ver como isso funciona, vamos considerar os contextos de segurança do daemon httpd em execução no nosso sistema:

 system_u:system_r:httpd_t:s0     7126 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     7127 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     7128 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     7129 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     7130 ?        00:00:00 httpd
system_u:system_r:httpd_t:s0     7131 ?        00:00:00 httpd

O diretório inicial padrão do servidor da web é /var/www/html. Vamos criar um arquivo nesse diretório e verificar seu contexto:

$ touch /var/www/html/index.html
$ ls -Z /var/www/html/*

O contexto do arquivo para o nosso conteúdo da web será httpd_sys_content_t :

 -rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html

Podemos usar o sesearch comando para verificar o tipo de acesso permitido para o daemon httpd:

$ sesearch --allow --source httpd_t --target httpd_sys_content_t --class file

Os sinalizadores usados com o comando são bastante auto-explicativos: o domínio de origem é httpd_t, o mesmo domínio em que o Apache está sendo executado. Estamos interessados nos recursos de destino que são arquivos e têm um contexto de tipo httpd_sys_content_t. Sua saída deve ficar assim:

 Found 4 semantic av rules:
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ;
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ;
   allow httpd_t httpd_content_type : file { ioctl read getattr lock open } ;
   allow httpd_t httpdcontent : file { ioctl read write create getattr setattr lock append unlink link rename execute open } ;

Observe a primeira linha:

 allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ;

Isso indica que o httpd daemon (o servidor Apache) possui controle de I/O, lê, obtém atributo, bloqueia e abre acesso a arquivos do tipo httpd_sys_content. Nesse caso, nosso index.html tem o mesmo tipo.

Indo um passo adiante, vamos primeiro modificar a página web (/var/www/html/index.html). Edite o arquivo para conter este conteúdo:

Em seguida, alteraremos a permissão do diretório /var/www/ e seu conteúdo, seguido por uma reinicialização do daemon httpd:

$ chmod -R 755 /var/www
$ service httpd restart

Em seguida, tentaremos acessá-la a partir de um navegador:

Nota
Dependendo de como o servidor estiver configurado, talvez seja necessário habilitar a porta 80 no firewall do IPTables para permitir o tráfego HTTP de entrada de fora do servidor. Não entraremos em detalhes sobre a ativação de portas no IPTables aqui. Existem outros artigos meus aqui no fórum que abordam sobre o assunto.

Por enquanto, tudo bem. O daemon httpd está autorizado a acessar um tipo específico de arquivo e podemos vê-lo ao acessar pelo navegador. Em seguida, vamos tornar as coisas um pouco diferentes, alterando o contexto do arquivo. Nós usaremos o comando chcon para isso. A –type sinalização para o comando permite especificar um novo tipo para o recurso de destino. Aqui, estamos alterando o tipo de arquivo para var_t.

$ chcon --type var_t /var/www/html/index.html

Podemos confirmar a alteração de tipo:

$ ls -Z /var/www/html/
 -rwxr-xr-x. root root unconfined_u:object_r:var_t:s0   index.html

Em seguida, quando tentamos acessar a página (ou seja, o daemon httpd tenta ler o arquivo), você pode receber um erro Forbidden ou a página genérica “Testing 123” do CentOS:

Então, o que está acontecendo aqui? Obviamente, agora algum acesso está sendo negado, mas de quem é esse acesso? No que diz respeito ao SELinux, o servidor está autorizado a acessar apenas certos tipos de arquivos e var_t não é um desses contextos. Como alteramos o contexto do arquivo index.html para var_t, o Apache não pode mais lê-lo e obtemos um erro.

Para fazer as coisas funcionarem novamente, vamos mudar o tipo de arquivo com o comando restorecon a opção -v mostra a alteração dos rótulos de contexto:

$ restorecon -v /var/www/html/index.html
 restorecon reset /var/www/html/index.html context unconfined_u:object_r:var_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0

Se tentarmos acessar a página agora, ele mostrará o texto "Esta é uma página de teste" novamente.

Este é um conceito importante para entender: garantir que arquivos e diretórios tenham o contexto correto é essencial para garantir que o SELinux esteja se comportando como deveria. Veremos um caso de uso prático no final desta seção, mas antes disso, vamos falar sobre mais algumas coisas.

Herança de contexto para arquivos e diretórios

O SELinux impõe algo que podemos chamar de "herança de contexto". O que isso significa é que, a menos que especificado pela política, processos e arquivos são criados com o contexto de seus pais.

Portanto, se tivermos um processo chamado “proc_a” gerando outro processo chamado “proc_b”, o processo gerado será executado no mesmo domínio que “proc_a”, a menos que especificado de outra forma pela política do SELinux.

Da mesma forma, se tivermos um diretório com o tipo "some_context_t", qualquer arquivo ou diretório criado nele terá o mesmo contexto de tipo, a menos que a política indique o contrário.

Para ilustrar isso, vamos verificar os contextos do diretório /var/www/:

$ ls -Z /var/www

O diretório html dentro de /var/www/ tem o contexto do tipo httpd_sys_content_t. Como vimos antes, o arquivo index.html dentro dele tem o mesmo contexto (ou seja, o contexto do pai):

 drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html 

Essa herança não é preservada quando os arquivos são copiados para outro local. Em uma operação de cópia, o arquivo ou diretório copiado assumirá o contexto de tipo do local de destino. No snippet de código abaixo, estamos copiando o arquivo index.html (com o contexto do tipo "httpd_sys_content_t") para o diretório /var:

$ cp /var/www/html/index.html /var/

Se verificarmos o contexto do arquivo copiado, veremos que ele mudou para var_t, o contexto de seu diretório pai atual:

$ ls -Z /var/index.html
 -rwxr-xr-x. root root unconfined_u:object_r:var_t:s0   /var/index.html

Essa mudança de contexto pode ser substituída pela --preserver=contexto cláusula no comando cp.

Quando arquivos ou diretórios são movidos, os contextos originais são preservados. No comando a seguir, estamos movendo o /var/index.html para o diretório /etc/:

$ mv /var/index.html /etc/ 

Quando verificamos o contexto do arquivo movido, vemos que o contexto var_t foi preservado no diretório /etc/:

$ ls -Z /etc/index.html 
 -rwxr-xr-x. root root unconfined_u:object_r:var_t:s0   /etc/index.html 

Então, por que estamos tão preocupados com os contextos dos arquivos? Por que esse conceito de copiar e mover é importante? Pense bem: talvez você tenha decidido copiar todos os arquivos HTML do servidor da web para um diretório separado na pasta raiz. Você fez isso para simplificar o processo de backup e também para aumentar a segurança: você não deseja que nenhum hacker adivinhe facilmente onde estão os arquivos do seu site. Você atualizou o controle de acesso do diretório, alterou o arquivo de configuração da web para apontar para o novo local, reiniciou o serviço, mas ainda não funciona. Talvez você possa ver os contextos do diretório e seus arquivos como a próxima etapa de solução de problemas. Vamos executá-lo como um exemplo prático.

SELinux em ação: testando um erro de contexto de arquivo

Primeiro, vamos criar um diretório nomeado www na raiz. Também criaremos uma pasta chamada html em www.

$ mkdir -p /www/html 

Se executarmos o comando ls -Z, veremos que esses diretórios foram criados com o contexto default_t :

$ ls -Z /www/
 drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 html

Em seguida, copiamos o conteúdo do diretório /var/www/html para /www/html:

$ cp /var/www/html/index.html /www/html/

O arquivo copiado terá um contexto de default_t. Esse é o contexto do diretório pai.

Agora, editamos o arquivo httpd.conf para apontar para esse novo diretório como a pasta raiz do site. Também teremos que modificar os direitos de acesso para este diretório.

$ vi /etc/httpd/conf/httpd.conf 

Primeiro comentamos o local existente para a raiz do documento e adicionamos uma nova diretiva DocumentRoot a /www/html:

 # DocumentRoot "/var/www/html"
DocumentRoot "/www/html" 

Também comentamos a seção de direitos de acesso para a raiz do documento existente e adicionamos uma nova seção:

#
#    AllowOverride None
    # Allow open access:
#    Require all granted
#


    AllowOverride None
    # Allow open access:
    Require all granted

Deixamos a localização do diretório cgi-bin como está. Não estamos entrando na configuração detalhada do Apache, aqui nós apenas queremos que nosso site funcione para fins do SELinux.

Por fim, reinicie o daemon httpd:

$ service httpd restart 

Depois que o servidor for reiniciado, o acesso à página da web nos dará o mesmo erro “403 Proibido” (ou a página padrão “Teste 123”) que vimos antes.

O erro está ocorrendo porque o contexto do arquivo index.html foi alterado durante a operação de cópia. Ele precisa ser alterado de volta ao seu contexto original (httpd_sys_content_t).

Mas como nós fazemos isso?

Alterando e restaurando contextos de arquivo SELinux

Em um exemplo de código anterior, vimos dois comandos para alterar o conteúdo do arquivo: chcon e restorecon. Usar chcon é uma medida temporária. Você pode usá-lo para alterar temporariamente os contextos de arquivo ou diretório para solucionar problemas de erros de negação de acesso. No entanto, esse método é apenas temporário: um sistema de arquivos chamado novamente ou executando o comando restorecon reverterá o arquivo para seu contexto original.

Além disso, a execução chcon requer que você conheça o contexto correto para o arquivo; o sinalizador --type especifica o contexto para o destino. restorecon não precisa disso especificado. Se você executar restorecon, o arquivo terá o contexto correto reaplicado e as alterações serão permanentes.

Mas se você não conhece o contexto correto do arquivo, como o sistema sabe qual contexto aplicar quando é executado restorecon?

Convenientemente, o SELinux "lembra" o contexto de cada arquivo ou diretório no servidor. No CentOS 7, os contextos dos arquivos já existentes no sistema são listados no arquivo /etc/selinux/targeted/contexts/files/file_contexts. É um arquivo grande e lista todos os tipos de arquivos associados a todos os aplicativos suportados pela distribuição Linux. Contextos de novos diretórios e arquivos são registrados no arquivo /etc/selinux/targeted/contexts/files/file_contexts.local. Portanto, quando executamos o comando restorecon, o SELinux pesquisará o contexto correto de um desses dois arquivos e o aplicará ao destino.

O trecho de código abaixo mostra uma extração de um dos arquivos:

$ cat /etc/selinux/targeted/contexts/files/file_contexts 
...
/usr/(.*/)?lib(/.*)?    system_u:object_r:lib_t:s0
/opt/(.*/)?man(/.*)?    system_u:object_r:man_t:s0
/dev/(misc/)?agpgart    -c      system_u:object_r:agp_device_t:s0
/usr/(.*/)?sbin(/.*)?   system_u:object_r:bin_t:s0
/opt/(.*/)?sbin(/.*)?   system_u:object_r:bin_t:s0
/etc/(open)?afs(/.*)?   system_u:object_r:afs_config_t:s0
...

Para alterar permanentemente o contexto do nosso arquivo index.html /www/html, precisamos seguir um processo de duas etapas.

• Primeiro, executamos o comando semanage fcontext. Isso gravará o novo contexto no arquivo /etc/selinux/targeted/contexts/files/file_contexts.local. Mas não irá rotular novamente o arquivo. Faremos isso nos dois diretórios.

$ semanage fcontext --add --type httpd_sys_content_t "/www(/.*)?"
$ semanage fcontext --add --type httpd_sys_content_t "/www/html(/.*)?"

Para garantir, podemos verificar o banco de dados de contexto do arquivo (observe que estamos usando o arquivo file_contexts.local):

$ cat /etc/selinux/targeted/contexts/files/file_contexts.local

Você deve ver os contextos atualizados:

# This file is auto-generated by libsemanage
# Do not edit directly.
/www(/.*)?    system_u:object_r:httpd_sys_content_t:s0
/www/html(/.*)?    system_u:object_r:httpd_sys_content_t:s0

Em seguida, executaremos o comando restorecon. Isso irá rotular novamente o arquivo ou diretório com o que foi gravado na etapa anterior:

$ restorecon -Rv /www

Isso deve redefinir o contexto em três níveis: o diretório /www de nível superior , o diretório /www/html abaixo dele e o arquivo index.html em /www/html:

restorecon reset /www context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
restorecon reset /www/html context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
restorecon reset /www/html/index.html context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0

Se agora tentarmos acessar a página da web, ela deverá funcionar.

Existe uma ferramenta bacana chamada matchpathcon que pode ajudar a solucionar problemas relacionados ao contexto. Este comando examinará o contexto atual de um recurso e o comparará com o listado no banco de dados de contexto do SELinux. Se diferente, sugerirá a alteração necessária. Vamos testar isso com o arquivo /www/html/index.html,Usaremos -V fleg que verifica o contexto:

$ matchpathcon -V /www/html/index.html

A saída matchpathcon deve mostrar que o contexto é verificado.

 /www/html/index.html verified.

Para um arquivo rotulado incorretamente, a mensagem dirá qual deve ser o contexto:

/www/html/index.html has context unconfined_u:object_r:default_t:s0, should be system_u:object_r:httpd_sys_content_t:s0 

Transição de Domínio

Até agora, vimos como os processos acessam os recursos do sistema de arquivos. Agora veremos como os processos acessam outros processos.

Transição de domínio é o método em que um processo altera seu contexto de um domínio para outro. Para entendê-lo, digamos que você tenha um processo chamado proc_a em execução dentro de um contexto de contextta_t. Com a transição do domínio, proc_a pode executar um aplicativo (um programa ou um script executável) chamado app_x que geraria outro processo. Esse novo processo pode ser chamado proc_b e pode estar em execução no domínio contextb_t. Tão efetivamente, contextta_t está fazendo a transição para contextb_t através do app_x. O executável app_x está funcionando como um ponto de entrada para contextb_t.

O caso de transição de domínio é bastante comum no SELinux. Vamos considerar o processo vsftpd em execução no nosso servidor. Se não estiver em execução, podemos executar o comando systemctl start vsftpd para iniciar o daemon.

A seguir, consideramos o processo systemd. Este é o ancestral de todos os processos. Essa é a substituição do processo de inicialização do System V e é executada dentro de um contexto de init_t. :

$ ps -eZ  | grep init
 system_u:system_r:init_t:s0         1 ?        00:00:02 systemd
system_u:system_r:mdadm_t:s0      773 ?        00:00:00 iprinit 

O processo em execução no domínio init_t é de curta duração: invocará o executável binário /usr/sbin/vsftpd, que possui um contexto de tipo ftpd_exec_t . Quando o executável binário é iniciado, ele se torna o daemon vsftpd e é executado no domínio ftpd_t.

Podemos verificar os contextos de domínio dos arquivos e processos:

$ ls -Z /usr/sbin/vsftpd

Saída:

-rwxr-xr-x. root root system_u:object_r:ftpd_exec_t:s0 /usr/sbin/vsftpd

Verificando o processo:

$ ps -eZ | grep vsftpd

Saída:

system_u:system_r:ftpd_t:s0-s0:c0.c1023 7708 ? 00:00:00 vsftpd

Portanto, aqui o processo em execução no domínio init_t está executando um arquivo binário com o tipo ftpd_exec_t. Esse arquivo inicia um daemon no domínio ftpd_t.

Essa transição não é algo que o aplicativo ou o usuário possa controlar. Isso foi estipulado na política do SELinux que é carregada na memória quando o sistema é inicializado. Em um servidor que não seja o SELinux, o usuário pode iniciar um processo alternando para uma conta mais poderosa (desde que tenha o direito de fazê-lo). No SELinux, esse acesso é controlado por políticas pré-escritas. E esse é outro motivo pelo qual o SELinux implementa o Controle de Acesso Obrigatório.

A transição de domínio está sujeita a três regras estritas:

• O processo pai do domínio de origem deve ter a permissão de execução do aplicativo entre os dois domínios (este é o ponto de entrada).
• O contexto do arquivo para o aplicativo deve ser identificado como um ponto de entrada para o domínio de destino.
• O domínio original deve ter permissão para fazer a transição para o domínio de destino.

Tomando o exemplo do daemon vsftpd acima, vamos executar o comando sesearch com diferentes opções para verificar se o daemon está em conformidade com essas três regras.

Primeiro, o domínio de origem init_t precisa ter permissão de execução no aplicativo de ponto de entrada com o contexto ftpd_exec_t. Portanto, se executarmos o seguinte comando:

$sesearch -s init_t -t ftpd_exec_t -c file -p execute -Ad 

O resultado mostra que os processos no domínio init_t podem ler, obter atributos, executar e abrir arquivos do contexto ftpd_exec_t:

 Found 1 semantic av rules:
   allow init_t ftpd_exec_t : file { read getattr execute open } ; 

Em seguida, verificamos se o arquivo binário é o ponto de entrada para o domínio de destino ftpd_t:

$ sesearch -s ftpd_t -t ftpd_exec_t -c file -p entrypoint -Ad

E de fato é:

 Found 1 semantic av rules:
   allow ftpd_t ftpd_exec_t : file { ioctl read getattr lock execute execute_no_trans entrypoint open } ; 

E, finalmente, o domínio de origem init_t precisa ter permissão para fazer a transição para o domínio de destino ftpd_t:

$ sesearch -s init_t -t ftpd_t -c process -p transition -Ad

Como podemos ver abaixo, o domínio de origem tem essa permissão:

Found 1 semantic av rules:
   allow init_t ftpd_t : process transition ;

Domínios não confinados

Quando introduzimos o conceito de domínios, o comparamos a uma bolha hipotética em torno do processo: algo que estipula o que o processo pode ou não fazer. É isso que limita o processo.

O SELinux também possui processos que são executados em domínios não confinados. Como você pode imaginar, processos não confinados teriam todos os tipos de acesso no sistema. Mesmo assim, esse acesso completo não é arbitrário: o acesso total também é especificado na política do SELinux.

O exemplo de um domínio de processo não confinado seria unconfined_t. Esse é o mesmo domínio que os usuários conectados executam seus processos por padrão. Falaremos sobre usuários e seus acessos para processar domínios nas seções subsequentes.

Conclusão

Cobrimos alguns conceitos muito importantes do SELinux. O gerenciamento de contexto de arquivo e processo está no centro de uma implementação bem-sucedida do SELinux. Como veremos na próxima e última parte desta série, há outra peça do quebra-cabeça restante: o usuário do SELinux.

Até a próxima e ultima parte do artigo.

Comentários

  • Chico, seu tutorial ficou muito bom, excelente! Tenho certeza que servirá como uma documentação do Selinux! Eu como leiga no assunto.. entendi como é a aplicação em processos e arquivos.