El Berkeley Packet Filter (BPF) o Berkeley Filter puede ser de utilidad para todos los sistemas ope­ra­ti­vos similares a Unix como, por ejemplo, Linux. La principal tarea de esta “máquina virtual para fines es­pe­cia­le­sˮ de­sa­rro­lla­da en 1992 es filtrar los paquetes de datos de las redes e in­te­grar­los en el núcleo del sistema operativo. El BPF forma una interfaz de capas de seguridad de la unidad de datos o de los programas. Estas capas de seguridad tienen la función de ga­ra­n­ti­zar la tra­n­s­mi­sión fiable de paquetes de datos y regular el acceso a estos paquetes.

Si uno de estos paquetes de datos llega al de­s­ti­na­ta­rio, el BPF lee los datos de las capas de seguridad del paquete y busca errores. De este modo, el de­s­ti­na­ta­rio puede re­so­l­ve­r­los. Asimismo, permite comparar los datos con las de­fi­ni­cio­nes de los filtros y así aceptar o rechazar un paquete que no se considere pe­r­ti­ne­n­te. Esto puede ahorrar mucha capacidad de co­mpu­tación.

¿Cómo funciona el Berkeley Packet Filter?

Para realizar sus funciones, el Berkeley Packet Filter se integró como un in­té­r­pre­te de código máquina dentro de una máquina virtual. Como resultado, el BPF ejecuta unas in­s­tru­c­cio­nes en formato pre­de­fi­ni­do. Como in­té­r­pre­te, Berkeley Filter lee los archivos de origen, los analiza y ejecuta sus in­s­tru­c­cio­nes su­ce­si­va­me­n­te. Traduce las in­s­tru­c­cio­nes en código máquina para permitir la ejecución directa.

Berkeley Filter utiliza las llamadas al sistema (SysCalls), que son llamadas a funciones es­pe­cí­fi­cas del sistema, listas para ser uti­li­za­das, para hacer pe­ti­cio­nes al núcleo del sistema operativo, también llamado núcleo. Este se encarga de comprobar los derechos de acceso antes de confirmar o rechazar la solicitud. Entre las apro­xi­ma­da­me­n­te 330 SysCalls de Linux están las si­guie­n­tes:

  • read - Permiso de lectura, con el que se puede leer un archivo
  • write - Permiso de escritura, para escribir en un archivo
  • open - Permiso para abrir los archivos o di­s­po­si­ti­vos
  • close - Permiso para los archivos o di­s­po­si­ti­vos
  • stat - Se recupera el estado de un archivo

Como el BPF está en constante de­sa­rro­llo, hoy en día funciona como una máquina universal y virtual di­re­c­ta­me­n­te en el núcleo del sistema operativo, donde tiene lugar todo el pro­ce­sa­mie­n­to y la or­ga­ni­za­ción de los datos. Con muchas nuevas ca­ra­c­te­rí­s­ti­cas, el filtro se conoce como Extended BPF o por su abre­via­tu­ra eBPF. Con esto, puede ejecutar cualquier código in­te­r­me­dio (código de bytes) de forma segura y durante el tiempo de ejecución (co­m­pi­la­ción just in time) di­re­c­ta­me­n­te en el núcleo operativo. Extended BPF funciona en el núcleo operativo dentro de un entorno de pruebas y por lo tanto está protegido. Este entorno de pruebas, conocido también como sandbox o caja de arena, ayuda a minimizar el riesgo de que el sistema afecte ne­ga­ti­va­me­n­te a la lógica del núcleo operativo.

Nota

El Berkeley Filter puede funcionar tanto en modo núcleo (acceso máximo a los recursos de la máquina) como en modo usuario (acceso limitado a los recursos de la máquina).

Ventajas del Berkeley Filter

El eBPF permite filtrar los paquetes de datos para evitar que los datos irre­le­va­n­tes ra­le­n­ti­cen el re­n­di­mie­n­to de tu PC. Así, los registros de datos inu­ti­li­za­bles o de­fe­c­tuo­sos pueden ser re­cha­za­dos o reparados desde el principio. Además, Extended BPF pro­po­r­cio­na mayor seguridad gracias a las llamadas al sistema, ya que permite medir fá­ci­l­me­n­te el re­n­di­mie­n­to o realizar un se­gui­mie­n­to con las llamadas al sistema.

