Configurar e trabalhar com SELinux (CentOS)

By | 15 de Fevereiro de 2016

O SELinux é uma importante camada de proteção para os servidores Linux. Infelizmente, é muito comum – e até corriqueiro – os administradores de servidores desabilitarem ele, sem saber o quão importante ele é para a segurança do sistema. Este artigo é um resumo de uma série que escrevi para o CSIRT Unicamp (links no final da página).

Introdução ao SELinux

Mesmo sendo conhecido por grande parte dos administradores de redes/sistemas, o uso mais comum consiste basicamente em “desabilitá-lo”. Por requerer um trabalho adicional, ou por não saber configurar o SELinux, ou por outros motivos, os administradores abrem mão de um importante aliado na proteção do servidor. Segundo estatísticas do CSIRT Unicamp, ao menos 70% dos problemas de Segurança em servidores web no ano de 2013 poderiam ter sido evitados se estivessem com SELinux ativo.

SELinux é a implantação do mecanismo de Segurança MAC (Mandatory Access Control) no kernel do Linux. Foi criado pela NSA (National Security Agency), e impõe regras em arquivos e processos em um sistema Linux.
A maioria dos sistemas utilizam DAC ( Discretionary Access Control) para prover segurança do sistema. De uma forma geral, DAC é um controle de acesso em que o usuário tem controle total dos arquivos que possui e executa. Uma vez definida estas permissões, não há nenhuma outra restrição para execução dos processos/arquivos. Isto pode ser um problema quando, por exemplo, o usuário (ou um processo iniciado pelo mesmo) não atribui a permissão adequada a um determinado arquivo, deixando-o exposto. Ou então quando um programa foge do seu comportamento “normal”. Vejamos um exemplo: O usuário apache está sendo utilizado para executar o software Apache. Durante sua execução, devido uma falha de programação no código da página, o processo recebe uma requisição para acessar o arquivo /etc/passwd. As permissões do arquivo são as seguintes:

# ls -l /etc/passwd
-rw-r–r– 1 root root 1760 Out 23 11:12 /etc/passwd

Segundo as permissões do arquivo /etc/passwd, todos podem ler o arquivo. Logo, o Apache poderá exibi-lo sem nenhum problema. Ainda neste exemplo, se a falha do código da página permitisse, seria possível o Apache salvar um arquivo em qualquer local que tiver permissão de escrita.
Mandatory Access Control (MAC), provido pelo SELinux, restringe o nível de controle que os usuários tem sobre os objetos que eles criam, e adiciona categorias e rótulos a todos os objetos do sistema de arquivos. Usuários e processos devem ter acesso adequado a estas categorias e rótulos para que então possam interagir com esses objetos. Quando corretamente implementado, MAC permite ao sistema defender-se adequadamente. A sua capacidade de limitar os privilégios associados a processos de execução limita o âmbito de dano potencial, que pode resultar da exploração de vulnerabilidades em aplicações e serviços do sistema.
Como aplicação do SELinux, o que se tem são rótulos contendo informações relevantes para a segurança de processos e arquivos. Essa informação é chamada de Contexto SELinux (SELinux context), e pode ser obtida utilizando a opção “-Z” no comando “ls”:

# ls -lZ /etc/passwd
-rw-r–r–. root root system_u:object_r:etc_t:s0 /etc/passwd

No arquivo acima temos o contexto do usuário (system_u), a regra (object_r), o tipo (etc_t) e o nível (s0). Estas informações são utilizadas para determinar o acesso do usuário ao arquivo. Agora, vamos voltar ao exemplo anterior, e considerar que neste sistema o SELinux está ativo. Verificaremos então o contexto do processo do Apache:

# ps axZ | grep httpd
unconfined_u:system_r:httpd_t:s0 6906 ? Ss 0:00 /usr/sbin/httpd

Logo, como o contexto do processo não coincide com o contexto do arquivo, o acesso ao mesmo será NEGADO, mesmo que nas permissões DAC o mesmo tenha permissão para tanto.

Modificando contextos

Conforme visto anteriormente, o SELinux tem seu funcionamento baseado em rótulos e em políticas de segurança. Os rótulos dos usuários, arquivos e processos definem o contexto de segurança de cada objeto. Colocando em uma aplicação prática, vejamos o exemplo a seguir:

# ls -Z /var/www/html/
-rw-r—–. root apache unconfined_u:object_r:user_home_t:s0 index.html

Em quase todos os casos, o campo do contexto que realmente importa é o terceiro campo; ele indica o tipo do objeto (neste caso, user_home_t indica que o tipo de arquivo é um arquivo de usuário “humano”). Considerando que este arquivo é uma página que será utilizada pelo Apache, conclui-se que ele não está com o contexto apropriado (que neste caso seria “httpd_sys_content_t”), logo não irá funcionar. Então, é necessário alterar o tipo de arquivo no contexto para que o mesmo funcione:

# chcon -R -t httpd_sys_content_t /var/www/html/

Assim como o chmod é utilizado para alterar permissões DAC, o chcon pode ser utilizado para alterar o contexto dos arquivos. Porém todas as alterações realizadas com o chcon são desfeitas quando o sistema é reiniciado. Para que a alteração seja permanente, deve-se utilizar o semanage:

