Libseccomp: Erro: manipulação de A2 interrompida por retrabalho src / db.c

Criado em 26 fev. 2018  ·  18Comentários  ·  Fonte: seccomp/libseccomp

Para testar minha proposta de melhorias de desempenho de árvore binária, escrevi um conjunto irreal de regras para read () e seu argumento de tamanho de buffer (A2). Mas parece que o commit de retrabalho src / db.c (ce3dda9a1) quebrou o processamento de A2 - pelo menos para este caso de teste.

Antes do commit de retrabalho do banco de dados, uma leitura como a seguinte - read(devzero_fd, buf, 8000) - retornou -10 . Após este commit, ele agora retorna -5 .

Aqui está o código C que usei para gerar minhas regras read () bobas:

        /* 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;
        } 

E aqui está o PFC gerado:

  # 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);
bug priorithigh

Todos 18 comentários

A propósito, farei o que puder para ajudar a causar a raiz disso

Usando scmp_bpf_disasm, o libseccomp mais recente está colocando os saltos na ordem incorreta

CABEÇA

 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

pré-retrabalho

 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)

Interessante. Portanto, o PFC parece estar "correto", mas o BPF gerado está ... ao contrário. Ímpar. Especialmente considerando que o commit não alterou o código de geração do BPF.

Eu me pergunto se os valores de prioridade estão ficando bagunçados de alguma forma?

Desculpe pela ambigüidade. O PFC (lançar a modificação de retrabalho) também está na ordem incorreta. O PFC que postei acima é a ordem em que estava antes do retrabalho do db.c.

Aqui está o PFC gerado atualmente pelo 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);

Ok, isso faz um pouco mais de sentido. Os problemas definitivamente residem em algum lugar na camada db.

É um pouco engraçado como é exatamente ao contrário.

Eu encontrei o problema. No gerenciamento de argumento da cadeia, o comportamento de lvl_nxt e lvl_prv mudou após o retrabalho db.c massivo. Algumas pequenas mudanças em _db_tree_add () o tornaram compatível com o comportamento anterior do libseccomp.

Aqui está um branch com a correção
https://github.com/drakenclimber/libseccomp/tree/issues/112

Vou limpar as alterações, adicionar um ou dois testes e garantir que a cobertura do código seja adequada.

Eu encontrei algum tempo esta manhã, provavelmente pouco antes de você postar o acima, e decidi dar uma olhada nisso um pouco. Parece que chegamos praticamente à mesma conclusão, embora as correções sejam um pouco diferentes. Aqui está minha correção atual, embora, como a sua, ela precise de algum trabalho / limpeza adicional:

Não tenho certeza de qual abordagem eu gosto mais agora, preciso pensar um pouco sobre isso, pensamentos?

Hmmm ... eu não vou mentir; Não estou apaixonado por nenhuma das soluções neste momento.

O meu é simples, mas ignorou completamente _db_tree_prune () que - como você disse em sua essência - provavelmente tem problemas semelhantes.

Gosto da sua ideia de retrabalhar a macro gt () para utilizar as macros lt () e eq (), mas elas estão ficando complicadas - especialmente lt (). Existe alguma razão para não converter lt () em uma função embutida?
EDIT - Acabei de notar que você fez um comentário semelhante na essência.

Eu executei o gdb contra o antigo libseccomp e HEAD, e os comportamentos de lvl_prv e lvl_nxt mudaram, mas talvez isso não seja um grande problema, já que é uma variável interna que ninguém deveria ver além de nós.

Acho que depois de toda essa divagação ... não sei. Eu concordo, preciso pensar sobre isso;)

Hmmm ... eu não vou mentir; Não estou apaixonado por nenhuma das soluções neste momento.

Estou preocupado que haja alguns bugs sutis com a reordenação de um nível de árvore como este, embora pareça que talvez o nível tenha sido reordenado por aquele commit anterior e este é um dos bugs sutis.

De qualquer forma, quero entender qual deve ser a ordem desejada para um nível: "maior" primeiro ou "maior" por último. Assim que entendermos isso, podemos prosseguir com os testes / consertos. Eu acho que a resposta, mesmo que por nenhuma outra razão além da compatibilidade com versões 2.x anteriores, é "maior" primeiro, mas não posso dizer isso com certeza neste momento.

O meu é simples, mas ignorou completamente _db_tree_prune () que - como você disse em sua essência - provavelmente tem problemas semelhantes.

Ambos fazem basicamente a mesma coisa em princípio, o meu vai um pouco além, adicionando algumas condições adicionais e limpando a macro db_chain_lt (x, y).

Gosto da sua ideia de retrabalhar a macro gt () para utilizar as macros lt () e eq (), mas elas estão ficando complicadas - especialmente lt (). Existe alguma razão para não converter lt () em uma função embutida?

Principalmente por razões históricas. Eles começaram como macros muito mais simples, mas cresceram um pouco a ponto de eu acho que provavelmente deveriam ser funções. Acho que também seria bom avaliar se eles realmente precisam estar no arquivo de cabeçalho, acredito que só sejam usados ​​por src / db.c.

Eu executei o gdb contra o antigo libseccomp e HEAD, e os comportamentos de lvl_prv e lvl_nxt mudaram, mas talvez isso não seja um grande problema, já que é uma variável interna que ninguém deveria ver além de nós.

Sim, é um estado / árvore interna, não estou muito preocupado com isso. O importante é a correção do filtro gerado.

Acho que depois de toda essa divagação ... não sei. Eu concordo, preciso pensar sobre isso;)

Heh. Vamos esperar um ou dois dias e nos reagrupar :) No momento, isso não afeta nenhuma versão lançada, está apenas no branch master, então temos algum tempo para acertar as coisas.

No momento, isso não afeta nenhuma versão lançada, está apenas no branch master, então temos algum tempo para acertar as coisas.

Soa bem. Vou fazer alguns testes enquanto pensamos em um plano

Eu escrevi um programa para avaliar o tratamento atual do seccomp A2. O programa completo está disponível aqui:

https://gist.github.com/drakenclimber/3c6b45ecd973ee495281ef225fa5e54a

Resumindo, regras maiores que são geradas em um pedido "criado pela última vez" e "processado pela primeira vez".

  • Para um filtro onde > regras são criadas em ordem crescente , por exemplo
    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)
    então o filtro se comportará de maneira coerente, por exemplo
if (A2 > 30)
    do action3
if (A2 > 20)
    do action2
if (A2 > 10)
    do action1
  • Para um filtro onde > regras são criadas em ordem decrescente , por exemplo
    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)
    então o filtro será criado, mas se comportar de forma estranha. Código morto será produzido. As duas últimas if declarações são inacessíveis
if (A2 > 10)
    do action1
if (A2 > 20)
    do action2
if (A2 > 30)
    do action1
  • Filtros com múltiplas operações < A2 não são permitidos atualmente pelo seccomp. Isso parece estranho porque não consegui descobrir uma maneira de tornar o <= equivalente ao filtro > acima
tom<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

Estou supondo que a lógica else if enterrada profundamente em src/db.c está causando as < falhas, por exemplo. Não tenho certeza se vale a pena mudar / consertar.

Vou tentar converter parte desse código em testes automatizados para que possamos capturar o comportamento atual.

Conforme está escrito, a essência aqui falhou nos testes automatizados que adicionei na semana passada. Vou me aprofundar e tentar descobrir o porquê.

 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)

Meu mal - eu apliquei mal a essência. Os testes estão passando. Ufa :)

Ha! :)

Achei que tinha feito os testes contra ele, mas estava brincando com muitas coisas naquela época, então achei que estava apenas me lembrando errado. Obrigado por continuar a olhar para isso, ainda estou um pouco atolado com SELinux e auditoria, mas como o kernel está em -rc5 agora, espero que ele se acalme assim que eu interromper o novo código antes da fusão janela ...

Sem problemas. Essa é definitivamente uma prioridade mais alta.

Estive examinando sua essência em vários testes irrealistas. Eu não consegui quebrar, mas também estou apenas exercitando pedaços de _db_tree_prune () até agora. Estou começando a me sentir mais confortável com as mudanças, mas quero dedicar um pouco mais de tempo.

Eu cutuquei e cutuquei o código _db_tree_prune () e não consegui decifrá-lo. O teste 08-sim-subtree_checks realmente faz um bom trabalho ao testar a maioria dos caminhos de código em prune ().

Acho que as mudanças em sua essência estão prontas.

Enviei a solicitação pull # 115. Eu acho que isso está pronto para rolar

Fechando, pois isso agora deve ser resolvido (consulte o histórico acima).

Esta página foi útil?
0 / 5 - 0 avaliações