Libseccomp: ERROR: no genere BPF para pseudo-syscalls

Creado en 15 jun. 2020  ·  20Comentarios  ·  Fuente: seccomp/libseccomp

Vea el número 249, específicamente este comentario :

¿Por qué comprobar si el syscall 4294957285 no existe en el bpf realmente generado?

No deberíamos, y no solíamos hacer eso, pero parece que libseccomp actual tiene un error aquí.

Gracias a @ vt-alt por informar de este error.

bug prioritmedium

Todos 20 comentarios

REPRODUCTOR ELIMINADO A FAVOR DEL BORRADOR MEJORADO A CONTINUACIÓN

Para ser claros, aún deberíamos emitir las pseudo-syscalls en el PFC, con fines de depuración, pero no deberíamos emitir una regla de filtro BPF (inútil).

Gracias por crear el problema a partir de mi informe.

Para ser claros, aún deberíamos emitir las pseudo-syscalls en el PFC, con fines de depuración, pero no deberíamos emitir una regla de filtro BPF (inútil).

Por favor reconsidere esto. Creo que esto solo complicará y oscurecerá las cosas si PFC no refleja BPF.

Por favor reconsidere esto. Creo que esto solo complicará y oscurecerá las cosas si PFC no refleja BPF.

Si falta la llamada al sistema en el PFC, recibiremos una serie de informes de errores falsos que hablan de cómo la biblioteca no puede agregar un filtro para las llamadas al sistema (inexistentes).

Para aquellos que entienden el concepto de las pseudo-llamadas al sistema, es un ejercicio trivial eliminarlas de la salida de PFC. También vale la pena mencionar que la salida PFC no pretende ser una copia exacta de la salida BPF, está ahí simplemente como una herramienta de depuración y una forma fácil de visualizar el código de filtro generado.

forma fácil de visualizar el código de filtro generado

Pero, entonces no visualizará el código de filtro _generado_ ya que en el código generado las pseudo llamadas al sistema deberían estar ausentes.

Si falta la llamada al sistema en el PFC, recibiremos una serie de informes de errores falsos que hablan de cómo la biblioteca no puede agregar un filtro para las llamadas al sistema (inexistentes).

Es mucho más fácil entender que las comprobaciones de pseudo syscall no deberían estar presentes en el código (como en 'optimizado hacia fuera', porque '' no hay tales llamadas al sistema para el arco '), que la diferencia lógica (presencia y ausencia de condicionales) en la visualización del código y el código real.

Preferiría que PFC refleje bpf que usar scmp_bpf_disasm ya que la salida de PFC es mucho más fácil de leer.

Entiendo su preocupación @ vt-alt, y tal vez en una versión futura lo hagamos con PFC, pero es mi opinión que eliminar las pseudo-syscalls de la salida de PFC es un error.

@drakenclimber , ¿tienes opiniones sólidas sobre esto?

Reproductor revisado para x86_64:

#include <stdlib.h>
#include <errno.h>

#include <seccomp.h>

#include "util.h"

int main(int argc, char *argv[])
{
        int rc;
        struct util_options opts;
        scmp_filter_ctx ctx = NULL;

        rc = util_getopt(argc, argv, &opts);
        if (rc < 0)
                goto out;

        ctx = seccomp_init(SCMP_ACT_KILL);
        if (ctx == NULL)
                return ENOMEM;

        rc = seccomp_arch_add(ctx, SCMP_ARCH_X32);
        if (rc < 0)
                goto out;

        rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(access), 0);
        if (rc < 0)
                goto out;
        rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(arm_fadvise64_64), 0);
        if (rc < 0)
                goto out;

        rc = util_filter_output(&opts, ctx);
        if (rc)
                goto out;

out:
        seccomp_release(ctx);
        return (rc < 0 ? -rc : rc);
}

ACTUALIZADO: solucionó un problema con TSKIP

Aún no se ha probado completamente, pero esto puede ser una solución: ¿puede verificar que esto sea razonable para el algoritmo de optimización de árbol equilibrado @drakenclimber?

diff --git a/src/arch-arm.c b/src/arch-arm.c
index 3465111..4dd4b63 100644
--- a/src/arch-arm.c
+++ b/src/arch-arm.c
@@ -54,7 +54,7 @@ int arm_syscall_resolve_name_munge(const char *name)
        if (sys == __NR_SCMP_ERROR)
                return sys;

