Libseccomp: Q: não pode haver filtros diferentes com SCMP_ACT_NOTIFY em tópicos diferentes

Criado em 6 nov. 2020  ·  9Comentários  ·  Fonte: seccomp/libseccomp

libseccomp armazena o fd de notificação em uma variável global: state.notify_fd . Isso torna impossível usar libseccomp para um aplicativo multi-threaded com filtros diferentes em threads diferentes (ou seja, sem usar TSYNC).

libseccomp tem seccomp_reset(NULL, ...) para redefinir a variável global state.notify_fd . Mas seccomp_reset() tem a infeliz conseqüência de redefinir state.nr_seccomp = -1 .

Esse problema foi observado ao tentar resolver testes de unidade em libseccomp-golang, consulte https://github.com/seccomp/libseccomp-golang/pull/59#issuecomment -723045033

cc @yvesf @rata

prioritlow question

Comentários muito úteis

Parece que estamos todos de acordo aqui, então vou encerrar este problema. @alban se você acha que está faltando algo importante, informe-nos e / ou

Obrigado a todos.

Todos 9 comentários

@drakenclimber suspende os próximos lançamentos v2.5.1 até obtermos alguns esclarecimentos sobre isso. Não tenho certeza se entendi completamente o relatório original ainda, mas como a v2.5.1 é a primeira versão a implementar o conceito seccomp_reset(NULL, ...) , vamos esperar apenas um minuto até que possamos verificar as coisas ...

Adicionando isso ao marco v2.5.1 simplesmente como um bloqueador por agora, isso pode mudar enquanto investigamos as coisas.

@drakenclimber suspende os próximos lançamentos v2.5.1 até obtermos alguns esclarecimentos sobre isso. Não tenho certeza se entendi completamente o relatório original ainda, mas como a v2.5.1 é a primeira versão a implementar o conceito seccomp_reset(NULL, ...) , vamos esperar apenas um minuto até que possamos verificar as coisas ...

Concordaram. Vai fazer.

libseccomp armazena o fd de notificação em uma variável global: state.notify_fd . Isso torna impossível usar libseccomp para um aplicativo multi-threaded com filtros diferentes em threads diferentes (ou seja, sem usar TSYNC).

Você pode elaborar um pouco mais sobre a última frase? Não tenho certeza se entendi o que você está tentando transmitir.

FWIW, a notificação seccomp FD é um objeto global de processo, você só pode solicitá-lo do kernel uma vez. Você pode ler https://github.com/seccomp/libseccomp/issues/273 para obter mais informações sobre o problema.

libseccomp tem seccomp_reset(NULL, ...) para redefinir a variável global state.notify_fd . Mas seccomp_reset() tem a infeliz conseqüência de redefinir state.nr_seccomp = -1 .

Por que redefinir state.nr_seccomp = -1 um problema significativo? Se o campo nr_seccomp for redefinido para -1 na próxima vez que uma operação for solicitada que possa usar seccomp(2) a biblioteca verifica se seccomp(2) é compatível e usa-o se estiver disponível. Sim, isso pode resultar em chamadas extras para seccomp(2) mas isso não deve ser um grande problema, é uma preocupação para o seu caso de uso?

@alban - Pergunta semelhante minha. Passei um pouco de tempo tentando inventar um caso de uso de filtro multissegmentado e multi-seccomp sensato (em C) e realmente não consegui pensar em nada.

Eu li a documentação Go de os.LockOSThread() e faz sentido para mim. Mas estou lutando para converter esse conhecimento em uma solução multi-threaded, multi-seccomp-filter.

Você poderia compartilhar algum pseudo-código ou design de alto nível do que está pensando? Eu ficaria feliz em fazer um protótipo em C então.

Você pode elaborar um pouco mais sobre a última frase? Não tenho certeza se entendi o que você está tentando transmitir.

Enquanto trabalhava nos testes de unidade em libseccomp-golang, percebi que o seguinte cenário estava sendo testado:

  1. Em uma primeira execução do teste de unidade, uma política seccomp foi aplicada sem SECCOMP_FILTER_FLAG_TSYNC (o que significa que é aplicada no nível do thread e não no nível do processo), mas com SECCOMP_FILTER_FLAG_NEW_LISTENER (então libseccomp irá armazenar o fd em state.notify_fd ).
  2. O mesmo teste de unidade é executado novamente no mesmo processo, mas em um thread diferente (usando runtime.LockOSThread em Go para ter certeza disso). Mas libseccomp reutiliza o fd do filtro seccomp anterior (de state.notify_fd ) em vez de obter um novo fd para o novo filtro. Em seguida, o teste falha porque esperamos receber os eventos no seccomp fd errado.

FWIW, a notificação seccomp FD é um objeto global de processo, você só pode solicitá-lo do kernel uma vez. Você pode ler # 273 para obter mais informações sobre o assunto.

Pelo que entendi, o kernel nos restringe a obter apenas um FD de notificação seccomp em uma árvore de filtro. Mas no cenário acima, os dois threads do mesmo processo estão usando árvores de filtro diferentes, então isso deve estar bem da perspectiva do kernel.

Este cenário para usar diferentes árvores de filtro com SECCOMP_FILTER_FLAG_NEW_LISTENER não foi construído propositalmente, ele apenas surgiu como uma consequência dos testes de unidade libseccomp-golang rodando no mesmo processo. Mas como a causa raiz é libseccomp usando uma variável global state.notify_fd que é compartilhada entre os threads, pensei que deveria abrir este bug aqui para abrir a discussão. No entanto, eu ficaria bem se isso fosse fechado como "WONTFIX" (não sei se outros usuários de libseccomp precisariam de suporte para esse tipo de cenário). Nesse caso, podemos apenas escrever os testes de unidade libseccomp-golang de uma maneira diferente (ou seja, usando um processo separado para cada iteração de teste); teríamos que fazer isso de qualquer maneira (para evitar misturar filtros de nível de thread e filtros de nível de processo - isso seria rejeitado pelo kernel).