En 2007 la im­ple­me­n­ta­ción de BPF se amplió con las Zero Copy buffer ex­te­n­sio­ns. Estas ex­te­n­sio­nes permiten a los co­n­tro­la­do­res de los di­s­po­si­ti­vos guardar los paquetes de datos recibidos di­re­c­ta­me­n­te en el programa sin tener que copiar los datos primero.

Programar filtros con BPF

En el modo de usuario, se pueden definir filtros in­di­vi­dua­les para la interfaz de Berkeley Filter en cualquier momento. An­te­rio­r­me­n­te, los códigos co­rre­s­po­n­die­n­tes se escribían a mano y se traducían a un código de bytes BPF. Hoy en día, gracias al Co­m­pi­la­dor de Clang LLVM, los códigos de bytes se pueden compilar di­re­c­ta­me­n­te.

Las bi­blio­te­cas del núcleo operativo también contienen programas de ejemplo que si­m­pli­fi­can la de­fi­ni­ción de los programas de eBPF. Existen también varias funciones de ayuda que te fa­ci­li­ta­rán la tarea.

El ve­ri­fi­ca­dor de seguridad eBPF

La ejecución de llamadas al sistema en el núcleo siempre está asociada a algunos riesgos de seguridad y es­ta­bi­li­dad. Antes de que se cargue una llamada al sistema de eBPF, esta debe pasar una serie de co­m­pro­ba­cio­nes:

  1. En primer lugar, el sistema comprueba si la llamada del sistema ha terminado y no contiene bucles. Esto podría causar fallos en el núcleo. El gráfico de flujo de control del programa verifica que no haya in­s­tru­c­cio­nes inal­ca­n­za­bles que no se carguen po­s­te­rio­r­me­n­te.
  2. Antes y después de que se ejecute una in­s­tru­c­ción, se comprueba el estado de la llamada al sistema eBPF. Esto asegura que el Extended BPF solo opera en los rangos pe­r­mi­ti­dos y no accede a los datos fuera del entorno de pruebas. Para esto, no es necesario comprobar cada ruta in­di­vi­dua­l­me­n­te. No­r­ma­l­me­n­te basta con comprobar algunas de ellas.
  3. Por último, se configura también el tipo de SysCall. Este paso es im­po­r­ta­n­te para re­s­tri­n­gir qué funciones del núcleo se pueden llamar y a qué es­tru­c­tu­ras de datos se puede acceder desde SysCall. De este modo, puedes utilizar llamadas al sistema que acceden di­re­c­ta­me­n­te a paquetes de red.

Los tipos de SysCall tienen estas cuatro funciones apro­xi­ma­da­me­n­te: dónde se puede adjuntar el programa, a qué funciones de ayuda del núcleo se puede acceder, si se puede acceder di­re­c­ta­me­n­te a los datos de los paquetes de red o no, y qué tipo de objeto se pasa con prioridad en una llamada al sistema.

En la ac­tua­li­dad, los si­guie­n­tes tipos de SysCall de eBPF son co­m­pa­ti­bles con el núcleo:

  • BPF_PROG_TYPE_SOCKET_FILTER
  • BPF_PROG_TYPE_KPROBE
  • BPF_PROG_TYPE_SCHED_CLS
  • BPF_PROG_TYPE_SCHED_ACT
  • BPF_PROG_TYPE_TRA­CE­POI­NT
  • BPF_PROG_TYPE_XDP
  • BPF_PROG_TYPE_PERF_EVENT
  • BPF_PROG_TYPE_CGROUP_SKB
  • BPF_PROG_TYPE_CGROUP_SOCK
  • BPF_PROG_TYPE_LWT_ *
  • BPF_PROG_TYPE_SOCK_OPS
  • BPF_PROG_TYPE_SK_SKB
  • BPF_PROG_CGROUP_DEVICE
Ir al menú principal