Atualmente, estou trabalhando em um projeto no qual tenho um processo pai que configura um socketpair, bifurca e usa esse socketpair para se comunicar. O filho, se quiser abrir um arquivo (ou qualquer outro recurso baseado em descritor de arquivo) deve sempre ir para o pai, solicitar o recurso e receber o fd
envio por meio do socketpair. Além disso, quero impedir que a criança abra qualquer descritor de arquivo por si só.
Eu tropecei sobre o setrlimit
que impede com êxito o filho de abrir novos descritores de arquivo, mas também parece invalidar quaisquer descritores de arquivo enviados pela conexão inicial do soquete. Existe algum método no Linux que permita que um único processo abra qualquer arquivo, envie seu descritor de arquivo para outros processos e permita que eles os usem sem permitir que esses outros processos abram qualquer descritor de arquivo por si mesmos?
Para o meu caso de uso, pode ser qualquer configuração do kernel, chamada do sistema etc., desde que possa ser aplicada após o fork e desde que seja aplicável a todos os descritores de arquivos (não apenas arquivos, mas também sockets, socketpairs, etc.).
fonte
Respostas:
O que você tem aqui é exatamente o caso de uso do seccomp .
Usando o seccomp, você pode filtrar os syscalls de maneiras diferentes. O que você quer fazer nesta situação é, logo depois
fork()
, instalar umseccomp
filtro que não permite o uso deopen(2)
,openat(2)
,socket(2)
(e mais). Para fazer isso, você pode fazer o seguinte:seccomp_init(3)
o comportamento padrão deSCMP_ACT_ALLOW
.seccomp_rule_add(3)
para cada syscall que você deseja negar. Você pode usarSCMP_ACT_KILL
para interromper o processo se tentar o syscall,SCMP_ACT_ERRNO(val)
fazer com que o syscall falhe ao retornar oerrno
valor especificado ou qualquer outroaction
valor definido na página do manual.seccomp_load(3)
para torná-lo eficaz.Antes de continuar, NOTE que uma abordagem de lista negra como esta é geralmente mais fraca que uma abordagem de lista de permissões. Ele permite qualquer syscall que não seja explicitamente proibido e pode resultar em um desvio do filtro . Se você acredita que o processo filho que você deseja executar pode estar tentando maliciosamente evitar o filtro, ou se você já sabe quais syscalls serão necessários pelos filhos, uma abordagem da lista de desbloqueio é melhor e você deve fazer o oposto do acima: crie um filtro com a ação padrão de
SCMP_ACT_KILL
e permita os syscalls necessários comSCMP_ACT_ALLOW
. Em termos de código, a diferença é mínima (a lista de permissões provavelmente é mais longa, mas as etapas são as mesmas).Aqui está um exemplo do exposto acima (estou fazendo
exit(-1)
em caso de erro apenas por uma questão de simplicidade):Agora, no seu programa, você pode chamar a função acima para aplicar o filtro seccomp logo após o
fork()
seguinte:Algumas notas importantes sobre o seccomp:
fork(2)
ouclone(2)
for permitido pelo filtro, qualquer processo filho será restringido pelo mesmo filtro.execve(2)
for permitido, o filtro existente será preservado em uma chamada paraexecve(2)
.prctl(2)
syscall for permitido, o processo poderá aplicar outros filtros.fonte
socket(2)
também pode criar umfd
, então isso também deve ser bloqueado. Se você conhece o processo filho, uma abordagem da lista de permissões é melhor.creat()
,dup()
edup2()
são todas as chamadas de sistema Linux que os descritores de arquivo retorno. Há uma série de maneiras em torno de uma lista negra ...