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!