# semanage fcontext -m -t httpd_sys_content_t /var/www/html/index.html

Alterar o contexto de arquivo por arquivo não parece ser muito produtivo. Por isso, você pode utilizar expressões regulares para alterar vários arquivos de uma vez só:

# semanage fcontext -m -t httpd_sys_content_t “/var/www/html(/.*)?”

Se o retorno que você tiver for o abaixo, basta você trocar o “-m” (modificar) pelo “-a” (adicionar) no comando:

usr/sbin/semanage: O contexto de arquivo para /var/www/html não está definido

# semanage fcontext -a -t httpd_sys_content_t “/var/www/html(/.*)?”

Após realizar as alterações com o semanage, é necessário utilizar o “restorecon” para aplicar as alterações:

# restorecon -Rv /var/www/html

Agora, o arquivo já está com o contexto que permitirá seu funcionamento:

# ls -Z /var/www/html/
-rwxr-x—. root apache unconfined_u:object_r:httpd_sys_content_t:s0 index.html

Políticas Booleanas

Além do contexto, o SELinux utiliza políticas pré-definidas para cada serviço para restringir/conceder acesso á determinadas funções. Você pode visualiza-las utilizando o comando abaixo:

# semanage boolean -l

Supondo que desejo que o home dos usuários seja acessível pelo apache (crio lá no home do usuário uma pasta public_html para o usuário acessar meusite.com/~usuario). Se não alterar nada, o SELinux irá bloquear o acesso. Então, listando as políticas, temos:

# semanage boolean -l | grep -E ‘httpd.*home’
httpd_enable_homedirs (desativado,desativado) Allow httpd to read home directories

Com isso, confirmamos que a esta opção está desativada. Vamos ativá-la então:

# setsebool -P httpd_enable_homedirs 1

Liberar Portas

O SELinux também provê controle sobre qual serviço pode acessar qual porta (para o desespero de alguns). A lista de portas/serviços liberados você pode obter com o comando abaixo:

# semanage port -l

Usando como exemplo um servidor apache, que quero que o mesmo funcione na porta 25000/TCP. Porém, nas políticas SELinux esta porta não está liberada:

# semanage port -l | grep http _port
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000

Então, vamos adicionar a porta 25000 á regra:

# semanage port -a -t http_port_t -p tcp 25000

Resolvendo problemas

    Muitas vezes, por diversas razões, não conseguimos impedir que o SELinux interfira no funcionamento adequado de determinados softwares. Para solucionar casos deste tipo, podemos utilizar o audit2allow para entender melhor o problema ou para criar módulos de políticas para SELinux.

O primeiro passo é verificar os logs em /var/log/audit,log, que terá registros semelhantes a esse:

type=AVC msg=audit(1455199601.283:181376): avc: denied { setattr } for pid=7489 comm=”mingetty” name=”tty6″ dev=devtmpfs ino=5354 scontext=system_u:system_r:getty_t:s0 tcontext=system_u:object_r:tmpfs_t:s0 tclass=chr_file
type=SYSCALL msg=audit(1455199601.283:181376): arch=c000003e syscall=92 success=no exit=-13 a0=7ffdf8b4b090 a1=0 a2=0 a3=7ffdf8b4acd0 items=0 ppid=1 pid=7489 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm=”mingetty” exe=”/sbin/mingetty” subj=system_u:system_r:getty_t:s0 key=(null)
type=AVC msg=audit(1455199606.148:181377): avc: denied { setattr } for pid=7490 comm=”mingetty” name=”tty2″ dev=devtmpfs ino=5350 scontext=system_u:system_r:getty_t:s0 tcontext=system_u:object_r:tmpfs_t:s0 tclass=chr_file

Neste exemplo, SELinux está bloqueando a função “setattr” para a aplicação “mingetty”. Iremos usar o audit2allow para criar um módulo de política SELinux para corrigir tal erros.

Para gerar um relatórios “humano” dos eventos do SELinux, você pode utilizar o comando abaixo:
# audit2allow -a

O comando acima irá analisar todos os registros contidos em /var/log/audit.log. Caso queira uma análise apenas para um erro específico, você pode usar o “grep” para filtrar os eventos:
# grep “mingetty” /var/log/audit.log | allow2audit -w

Para criar um modulo de política SELinux, utilze a opção “-M”:
# audit2allow -a -M meumodulo

Posso também utilizar o “grep”, como no exemplo anterior:
# grep “mingetty” /var/log/audit.log | allow2audit -M meumodulo

Ele irá criar um arquivo “.pp” e um .”te” no diretório corrente. Para instalar o módulo, você utilize o comando:
# semodule -i meumodulo.pp

Em seguinda, habilite o módulo:
# semodule -e meumodulo

Referências:

https://www.security.unicamp.br/54-selinux-um-importante-aliado-na-seguranca-de-servidores-linux-parte-1.html

https://www.security.unicamp.br/86-selinux-um-importante-aliado-na-seguranca-de-servidores-linux-parte-2.html

https://www.security.unicamp.br/103-selinux-um-importante-aliado-na-seguranca-de-servidores-linux-parte-3.html