Como evitar que um processo grave no diário do systemd?

4

Estou usando um aplicativo .NET Core de terceiros (uma distribuição binária usada por uma extensão VS Code) que infelizmente tem o log de diagnóstico ativado sem nenhuma maneira aparente de desativá-lo (eu já relatei isso para os autores). A solução ideal (além de poder desativá-lo) seria se eu pudesse especificar para systemd que ele não deveria registrar nada para esse programa em particular, mas não consegui encontrar uma maneira de fazer isso. Aqui está tudo que eu tentei até agora:

A primeira coisa que tentei foi redirecionar stdout e stderr para /dev/null : dotnet-app > /dev/null 2>&1 . Isso de fato desativou qualquer saída normal, mas o registro de diagnóstico ainda estava sendo gravado no diário do systemd.

Eu esperava que o aplicativo tivesse um argumento de linha de comando que me permitisse desabilitar o log de diagnóstico. Ele tinha um argumento de verbosidade, mas depois de experimentar, parecia apenas ter efeito na saída normal, não no registro de diagnóstico.

Usando strace e procurando chamadas para connect , descobri que o aplicativo escreveu o log de diagnóstico diretamente para /dev/log .

O caminho /dev/log é um link simbólico para /run/systemd/journal/dev-log , então, para verificar minha descoberta, alterei o link simbólico para apontar para /dev/null . Isso realmente impediu que o log de diagnóstico aparecesse no diário do systemd.

Fui informado sobre LD_PRELOAD e fiz uma biblioteca que substituiu o padrão connect por minha própria versão que retornou um erro caso tentasse se conectar a /dev/log . Isso funcionou corretamente no meu programa de teste, mas falhou com o aplicativo .NET Core, falhando com connect ENOENT /tmp/CoreFxPipe_1ddf2df2725f40a68990c92cb4d1ff1e . Eu experimentei a minha biblioteca, mas mesmo que tudo o que fizesse fosse passar diretamente os argumentos para a função connect padrão, ela ainda falharia com o mesmo erro.

Eu tentei usar namespaces do Linux para fazer com que /dev/log apontasse para /dev/null apenas para o aplicativo .NET Core: unshare --map-root-user --mount sh -c "mount --bind /dev/null /dev/log; dotnet-app $@" . Isso também falhou com o mesmo erro, embora tenha funcionado novamente para o meu programa de teste. Mesmo usando apenas unshare --map-root-user --mount dotnet-app "$@" falharia com o erro.

Em seguida, tentei usar gdb para fechar o descritor de arquivo para /dev/log enquanto o aplicativo estava em execução. Isso funcionou, mas reabre depois de algum tempo. Eu também tentei alterar o descritor de arquivo para apontar para /dev/null , que também funcionou, mas também foi redefinido para /dev/log depois de algum tempo.

Minha última tentativa foi escrever meu próprio soquete UNIX que filtraria todos os arquivos do aplicativo .NET Core. Isso realmente funcionou, mas aprendi que o PID é enviado junto com o que está escrito nos soquetes do UNIX, então tudo que é transmitido ao diário do systemd seria reportado vindo do PID do programa que faz o backup do meu soquete UNIX.

Por enquanto esta solução é aceitável para mim, porque no meu sistema quase nada usa /dev/log , mas gostaria de receber uma solução melhor. Por exemplo, eu li que era possível falsificar certas coisas como root para sockets UNIX , mas não consegui descobrir mais sobre isso.

Ou se alguém puder ter alguma ideia de por que ambos LD_PRELOAD e unshare podem falhar para o aplicativo .NET Core, enquanto eles funcionam bem para um programa de teste C simples que grava em /dev/log ?

    
por Matthijs Steen 14.11.2018 / 22:15

1 resposta

1

Em suma, sua biblioteca carregada por LD_PRELOAD substitui o syslog (3) em vez de se conectar (3 ).

O soquete /dev/log Unix é usado pela função glibc syslog (3), que se conecta a ele e grava nele. Ignorar connect (3) provavelmente não funciona porque a implementação do syslog (3) dentro da glibc executará a chamada de sistema connect (2) em vez da função de biblioteca, portanto, um gancho LD_PRELOAD não interceptará a chamada de dentro do syslog (3).

Há uma desconexão entre strace , que mostra o syscalls, e LD_PRELOAD , que pode substituir as funções da biblioteca (nesse caso, funções da glibc.) O fato de que há um connect(3) função glibc e também um connect (2) também ajuda nessa confusão. (É possível que usar ltrace teria ajudado aqui, mostrando chamadas para o syslog (3).)

Provavelmente você pode confirmar que a substituição da conexão (3) em LD_PRELOAD como você está fazendo não funcionará com o syslog (3) fazendo com que seu programa de teste chame syslog (3) diretamente, em vez de se conectar explicitamente a /dev/log , que eu suspeito é como o aplicativo .NET Core está se comportando.

Conectar-se ao syslog (3) também é potencialmente mais útil, porque estando em um nível mais alto na pilha, você pode usar esse gancho para tomar decisões como encaminhar seletivamente algumas das mensagens para o syslog . (Você pode carregar a função syslog da glibc com dlsym(RTLD_NEXT, "syslog") e, em seguida, você pode usar esse ponteiro de função para chamar syslog (3) para as mensagens que você deseja encaminhar do gancho.)

A abordagem de substituir /dev/log por um link simbólico para /dev/null está com defeito em que /dev/null não aceitará uma operação connect (2) (somente operações de arquivo como open (2)), portanto syslog (3) vai tentar se conectar e obter um erro e de alguma forma tentar manipulá-lo (ou talvez devolvê-lo ao chamador), em qualquer caso, isso pode ter efeitos colaterais.

Espero que o uso de uma substituição LD_PRELOAD do syslog (3) seja tudo o que você precisa aqui.

    
por 15.11.2018 / 04:32