-       return sys + __SCMP_NR_BASE;
+       return (sys | __SCMP_NR_BASE);
 }

 /**
@@ -68,7 +68,7 @@ int arm_syscall_resolve_name_munge(const char *name)
  */
 const char *arm_syscall_resolve_num_munge(int num)
 {
-       return arm_syscall_resolve_num(num - __SCMP_NR_BASE);
+       return arm_syscall_resolve_num(num & (~__SCMP_NR_BASE));
 }

 const struct arch_def arch_def_arm = {
diff --git a/src/arch-x32.c b/src/arch-x32.c
index 7b97fb3..3890968 100644
--- a/src/arch-x32.c
+++ b/src/arch-x32.c
@@ -43,7 +43,7 @@ int x32_syscall_resolve_name_munge(const char *name)
        if (sys == __NR_SCMP_ERROR)
                return sys;

-       return sys + X32_SYSCALL_BIT;
+       return (sys | X32_SYSCALL_BIT);
 }

 /**
@@ -57,7 +57,7 @@ int x32_syscall_resolve_name_munge(const char *name)
  */
 const char *x32_syscall_resolve_num_munge(int num)
 {
-       return x32_syscall_resolve_num(num - X32_SYSCALL_BIT);
+       return x32_syscall_resolve_num(num & (~X32_SYSCALL_BIT));
 }

 const struct arch_def arch_def_x32 = {
diff --git a/src/gen_bpf.c b/src/gen_bpf.c
index 55a7958..ae9c3f4 100644
--- a/src/gen_bpf.c
+++ b/src/gen_bpf.c
@@ -1555,6 +1555,10 @@ static int _gen_bpf_syscalls(struct bpf_state *state,
        for (s_iter = s_tail; s_iter != NULL; s_iter = s_iter->pri_prv) {
                if (!s_iter->valid)
                        continue;
+               /* skip pseudo-syscalls */
+               if ((s_iter->num & 0x80000000) &&
+                   (state->attr->api_tskip == 0 || s_iter->num != -1))
+                       continue;

                if (*bintree_levels > 0 &&
                    ((syscall_cnt + empty_cnt) % SYSCALLS_PER_NODE) == 0)

Entiendo su preocupación @ vt-alt, y tal vez en una versión futura lo hagamos con PFC, pero es mi opinión que eliminar las pseudo-syscalls de la salida de PFC es un error.

@drakenclimber , ¿tienes opiniones sólidas sobre esto?

Realmente no, pero creo que la raíz del problema es que la salida de PFC se está utilizando de múltiples formas divergentes:

  1. Como se mencionó anteriormente, es una manera fácil para que los usuarios nuevos (más) verifiquen aproximadamente su filtro
  2. Los usuarios más avanzados esperan que sea una aproximación cercana al filtro BPF real

¿Quizás podríamos agregar una bandera --no-pseudo-syscalls a la lógica PFC? Entonces puede permanecer igual para los usuarios principiantes, pero los usuarios avanzados pueden obtener una mejor aproximación del BPF.

_ ACTUALIZADO: solucionó un problema con TSKIP_

Aún no se ha probado completamente, pero esto puede ser una solución: ¿puede verificar que esto sea razonable para el algoritmo de optimización de árbol equilibrado @drakenclimber?

Servirá. Quiero ver si puedo hacer una prueba automatizada que reproduzca este escenario.

_ ACTUALIZADO: solucionó un problema con TSKIP_
Aún no se ha probado completamente, pero esto puede ser una solución: ¿puede verificar que esto sea razonable para el algoritmo de optimización de árbol equilibrado @drakenclimber?

Servirá. Quiero ver si puedo hacer una prueba automatizada que reproduzca este escenario.

Y, por supuesto, comenzaré con la prueba del reproductor que tienes arriba. ¡Gracias!

_ ACTUALIZADO: solucionó un problema con TSKIP_

Aún no se ha probado completamente, pero esto puede ser una solución: ¿puede verificar que esto sea razonable para el algoritmo de optimización de árbol equilibrado @drakenclimber?

El árbol binario precalcula cuándo es necesario modificar el acumulador, y así es como sabe insertar la lógica jge . Retirar llamadas al sistema (como la propuesta anterior) mientras se construye el filtro rompe esta lógica.

Todavía no he probado completamente mis cambios :), pero estoy bastante seguro de que necesitaremos algo como esto para que el árbol binario funcione con la eliminación de pseudo-syscalls. Genere un árbol binario BPF usando esto y parece razonable. A medida que nos acerquemos a una solución lista para producción, la verificaré por completo.

@@ -1532,11 +1532,31 @@ static int _gen_bpf_syscalls(struct bpf_state *state,
                _sys_sort(db_secondary->syscalls, &s_head, &s_tail, optimize);

        if (optimize == 2) {
+               /* since pseudo-syscalls are removed from the filter, we need
+                * to calculate the syscall count by hand
+                */
+               for (s_iter = s_tail; s_iter != NULL; s_iter = s_iter->pri_prv) {
+                       if (!s_iter->valid)
+                               continue;
+
+                       /* skip pseudo-syscalls */
+                       if ((s_iter->num & 0x80000000) &&
+                           (state->attr->api_tskip == 0 || s_iter->num != -1))
+                               continue;
+
+                       syscall_cnt++;
+               }
+
                rc = _gen_bpf_init_bintree(&bintree_hashes, &bintree_syscalls,
-                                          bintree_levels, db->syscall_cnt,
+                                          bintree_levels, syscall_cnt,
                                           &empty_cnt);
                if (rc < 0)
                        goto out;
+
+               /* reset the syscall_cnt variable because later in this
+                * function it's used as a counter
+                */
+               syscall_cnt = 0;
        }

Esto podría hacerse más inteligente / rápido si tenemos una variable en la estructura db que rastrea el recuento de llamadas al sistema "válidas".

¿Quizás podríamos agregar un indicador --no-pseudo-syscalls a la lógica de PFC?

¿A dónde iría esta bandera? No creo que queramos esto como una opción de tiempo de construcción. Supongo que podríamos agregar una opción de filtro, pero eso no me entusiasma mucho. Votaría por seguir con las pseudo-llamadas al sistema en el PFC pero eliminarlo del BPF (obviamente) por ahora, y si necesitamos aumentar esto en algún momento en el futuro, podemos hacerlo.

Todavía no he probado completamente mis cambios :), pero estoy bastante seguro de que necesitaremos algo como esto para que el árbol binario funcione con la eliminación de pseudo-syscalls. Genere un árbol binario BPF usando esto y parece razonable. A medida que nos acerquemos a una solución lista para producción, la verificaré por completo.

Sospeché que esto iba a romper la optimización del árbol.

@drakenclimber, considerando que esto afecta la clasificación de árboles mucho más que la optimización estándar, ¿quieres abordar este problema? Siéntase libre de robar tanto o tan poco del código que copie y pegue arriba como tenga sentido.

Una cosa que creo que deberíamos hacer independientemente son los cambios en "arch-arm.c" y "arch-x32.c" ya que tiene más sentido.

¿Quizás podríamos agregar un indicador --no-pseudo-syscalls a la lógica de PFC?

¿A dónde iría esta bandera? No creo que queramos esto como una opción de tiempo de construcción. Supongo que podríamos agregar una opción de filtro, pero eso no me entusiasma mucho. Votaría por seguir con las pseudo-llamadas al sistema en el PFC pero eliminarlo del BPF (obviamente) por ahora, y si necesitamos aumentar esto en algún momento en el futuro, podemos hacerlo.

Admito que escribí antes de pensar. ;)

Sí, tendría que ser una opción de filtro y se siente mal. Estoy de acuerdo; hagamos lo que describiste anteriormente. Si seguimos recibiendo preguntas, podemos volver a visitarlas.

Todavía no he probado completamente mis cambios :), pero estoy bastante seguro de que necesitaremos algo como esto para que el árbol binario funcione con la eliminación de pseudo-syscalls. Genere un árbol binario BPF usando esto y parece razonable. A medida que nos acerquemos a una solución lista para producción, la verificaré por completo.

