As complexidades do monitoramento de processos em execução no Linux

Todo mundo sabe como monitorar processos em execução em um sistema Linux. Mas quase ninguém consegue alta precisão em tais observações. Na verdade, todos os métodos de monitoramento de processos que serão discutidos neste material estão faltando alguma coisa. Antes de começarmos a experimentar, vamos definir os requisitos para um sistema de monitoramento de processo:











  1. As informações sobre todos os processos, mesmo os de curta duração, devem ser registradas.
  2. Devemos ter informações sobre o caminho completo para o arquivo executável para todos os processos em execução.
  3. Nós, dentro do razoável, não devemos modificar ou recompilar nosso código para diferentes versões do kernel.
  4. : - Kubernetes Docker, , / . cgroup ID . , , «» « ». , « », « », « », API, Docker . ID , . Docker .


Vamos falar sobre APIs Linux comuns que podem ajudar nessa tarefa. Para não complicar a história, daremos atenção especial aos processos criados por meio de chamadas de sistema execve. Se falamos de uma solução mais completa do problema, então durante a sua implementação é necessário, além disso, monitorar os processos criados por meio de chamadas de sistema fork/clonee suas variantes, bem como os resultados das chamadas execveat.



Soluções simples implementadas em modo de usuário



  1. Entrando em contato /proc. Este método, devido ao problema de processos de curta duração, não é particularmente adequado para nós.
  2. netlink. netlink , PID . . /proc, .
  3. Linux. — , . API . . . — , , , . , API , auditd osquery. , , auditd go-audit, em tese, pode amenizar esse problema. Mas, no caso de soluções de classe empresarial, você não pode saber com antecedência se os clientes estão usando essas ferramentas e, se usam, quais delas. Também não é possível saber com antecedência quais controles de segurança que funcionam diretamente com a API de auditoria estão sendo usados ​​pelos clientes. A segunda desvantagem é que as APIs de auditoria não sabem nada sobre contêineres. E isso apesar de esse assunto ser discutido há muitos anos.


Ferramentas de depuração de modo kernel simples



A implementação desses mecanismos envolve o uso de "probes" de vários tipos em uma única cópia.



▍Tracepoints



Usando tracepoints ( tracepoint). Os pontos de rastreamento são sensores que são conectados estaticamente em locais específicos no kernel durante a compilação. Cada um desses sensores pode ser ativado independentemente dos outros, como resultado, ele emitirá notificações nos casos em que o local do código do kernel é alcançado onde ele está embutido. O kernel contém vários pontos de rastreio adequados para nós, cujo código é executado em vários pontos da operação da chamada do sistema execve. Este - sched_process_exec, open_exec, sys_enter_execve, sys_exit_execve. Para obter esta lista, executei o comandocat /sys/kernel/tracing/available_events | grep exece filtrou a lista resultante usando as informações obtidas na leitura do código do kernel. Esses tracepoints nos adaptam melhor do que os mecanismos descritos acima, uma vez que nos permitem organizar a observação de processos de curta duração. Mas nenhum deles fornece informações sobre o caminho completo para o arquivo executável do processo, caso os parâmetros execsejam o caminho relativo para esse arquivo. Em outras palavras, se o usuário executa um comando como cd /bin && ./ls, então obtemos as informações do caminho no formulário ./ls, não no formulário /bin/ls. Aqui está um exemplo simples:



#    the sched_process_exec
sudo -s
cd /sys/kernel/debug/tracing
echo 1 > events/sched/sched_process_exec/enable

#  ls    
cd /bin && ./ls

#      sched_process_exec
#    ,        
cd -
cat trace | grep ls

#   
echo 0 > events/sched/sched_process_exec/enable


▍ Sensores Kprobe / kretprobe