Enquanto trabalhava nos testes de unidade em libseccomp-golang, percebi que o seguinte cenário estava sendo testado:

  1. Em uma primeira execução do teste de unidade, uma política seccomp foi aplicada sem SECCOMP_FILTER_FLAG_TSYNC (o que significa que é aplicada no nível do thread e não no nível do processo), mas com SECCOMP_FILTER_FLAG_NEW_LISTENER (então libseccomp irá armazenar o fd em state.notify_fd ).
  2. O mesmo teste de unidade é executado novamente no mesmo processo, mas em um thread diferente (usando runtime.LockOSThread em Go para ter certeza disso). Mas libseccomp reutiliza o fd do filtro seccomp anterior (de state.notify_fd ) em vez de obter um novo fd para o novo filtro. Em seguida, o teste falha porque esperamos receber os eventos no seccomp fd errado.

Ah ha, isso faz mais sentido agora. Muitas vezes me perguntei se deveríamos tornar o TSYNC o padrão para as ligações libseccomp-golang; dada a ambigüidade do tópico em Go, parece uma escolha muito mais segura.

Pelo que entendi, o kernel nos restringe a obter apenas um FD de notificação seccomp em uma árvore de filtro. Mas no cenário acima, os dois threads do mesmo processo estão usando árvores de filtro diferentes, então isso deve estar bem da perspectiva do kernel.

Este cenário para usar diferentes árvores de filtro com SECCOMP_FILTER_FLAG_NEW_LISTENER não foi construído propositalmente, ele apenas surgiu como uma consequência dos testes de unidade libseccomp-golang rodando no mesmo processo. Mas como a causa raiz é libseccomp usando uma variável global state.notify_fd que é compartilhada entre os threads, pensei que deveria abrir este bug aqui para abrir a discussão. No entanto, eu ficaria bem se isso fosse fechado como "WONTFIX" (não sei se outros usuários de libseccomp precisariam de suporte para esse tipo de cenário). Nesse caso, podemos apenas escrever os testes de unidade libseccomp-golang de uma maneira diferente (ou seja, usando um processo separado para cada iteração de teste); teríamos que fazer isso de qualquer maneira (para evitar misturar filtros de nível de thread e filtros de nível de processo - isso seria rejeitado pelo kernel).

Estarei interessado em obter a opinião de @drakenclimber sobre isso, mas sim, meu pensamento agora é que este é um "WONTFIX" devido a ser um caso secundário um tanto bizarro. Se um aplicativo quiser fazer algo assim, ele pode salvar o fd de notificação da árvore de filtros "A", redefinir libseccomp e, em seguida, recuperar e salvar o fd de notificação da árvore de filtros "B".

Para "consertar" isso em libseccomp, precisaríamos conscientizar o thread de libseccomp, que vem com uma série de desafios e armadilhas, de modo que atualmente sou da opinião de que isso seria uma má ideia. No entanto, para fins de argumentação, se tornássemos o thread libseccomp ciente, também poderíamos tornar o estado global interno um estado específico do thread e / ou possivelmente um estado específico da árvore de filtro; em qualquer um desses casos, acho que a API atual (incluindo seccomp_reset(NULL, ...) ) ainda seria razoável, por isso estou tentado a deixar as coisas como estão com a API. Se alguém tiver alguma dúvida sobre isso, entre em contato conosco em breve.

@drakenclimber? Excluindo quaisquer objeções ao acima, acho que estamos de volta para a versão v2.5.1.

Estarei interessado em obter a opinião de @drakenclimber sobre isso, mas sim, meu pensamento agora é que este é um "WONTFIX" devido a ser um caso secundário um tanto bizarro. Se um aplicativo quiser fazer algo assim, ele pode salvar o fd de notificação da árvore de filtros "A", redefinir libseccomp e, em seguida, recuperar e salvar o fd de notificação da árvore de filtros "B".

Eu concordo. Passei algum tempo vasculhando o patchset original de

Dito isso, tentei criar um caso de uso de processo único e multithread que tem vários invocadores e manipuladores de notificação. Honestamente, eu não poderia conceber coerentemente tal cenário. Como este é um caso de uso bastante artificial e não consigo imaginar um caso de uso realista, devemos marcar este como WONTFIX.

À parte - consegui fazer com que o kernel retornasse vários fds de notificação para um processo. Ao criar vários pthreads e fazer com que todos carreguem imediatamente um filtro seccomp com uma ação de notificação, ocasionalmente eu era capaz de obter dois ou três fds de notificação diferentes retornados ao processo de espaço do usuário. Já que isso é tão irreal, eu tenderia a marcar esse problema do kernel como um WONTFIX também.

@drakenclimber? Excluindo quaisquer objeções ao acima, acho que estamos de volta para a versão v2.5.1.

Ótimo. Devo poder começar a trabalhar nisso na próxima semana.

Parece que estamos todos de acordo aqui, então vou encerrar este problema. @alban se você acha que está faltando algo importante, informe-nos e / ou

Obrigado a todos.

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

Questões relacionadas

varqox picture varqox  ·  23Comentários

vasanthaganeshk picture vasanthaganeshk  ·  9Comentários

erdumbledore picture erdumbledore  ·  3Comentários

pcmoore picture pcmoore  ·  23Comentários

pcmoore picture pcmoore  ·  4Comentários