Por que nem todas as capacidades permitidas de um processo do Linux são efetivas o tempo todo?

4

man 7 capabilities documenta que os recursos de um processo em uma caixa linux recebem um conjunto de três máscaras:

  • permitido
  • efetivo
  • herdável

Eu tenho uma idéia de qual extensão a máscara herdável viria a desempenhar, mas não estou claro por que parece haver um caso de necessidade / uso para separar os recursos permitidos daqueles que são eficazes ?

Existe um caso em que alguns recursos permitidos não são eficazes? o que poderia apimentar uma resposta a esta pergunta?

Ronda de bónus

Dado o caso, alguns recursos não são eficazes e permitidos, o que impede que um processo os torne eficazes? Parece-me pelo menos que um processo de rouge não hesitaria em definir tudo o que é permitido como efetivo e, em geral, até mesmo tentar aumentar ainda mais os privilégios?

    
por humanityANDpeace 28.07.2016 / 17:41

2 respostas

3

Rápida hipotética onde poderia ser útil: Você deseja que um usuário possa copiar (ler) qualquer arquivo no sistema, mas não alterá-lo (gravar) para eles. Você poderia ter um programa que tenha CAP_DAC_OVERRIDE (para ignorar verificações de permissão) que funcione como cp . Mas para garantir que o usuário de backup não sobrescreva arquivos arbitrários, ele pode remover CAP_DAC_OVERRIDE do conjunto efetivo antes de abrir cada arquivo de saída.

Quanto à sua pergunta bônus: Nada impede que eles sejam revertidos para efetivo, se o código arbitrário puder ser executado. Mas pode ser útil no caso de outros compromissos (por exemplo, você convence o programa a tentar substituir um arquivo arbitrário via ataque de link simbólico).

    
por 28.07.2016 / 18:26
3

A diferença entre os recursos efetivos / permitidos é semelhante à diferença entre UIDs reais / efetivos em programas setuid. A idéia não é impedir que um aplicativo desonesto recrute privs (você não concederia privs em primeiro lugar, da mesma forma que você não os configuraria), mas permitir que um programa seja executado com privilégios mínimos e apenas escalar onde necessário . Isso ajuda a minimizar o impacto de bugs

Um exemplo muito artificial: Eu quero ter um programa que me permita enviar um SIGHUP para processos pertencentes ao usuário ou para permitir que um usuário God envie o SIGHUP para init .

Este programa tem o recurso CAP_KILL definido no arquivo.

O pseudo código pode ser parecido com:

drop_effective CAP_KILL
repeat forever:
  get_process_id_from user
  if process_id==1 and user_is_God:
    set_effective CAP_KILL
    kill(-1,1)
    drop_effective CAP_KILL
 else:
   kill(-1,process_id)

O erro óbvio, aqui, é que eu não verifico se o usuário está autorizado a enviar o sinal em primeiro lugar. Como deixei cair a permissão CAP_KILL efetiva, não permitirei que o usuário mate processos que não sejam os seus.

Muito artificial, com certeza! Mas a ideia é correr o máximo possível com "menos privilégios" e apenas ativar privilégios quando necessário.

Agora, isso não protege necessariamente contra ataques de estouro de buffer porque o código injetado pode permitir privilégios permitidos, portanto, o código com reconhecimento de capacidade também deve eliminar os privilégios permitidos quando não forem mais necessários; por exemplo, um servidor da Web pode soltar o CAP_NET_BIND_SERVICE depois de ter sido ligado à porta 80. Você não pode ativar algo que não esteja no seu conjunto permitido!

    
por 28.07.2016 / 18:34