Os sensores kprobepermitem que você extraia informações de depuração de quase qualquer lugar no kernel. Eles são como pontos de interrupção especiais no código do kernel que fornecem informações sem interromper a execução do código. Um sensor kprobe, ao contrário dos trackpoints, pode ser conectado a uma ampla variedade de funções. O código de tal sensor será acionado durante a execução de uma chamada de sistema execve. Mas eu não encontrei no gráfico de chamadas de execvenenhuma função cujos parâmetros são o PIDprocesso e o caminho completo para seu arquivo executável. Como resultado, nos deparamos com o mesmo "problema de caminho relativo" de quando usamos tracepoints. Aqui você pode, dependendo das peculiaridades de um kernel específico, "ajustar" algo. Afinal, sensoreskprobepode ler dados da pilha de chamadas do kernel. Mas tal solução não funcionará de forma estável em diferentes versões do kernel. Portanto, eu não considero isso.



▍ Usando programas eBPF com pontos de rastreamento, com sondas kprobe e kretprobe



Aqui estamos falando sobre o fato de que quando algum código é executado, tracepoints ou sensores serão acionados, mas o código de programas eBPF será executado, e não o código de tratadores de eventos comuns.



Usar essa abordagem abre algumas novas possibilidades para nós. Agora podemos executar um código arbitrário no kernel ao fazer uma chamada de sistema execve. Isso, em teoria, deve nos dar a capacidade de extrair qualquer informação necessária do kernel e enviá-la para o espaço do usuário. Existem duas maneiras de obter esse tipo de dados, mas nenhuma delas atende aos requisitos acima.



  1. , task_struct linux_binprm. , , . , sched_process_exec , eBPF- , dentry bprm->file->f_path.dentry, . eBPF- . . , eBPF- , , , .
  2. eBPF . , . — API. — . (, eBPF, cgroup ID, ).


«»



  1. LD_PRELOAD exec libc. , . , , , , .
  2. execve, fork/clone chdir , . , execve execve . — eBPF- eBPF- , .
  3. , ptrace. -. — ptrace seccomp SECCOMP_RET_TRACE. seccomp execve , execve seccomp execve.
  4. Usando o AppArmor. Você pode escrever um perfil do AppArmor para evitar que os processos chamem arquivos executáveis. Se você usar este perfil no modo de treinamento (reclamar), o AppArmor não proibirá a execução de processos, mas apenas emitirá notificações sobre violações das regras especificadas no perfil. Se conectarmos um perfil a cada processo em execução, teremos uma solução funcional, mas muito pouco atraente e muito "hackeada". Provavelmente não vale a pena usar essa abordagem.


Outras soluções



Direi imediatamente que nenhuma dessas soluções atende aos nossos requisitos, mas, mesmo assim, vou listá-las:



  1. Usando o utilitário ps. Essa ferramenta simplesmente aborda /proce, como resultado, sofre os mesmos problemas que direcionar para /proc.
  2. execsnoop, eBPF. , , , kprobe/kretprobe, , , . , execsnoop , , , .
  3. execsnoop, eBPF. — kprobe, .




No futuro, será possível usar a função eBPF auxiliar get_fd_path, que ainda não está disponível . Depois de adicionado ao kernel, será útil para resolver nosso problema. É verdade que o caminho completo para o arquivo executável do processo deverá ser obtido por meio de um método que não forneça informações de leitura das estruturas de dados do kernel.



Resultado



Nenhuma das APIs que analisamos é perfeita. Abaixo, desejo fornecer algumas diretrizes sobre quais abordagens usar para obter informações sobre os processos e quando usá-los:



  1. auditd go-audit. , . , , , . , , , - API , , . — , .
  2. , , , , , execsnoop. — .
  3. , , , , , . , . , , eBPF- eBPF-, perf... Uma história sobre tudo isso merece um artigo separado. A coisa mais importante a lembrar ao escolher este método de monitoramento de processos é o seguinte. Se você usa programas eBPF, verifique a possibilidade de sua compilação estática, o que permitirá que você não dependa dos cabeçalhos do kernel. Mas é precisamente essa dependência que estamos tentando evitar usando este método. Usar este método também significa que você não pode trabalhar com estruturas de dados do kernel e que não pode usar estruturas como BCC que compilam programas eBPF em tempo de execução.
  4. Se você não está interessado em processos de curta duração e as recomendações anteriores não são adequadas para você, use as possibilidades do netlink junto com /proc.


Como você organiza o monitoramento dos processos em execução no Linux?










All Articles