O SELinux é configurado para negar por padrão, o que significa que todo acesso para o qual ele tem um hook no kernel precisa ser explicitamente permitido pela política. Isso significa que um arquivo de política é composto por uma grande quantidade de informações sobre regras, tipos, classes, permissões e muito mais. Uma consideração completa do SELinux está fora do escopo deste documento, mas entender como escrever regras de política agora é essencial ao ativar novos dispositivos Android. Já há muitas informações disponíveis sobre o SELinux. Consulte a documentação de suporte para recursos sugeridos.
Arquivos de chave
Para ativar o SELinux, integre o kernel mais recente do Android e incorpore os arquivos encontrados no diretório system/sepolicy. Quando compilados, esses arquivos compõem a política de segurança do kernel do SELinux e cobrem o sistema operacional Android upstream.
Em geral, não é recomendável modificar os arquivos system/sepolicy diretamente. Em vez disso, adicione ou edite seus próprios arquivos de política específicos do dispositivo no
/device/manufacturer/device-name/sepolicy
diretório. No Android 8.0 e mais recente, as mudanças feitas nesses arquivos só afetam a política no diretório do fornecedor. Para mais detalhes sobre a separação da
sepolicy pública no Android 8.0 e mais recente, consulte
Personalizar a SEPolicy no Android
8.0 e mais recente. Independentemente da versão do Android, você ainda está modificando estes arquivos:
Arquivos de política
Os arquivos que terminam com *.te são arquivos de origem da política do SELinux, que definem domínios e rótulos. Talvez seja necessário criar novos arquivos de política em
/device/manufacturer/device-name/sepolicy,
mas tente atualizar os arquivos atuais sempre que possível.
Arquivos de contexto
Os arquivos de contexto são onde você especifica rótulos para seus objetos.
file_contextsatribui rótulos a arquivos e é usado por vários componentes do espaço do usuário. Ao criar novas políticas, crie ou atualize esse arquivo para atribuir novos rótulos aos arquivos. Para aplicar novosfile_contexts, recrie a imagem do sistema de arquivos ou executerestoreconno arquivo a ser rotulado novamente. Em upgrades, as mudanças emfile_contextssão aplicadas automaticamente às partições do sistema e de dados do usuário como parte do upgrade. As mudanças também podem ser aplicadas automaticamente no upgrade a outras partições adicionando chamadasrestorecon_recursiveao arquivo init.board.rc depois que a partição for montada como leitura/gravação.genfs_contextsatribui rótulos a sistemas de arquivos, comoprocouvfatque não oferecem suporte a atributos estendidos. Essa configuração é carregada como parte da política do kernel, mas as mudanças podem não entrar em vigor para inodes no núcleo, exigindo uma reinicialização ou desmontagem e remontagem do sistema de arquivos para aplicar totalmente a mudança. Rótulos específicos também podem ser atribuídos a montagens específicas, comovfatusando a opçãocontext=mount.property_contextsatribui rótulos a propriedades do sistema Android para controlar quais processos podem defini-los. Essa configuração é lida peloinitprocesso durante a inicialização.service_contextsatribui rótulos aos serviços do binder do Android para controlar quais processos podem adicionar (registrar) e encontrar (pesquisar) uma referência do binder para o serviço. Essa configuração é lida peloservicemanagerprocesso durante a inicialização.seapp_contextsatribui rótulos a processos de apps e/data/datadiretórios. Essa configuração é lida pelozygoteprocesso em cada inicialização do app e porinstallddurante a inicialização.mac_permissions.xmlatribui uma tagseinfoaos apps com base na assinatura e, opcionalmente, no nome do pacote. A tagseinfopode ser usada como uma chave no arquivoseapp_contextspara atribuir um rótulo específico a todos os apps com essa tagseinfo. Essa configuração é lida porsystem_serverdurante a inicialização.keystore2_key_contextsatribui rótulos aos namespaces do Keystore 2. Esses namespaces são aplicados pelo daemonkeystore2. O Keystore sempre forneceu namespaces baseados em UID/AID. O Keystore 2 também aplica namespaces definidos pela sepolicy. Uma descrição detalhada do formato e das convenções desse arquivo pode ser encontrada aqui.
Makefile BoardConfig.mk
Depois de editar ou adicionar arquivos de política e contexto, atualize o
/device/manufacturer/device-name/BoardConfig.mk
Makefile para referenciar o sepolicy subdiretório e cada novo arquivo de política.
Para mais informações sobre as variáveis BOARD_SEPOLICY, consulte o arquivo
system/sepolicy/README.
BOARD_SEPOLICY_DIRS += \
<root>/device/manufacturer/device-name/sepolicy
BOARD_SEPOLICY_UNION += \
genfs_contexts \
file_contexts \
sepolicy.te
Após a recriação, o dispositivo é ativado com o SELinux. Agora você pode personalizar suas políticas do SELinux para acomodar suas próprias adições ao sistema operacional Android, conforme descrito em Personalização ou verificar a configuração atual, conforme abordado em Validação.
Quando os novos arquivos de política e as atualizações do BoardConfig.mk estiverem em vigor, as novas configurações de política serão incorporadas automaticamente ao arquivo de política do kernel final. Para mais informações sobre como a sepolicy é criada no dispositivo, consulte Como criar a sepolicy.
Implementação
Para começar a usar o SELinux:
- Ative o SELinux no kernel:
CONFIG_SECURITY_SELINUX=y - Mude o parâmetro kernel_cmdline ou bootconfig para que:
ouBOARD_KERNEL_CMDLINE := androidboot.selinux=permissive
Isso é apenas para o desenvolvimento inicial da política do dispositivo. Depois de ter uma política de bootstrap inicial, remova esse parâmetro para que o dispositivo seja aplicado ou falhe no CTS.BOARD_BOOTCONFIG := androidboot.selinux=permissive
- Inicialize o sistema no modo permissivo e veja quais negações são encontradas na inicialização:
No Ubuntu 14.04 ou mais recente: No Ubuntu 12.04:adb shell su -c dmesg | grep denied | audit2allow -p out/target/product/BOARD/root/sepolicy
adb pull /sys/fs/selinux/policy adb logcat -b all | audit2allow -p policy
- Avalie a saída para avisos semelhantes a
init: Warning! Service name needs a SELinux domain defined; please fix!Consulte Validação para instruções e ferramentas. - Identifique dispositivos e outros novos arquivos que precisam de rótulos.
- Use rótulos atuais ou novos para seus objetos. Consulte os arquivos
*_contextspara saber como as coisas foram rotuladas anteriormente e use o conhecimento dos significados dos rótulos para atribuir um novo. O ideal é que esse seja um rótulo atual que se encaixe na política, mas às vezes um novo rótulo é necessário, assim como regras de acesso a ele são necessárias. Adicione seus rótulos aos arquivos de contexto apropriados. - Identifique domínios/processos que precisam ter seus próprios domínios de segurança.
É provável que você precise escrever uma política completamente nova para cada um deles. Todos os
serviços gerados a partir de
init, por exemplo, precisam ter o próprio. Os comandos a seguir ajudam a revelar aqueles que permanecem em execução (mas TODOS serviços precisam desse tratamento):
adb shell su -c ps -Z | grep init
adb shell su -c dmesg | grep 'avc: '
- Analise
init.device.rcpara identificar domínios que não têm um tipo de domínio. Atribua um domínio no início do seu processo de desenvolvimento para evitar adicionar regras ainitou confundir os acessosinitcom aqueles que estão na própria política. - Configure
BOARD_CONFIG.mkpara usar variáveisBOARD_SEPOLICY_*. Consulte o README emsystem/sepolicypara detalhes sobre a configuração. - Examine o arquivo init.device.rc e fstab.device e
verifique se cada uso de
mountcorresponde a um sistema de arquivos rotulado corretamente ou se uma opçãocontext= mountestá especificada. - Analise cada negação e crie uma política do SELinux para processar cada uma delas corretamente. Consulte os exemplos em Personalização.
Comece com as políticas na AOSP e crie suas próprias personalizações. Para mais informações sobre a estratégia de política e uma análise mais detalhada de algumas dessas etapas, consulte Como escrever uma política do SELinux.
Casos de uso
Confira exemplos específicos de exploits a serem considerados ao criar seu próprio software e políticas do SELinux associadas:
Links simbólicos:como os links simbólicos aparecem como arquivos, eles são lidos com frequência como arquivos, o que pode levar a exploits. Por exemplo, alguns componentes privilegiados, como init, mudam as permissões de determinados arquivos, às vezes para serem excessivamente abertos.
Os invasores podem substituir esses arquivos por links simbólicos para o código que controlam, permitindo que o invasor substitua arquivos arbitrários. No entanto, se você souber que seu app nunca atravessa um link simbólico, poderá proibi-lo de fazer isso com o SELinux.
Arquivos do sistema:considere a classe de arquivos do sistema que só podem ser modificados pelo servidor do sistema. No entanto, como netd, init e vold são executados como raiz, eles podem acessar esses arquivos do sistema. Portanto, se netd for comprometido, ele poderá comprometer esses arquivos e, potencialmente, o próprio servidor do sistema.
Com o SELinux, é possível identificar esses arquivos como arquivos de dados do servidor do sistema.
Portanto, o único domínio que tem acesso de leitura/gravação a eles é o servidor do sistema.
Mesmo que netd seja comprometido, ele não poderá mudar de domínio para o domínio do servidor do sistema e acessar esses arquivos do sistema, embora seja executado como raiz.
Dados do app:outro exemplo é a classe de funções que precisam ser executadas como raiz, mas não podem acessar dados do app. Isso é incrivelmente útil, já que declarações abrangentes podem ser feitas, como determinados domínios não relacionados a dados de apps que são proibidos de acessar a Internet.
setattr:para comandos como chmod e chown, é possível identificar o conjunto de arquivos em que o domínio associado pode conduzir setattr. Qualquer coisa fora disso pode ser proibida dessas mudanças, mesmo pela raiz. Assim, um app pode executar chmod e chown nos arquivos rotulados como app_data_files, mas não shell_data_files ou system_data_files.