Para probar las mejoras de rendimiento de mi árbol binario propuesto, escribí un conjunto poco realista de reglas para read () y su argumento de tamaño de búfer (A2). Pero parece que la confirmación de reelaboración de src / db.c (ce3dda9a1) rompió el procesamiento de A2, al menos para este caso de prueba.
Antes de la confirmación de la reelaboración de la base de datos, una lectura como la siguiente - read(devzero_fd, buf, 8000)
- devolvió -10
. Después de esta confirmación, ahora devuelve -5
.
Aquí está el código C que usé para generar mis tontas reglas read ():
/* read */
for (i = 5; i <= 12; i++) {
rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(i), SCMP_SYS(read), 1,
SCMP_A2(SCMP_CMP_GT, 4 << i));
if (rc < 0) {
fprintf(stdout, "%s:%d Failed to add read rule %d : rc = %d\n",
__FUNCTION__, __LINE__, i, rc);
goto error;
}
}
rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1,
SCMP_A2(SCMP_CMP_LE, 64));
if (rc < 0) {
fprintf(stdout, "%s:%d Failed to add read allow rule : rc = %d\n",
__FUNCTION__, __LINE__, rc);
goto error;
}
Y aquí está el PFC que generó:
# filter for syscall "read" (0) [priority: 65525]
if ($syscall == 0)
if ($a2.hi32 >= 0)
if ($a2.lo32 > 64)
else
action ALLOW;
if ($a2.lo32 > 16384)
action ERRNO(12);
if ($a2.lo32 > 8192)
action ERRNO(11);
if ($a2.lo32 > 4096)
action ERRNO(10);
if ($a2.lo32 > 2048)
action ERRNO(9);
if ($a2.lo32 > 1024)
action ERRNO(8);
if ($a2.lo32 > 512)
action ERRNO(7);
if ($a2.lo32 > 256)
action ERRNO(6);
if ($a2.lo32 > 128)
action ERRNO(5);
else
action ALLOW;
# default action
action ERRNO(34);
Por cierto, haré lo que pueda para ayudar a enraizar la causa.
Usando scmp_bpf_disasm, la última libseccomp está poniendo los saltos en el orden incorrecto
CABEZA
0014: 0x25 0x11 0x00 0x00000080 jgt 128 true:0032 false:0015
0015: 0x25 0x0f 0x00 0x00000100 jgt 256 true:0031 false:0016
0016: 0x25 0x0d 0x00 0x00000200 jgt 512 true:0030 false:0017
0017: 0x25 0x0b 0x00 0x00000400 jgt 1024 true:0029 false:0018
0018: 0x25 0x09 0x00 0x00000800 jgt 2048 true:0028 false:0019
0019: 0x25 0x07 0x00 0x00001000 jgt 4096 true:0027 false:0020
0020: 0x25 0x05 0x00 0x00002000 jgt 8192 true:0026 false:0021
0021: 0x25 0x03 0x00 0x00004000 jgt 16384 true:0025 false:0022
0022: 0x25 0x01 0x00 0x00000040 jgt 64 true:0024 false:0023
0023: 0x06 0x00 0x00 0x7fff0000 ret ALLOW
pre-retrabajo
0014: 0x25 0x01 0x00 0x00000040 jgt 64 true:0016 false:0015
0015: 0x06 0x00 0x00 0x7fff0000 ret ALLOW
0016: 0x25 0x0f 0x00 0x00004000 jgt 16384 true:0032 false:0017
0017: 0x25 0x0d 0x00 0x00002000 jgt 8192 true:0031 false:0018
0018: 0x25 0x0b 0x00 0x00001000 jgt 4096 true:0030 false:0019
0019: 0x25 0x09 0x00 0x00000800 jgt 2048 true:0029 false:0020
0020: 0x25 0x07 0x00 0x00000400 jgt 1024 true:0028 false:0021
0021: 0x25 0x05 0x00 0x00000200 jgt 512 true:0027 false:0022
0022: 0x25 0x03 0x00 0x00000100 jgt 256 true:0026 false:0023
0023: 0x25 0x01 0x00 0x00000080 jgt 128 true:0025 false:0024
0024: 0x06 0x00 0x00 0x00050022 ret ERRNO(34)
Interesante. Entonces, el PFC parece ser "correcto", pero el BPF generado es ... al revés. Impar. Especialmente dado que la confirmación no cambió el código de generación de BPF.
Me pregunto si los valores de prioridad se están estropeando de alguna manera.
Perdón por la ambigüedad. El PFC (publicar el cambio de retrabajo) también está en el orden incorrecto. El PFC que publiqué arriba es el orden en el que estaba antes de la reelaboración de db.c.
Aquí está el PFC generado actualmente por HEAD
# filter for syscall "read" (0) [priority: 65525]
if ($syscall == 0)
if ($a2.hi32 >= 0)
if ($a2.lo32 > 128)
action ERRNO(5);
if ($a2.lo32 > 256)
action ERRNO(6);
if ($a2.lo32 > 512)
action ERRNO(7);
if ($a2.lo32 > 1024)
action ERRNO(8);
if ($a2.lo32 > 2048)
action ERRNO(9);
if ($a2.lo32 > 4096)
action ERRNO(10);
if ($a2.lo32 > 8192)
action ERRNO(11);
if ($a2.lo32 > 16384)
action ERRNO(12);
if ($a2.lo32 > 64)
else
action ALLOW;
else
action ALLOW;
# default action
action ERRNO(34);
Está bien, eso tiene un poco más de sentido. Los problemas definitivamente viven en algún lugar de la capa db.
Es un poco curioso cómo es exactamente al revés.
Encontré el problema. En la gestión de argumentos en cadena, el comportamiento de lvl_nxt y lvl_prv se intercambió después de la reelaboración masiva de db.c. Un par de pequeños cambios en _db_tree_add () hicieron que coincidiera con el comportamiento anterior de libseccomp.
Aquí hay una rama con la solución.
https://github.com/drakenclimber/libseccomp/tree/issues/112
Limpiaré los cambios, agregaré una prueba o dos y me aseguraré de que la cobertura del código esté a la altura.
Encontré algo de tiempo esta mañana, probablemente justo antes de que publicaras lo anterior, y decidí investigar un poco esto. Parece que llegamos prácticamente a la misma conclusión, aunque las correcciones son ligeramente diferentes. Aquí está mi solución actual, aunque como la suya, necesita algo de trabajo / limpieza adicional:
No estoy seguro de qué enfoque me gusta más en este momento, necesito pensar un poco en esto, ¿pensamientos?
Hmmm ... no mentiré; No estoy enamorado de ninguna solución en este momento.
El mío es simple, pero ignoró por completo _db_tree_prune () que, como dijiste en tu esencia, probablemente tenga problemas similares.
Me gusta su idea de reelaborar la macro gt () para utilizar las macros lt () y eq (), pero se están volviendo difíciles de manejar, especialmente lt (). ¿Hay alguna razón para no convertir lt () en una función en línea?
EDITAR - Acabo de notar que hiciste un comentario similar en la esencia.
Ejecuté gdb contra los antiguos libseccomp y HEAD, y los comportamientos de lvl_prv y lvl_nxt cambiaron, pero quizás eso no sea un gran problema ya que es una variable interna que nadie debería ver excepto nosotros.
Supongo que después de tanto divagar ... no lo sé. Estoy de acuerdo, necesito pensarlo;)
Hmmm ... no mentiré; No estoy enamorado de ninguna solución en este momento.
Me preocupa que haya algunos errores sutiles al reordenar un nivel de árbol como este, aunque parece que quizás el nivel fue reordenado por esa confirmación anterior y este es uno de los errores sutiles.
De cualquier manera, quiero entender cuál debería ser el orden deseado para un nivel: ¿"más grande" primero o "más grande" al final? Una vez que entendamos eso, podemos seguir adelante con las pruebas / reparaciones. Creo que la respuesta, aunque no sea por otra razón que la compatibilidad con versiones 2.x anteriores, es "más grande" primero, pero no puedo decirlo con certeza en este momento.
El mío es simple, pero ignoró por completo _db_tree_prune () que, como dijiste en tu esencia, probablemente tenga problemas similares.
Ambos básicamente hacen lo mismo en principio, el mío va un poco más allá al agregar algunas condiciones adicionales y limpiar la macro db_chain_lt (x, y).
Me gusta su idea de reelaborar la macro gt () para utilizar las macros lt () y eq (), pero se están volviendo difíciles de manejar, especialmente lt (). ¿Hay alguna razón para no convertir lt () en una función en línea?
Principalmente razones históricas. Comenzaron su vida como macros mucho más simples, pero han crecido bastante hasta el punto en que creo que probablemente deberían ser funciones. Creo que también sería bueno evaluar si realmente necesitan estar en el archivo de encabezado, creo que solo los usa src / db.c.
Ejecuté gdb contra los antiguos libseccomp y HEAD, y los comportamientos de lvl_prv y lvl_nxt cambiaron, pero quizás eso no sea un gran problema ya que es una variable interna que nadie debería ver excepto nosotros.
Sí, es un estado / árbol interno, no estoy demasiado preocupado por eso. Lo importante es la corrección del filtro generado.
Supongo que después de tanto divagar ... no lo sé. Estoy de acuerdo, necesito pensarlo;)
Je. Demos a esto uno o dos días y reagruparnos :) En este momento, esto no afecta a ninguna versión lanzada, solo está en la rama maestra, así que tenemos algo de tiempo para hacer las cosas bien.
En este momento, esto no afecta a ninguna versión lanzada, solo está en la rama maestra, por lo que tenemos algo de tiempo para hacer las cosas bien.
Suena bien. Haré algunas pruebas mientras contemplamos un plan
Escribí un programa para evaluar el manejo actual de seccomp A2. Todo el programa está disponible aquí:
https://gist.github.com/drakenclimber/3c6b45ecd973ee495281ef225fa5e54a
En pocas palabras, las reglas mayores que se generan en un orden de "última creación" "primer procesamiento".
>
se crean en orden ascendente , p. Ej.seccomp_rule_add(ctx, action1, syscall, 1, SCMP(SCMP_CMP_GT, 10)
seccomp_rule_add(ctx, action2, syscall, 1, SCMP(SCMP_CMP_GT, 20)
seccomp_rule_add(ctx, action3, syscall, 1, SCMP(SCMP_CMP_GT. 30)
if (A2 > 30)
do action3
if (A2 > 20)
do action2
if (A2 > 10)
do action1
>
se crean en orden descendente , p. Ej.seccomp_rule_add(ctx, action3, syscall, 1, SCMP(SCMP_CMP_GT, 30)
seccomp_rule_add(ctx, action2, syscall, 1, SCMP(SCMP_CMP_GT, 20)
seccomp_rule_add(ctx, action1, syscall, 1, SCMP(SCMP_CMP_GT. 10)
if
no se pueden alcanzarif (A2 > 10)
do action1
if (A2 > 20)
do action2
if (A2 > 30)
do action1
<
A2. Esto parece extraño porque no pude encontrar una manera de hacer el <=
equivalente al filtro >
anteriortom<strong i="43">@OracleDesktop</strong> $ ./a2test 3
Failed to add rule
action = 0x5000e op = 0x3 datum = 18000 rc = -17
Mode 3 (LE descending) test failed. rc = -17
tom<strong i="46">@OracleDesktop</strong> $ ./a2test 4
Failed to add rule
action = 0x50006 op = 0x3 datum = 250 rc = -17
Mode 4 (LE ascending) test failed. rc = -17
Supongo que la lógica else if
enterrada profundamente en src/db.c
está causando las fallas <
, por ejemplo. No estoy seguro de si vale la pena cambiarlo / arreglarlo.
Intentaré convertir parte de este código en pruebas automatizadas para que podamos capturar el comportamiento actual.
Como está escrito, la esencia aquí falló las pruebas automatizadas que agregué la semana pasada. Profundizaré y trataré de averiguar por qué.
batch name: 43-sim-a2_order
test mode: c
test type: bpf-sim
Test 43-sim-a2_order%%001-00001 result: SUCCESS
Test 43-sim-a2_order%%002-00001 result: SUCCESS
Test 43-sim-a2_order%%003-00001 result: SUCCESS
Test 43-sim-a2_order%%004-00001 result: SUCCESS
Test 43-sim-a2_order%%005-00001 result: SUCCESS
Test 43-sim-a2_order%%006-00001 result: SUCCESS
Test 43-sim-a2_order%%007-00001 result: SUCCESS
Test 43-sim-a2_order%%008-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%009-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%010-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%011-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%012-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%013-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%014-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%015-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%016-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%017-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%018-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%019-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%020-00001 result: FAILURE bpf_sim resulted in ERRNO(5)
Mi mal - apliqué mal la esencia. Las pruebas están pasando. Uf :)
¡Decir ah! :)
Pensé que hice las pruebas en su contra, pero estaba jugando con muchas cosas en ese momento, así que pensé que estaba recordando mal. Gracias por seguir mirando esto, todavía estoy un poco atascado con SELinux y audit, pero dado que el kernel está en -rc5 en este momento, espero que se calme tan pronto como coloque las interrupciones en el nuevo código antes de la fusión ventana ...
No hay problema. Eso es definitivamente una prioridad más alta.
He estado analizando su esencia a través de varias pruebas poco realistas. No he conseguido que se rompa, pero hasta ahora solo estoy ejercitando partes de _db_tree_prune (). Estoy empezando a sentirme más cómodo con los cambios, pero quiero dedicarle un poco más de tiempo.
Toqué y pinché en el código _db_tree_prune () y no pude romperlo. Test 08-sim-subtree_checks realmente hace un buen trabajo probando la mayoría de las rutas de código dentro de prune ().
Creo que los cambios de tu esencia están listos.
Envié la solicitud de extracción n. ° 115. Creo que esto está listo para rodar
Cerrando, ya que esto debería resolverse ahora (ver historial arriba).