Las complejidades de monitorear los procesos en ejecución en Linux

Todos saben cómo monitorear los procesos en ejecución en un sistema Linux. Pero casi nadie logra una alta precisión en tales observaciones. De hecho, a todos los métodos de seguimiento de los procesos que se analizarán en este material les falta algo. Antes de comenzar a experimentar, definamos los requisitos para un sistema de monitoreo de procesos:











  1. Se debe registrar información sobre todos los procesos, incluso sobre los de corta duración.
  2. Deberíamos tener información sobre la ruta completa al archivo ejecutable para todos los procesos en ejecución.
  3. Nosotros, dentro de lo razonable, no deberíamos necesitar modificar o recompilar nuestro código para diferentes versiones del kernel.
  4. : - Kubernetes Docker, , / . cgroup ID . , , «» « ». , « », « », « », API, Docker . ID , . Docker .


Hablemos de las API de Linux comunes que pueden ayudar con esta tarea. Para no complicar la historia, prestaremos especial atención a los procesos creados mediante llamadas al sistema execve. Si hablamos de una solución más completa del problema, entonces durante su implementación es necesario, además, monitorear los procesos creados mediante llamadas al sistema fork/cloney sus variantes, así como los resultados de las llamadas execveat.



Soluciones sencillas implementadas en modo usuario



  1. Contactando /proc. Este método, debido al problema de los procesos de corta duración, no es especialmente adecuado para nosotros.
  2. netlink. netlink , PID . . /proc, .
  3. Linux. — , . API . . . — , , , . , API , auditd osquery. , , auditd go-audit, en teoría, puede mitigar este problema. Pero en el caso de las soluciones de clase empresarial, no puede saber de antemano si los clientes utilizan dichas herramientas y, si lo hacen, cuáles. Tampoco es posible saber de antemano qué controles de seguridad que funcionan directamente con la API de auditoría están siendo utilizados por los clientes. El segundo inconveniente es que las API de auditoría no saben nada sobre contenedores. Y esto a pesar de que este tema se ha debatido durante muchos años.


Herramientas de depuración sencillas en modo kernel



La implementación de estos mecanismos implica el uso de "sondas" de varios tipos en una sola copia.



▍Puntos de seguimiento



Usando puntos de rastreo ( tracepoint). Los puntos de seguimiento son sensores que se conectan estáticamente a ubicaciones específicas en el kernel durante la compilación. Cada uno de estos sensores se puede activar independientemente de los demás, como resultado de lo cual emitirá notificaciones en los casos en que se alcance el lugar del código del kernel donde está incrustado. El kernel contiene varios puntos de seguimiento adecuados para nosotros, cuyo código se ejecuta en varios puntos de la llamada al sistema execve. Esta - sched_process_exec, open_exec, sys_enter_execve, sys_exit_execve. Para obtener esta lista, ejecuté el comandocat /sys/kernel/tracing/available_events | grep execy filtró la lista resultante utilizando la información obtenida de la lectura del código del kernel. Estos puntos de rastreo nos convienen mejor que los mecanismos descritos anteriormente, ya que nos permiten organizar la observación de procesos de corta duración. Pero ninguno de ellos proporciona información sobre la ruta completa al archivo ejecutable del proceso, si los parámetros execson la ruta relativa a dicho archivo. En otras palabras, si el usuario ejecuta un comando como cd /bin && ./ls, entonces obtenemos la información de la ruta en el formulario ./ls, no en el formulario /bin/ls. He aquí un ejemplo sencillo:



#    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



Los sensores le kprobepermiten extraer información de depuración desde casi cualquier lugar del kernel. Son como puntos de interrupción especiales en el código del kernel que brindan información sin detener la ejecución del código. Un sensor kprobe, a diferencia de los trackpoints, se puede conectar a una amplia variedad de funciones. El código de dicho sensor se activará durante la ejecución de una llamada al sistema execve. Pero no encontré en el gráfico de llamadas de execveninguna función cuyos parámetros sean tanto el PIDproceso como la ruta completa a su archivo ejecutable. Como resultado, nos enfrentamos al mismo "problema de ruta relativa" que cuando usamos puntos de rastreo. Aquí puede, confiando en las características de un kernel en particular, algo para "modificar". Después de todo, los sensoreskprobepuede leer datos de la pila de llamadas del kernel. Pero tal solución no funcionará de manera estable en diferentes versiones del kernel. Por tanto, no lo considero.



▍Uso de programas eBPF con puntos de rastreo, con sondas kprobe y kretprobe



Aquí estamos hablando del hecho de que cuando se ejecuta algún código, se activarán puntos de rastreo o sensores, pero se ejecutará el código de los programas eBPF y no el código de los controladores de eventos ordinarios.



El uso de este enfoque nos abre nuevas posibilidades. Ahora podemos ejecutar código arbitrario en el kernel cuando hacemos una llamada al sistema execve. Esto, en teoría, debería darnos la capacidad de extraer cualquier información que necesitemos del kernel y enviarla al espacio de usuario. Hay dos formas de obtener este tipo de datos, pero ninguna cumple con los requisitos anteriores.



  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. Utilizando AppArmor. Puede escribir un perfil de AppArmor para evitar que los procesos llamen a archivos ejecutables. Si usa este perfil en el modo de entrenamiento (queja), AppArmor no prohibirá la ejecución de procesos, sino que solo emitirá notificaciones sobre violaciones de las reglas especificadas en el perfil. Si conecta un perfil a cada proceso en ejecución, obtenemos una solución que funciona, pero muy poco atractiva y demasiado "pirateada". Probablemente no valga la pena utilizar este enfoque.


Otras soluciones



Diré de inmediato que ninguna de estas soluciones cumple con nuestros requisitos, pero, sin embargo, las enumeraré:



  1. Usando la utilidad ps. Esta herramienta simplemente se refiere /procy, como resultado, sufre los mismos problemas que el acceso directo a /proc.
  2. execsnoop, eBPF. , , , kprobe/kretprobe, , , . , execsnoop , , , .
  3. execsnoop, eBPF. — kprobe, .




En el futuro, será posible utilizar la función eBPF auxiliar aún no disponible get_fd_path . Después de agregarlo al kernel, será útil para resolver nuestro problema. Es cierto que la ruta completa al archivo ejecutable del proceso deberá obtenerse utilizando un método que no permita leer información de las estructuras de datos del kernel.



Salir



Ninguna de las API que hemos revisado es perfecta. A continuación, quiero dar algunos consejos sobre qué enfoques usar para obtener información sobre los procesos y cuándo usarlos:



  1. auditd go-audit. , . , , , . , , , - API , , . — , .
  2. , , , , , execsnoop. — .
  3. , , , , , . , . , , eBPF- eBPF-, perf... Una historia sobre todo esto merece un artículo aparte. Lo más importante que debe recordar al elegir este método de monitoreo de procesos es lo siguiente. Si usa programas eBPF, verifique la posibilidad de su compilación estática, lo que le permitirá no depender de los encabezados del kernel. Pero es precisamente esta dependencia la que intentamos evitar con este método. El uso de este método también significa que no puede trabajar con estructuras de datos del kernel y no puede usar marcos como BCC que compilan programas eBPF en tiempo de ejecución.
  4. Si no está interesado en procesos de corta duración y las recomendaciones anteriores no le convienen, utilice las capacidades de netlink junto con /proc.


¿Cómo organiza la supervisión de los procesos en ejecución en Linux?










All Articles