Sospeché que esto iba a romper la optimización del árbol.

@drakenclimber, considerando que esto afecta la clasificación de árboles mucho más que la optimización estándar, ¿quieres abordar este problema? Siéntase libre de robar tanto o tan poco del código que copie y pegue arriba como tenga sentido.

Una cosa que creo que deberíamos hacer independientemente son los cambios en "arch-arm.c" y "arch-x32.c" ya que tiene más sentido.

Seguro. Puedo tener este.

@drakenclimber "> Como se mencionó anteriormente, es una manera fácil para que los usuarios nuevos (más) verifiquen aproximadamente su filtro"

"Pseudo syscall" no existe en el kernel y tampoco es un concepto muy conocido. Es puramente la invención de libseccomp y no se explica aquí. Solo se indica que son números negativos y aparecen cuando la llamada al sistema dada no existe para la arquitectura. ¿En qué se diferencia esto de una llamada al sistema inexistente? ¿Con qué propósito son negativos? El concepto de pseudo syscall es realmente confuso para los nuevos usuarios.

No puedo creer que los usuarios nuevos (más) quieran ver llamadas al sistema inexistentes marcadas en sus filtros.

Permítanme agregar un punto más. Todo esto está en el campo de la seguridad, donde solo funciona una comprensión cuidadosa y detallada. Estás creando nuevos conceptos oscuros (de pseudo syscalls) y la diferencia entre representaciones (bpf y pfc). ¿Está esto realmente destinado a nuevos usuarios, para confundirlos más?

@ vt-alt gracias por expresar su preocupación, pero para la versión v2.5.0 vamos a suprimir las pseudo-llamadas al sistema del filtro BPF y continuar mostrándolas en el filtro PFC. Reconozco que puede no estar de acuerdo con esta decisión, pero le pido que la respete. En futuras versiones haremos un mejor trabajo explicando el propósito detrás de las pseudo-syscalls (es para soporte de múltiples ABI) y documentándolo en las páginas de manual; Creé un problema para eso (enlace a continuación), lo invitamos y lo alentamos a participar en esa discusión y en cualquier RP que resulte. También es posible que revisemos nuestro enfoque del filtro PFC en el futuro, pero no quiero prometer nada aquí.

Una vez más, gracias por llamar nuestra atención sobre el problema de BPF; ¡ha ayudado a mejorar la próxima versión de libseccomp!

Cierre por # 264.

¿Fue útil esta página
0 / 5 - 0 calificaciones