Quero traduzir:
"a b c syscall=257 success=yes"
no seguinte:
"a b c syscall=openat success=yes"
Gostaria de usar o grupo sed capturando regexp e substituição combinados com o uso do ausyscall aplicado ao número extraído pelo grupo regexp.
Tentei o seguinte no Linux/bash:
echo "a b c syscall=257 success=yes" |
sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall 257)":"
Imprime: a b c SYSCALL=openat success=yes
conforme o esperado.
Então eu tentei usar o grupo de captura #1 como argumento para ausyscall
. Assim:
echo "a b c syscall=257 success=yes" |
sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \1)":"
Isso invoca ausyscall 1
which imprime write
. Este não é o grupo capturado #1 (que tem um valor de 257).
Então tentei usar \\1
, mas também não funcionou:
echo "a b c syscall=257 success=yes" |
sed -e "s:syscall=\([0-9]*\):SYSCALL="$(ausyscall \\1)":"
Isso invoca ausyscall \1
, então falha, imprime um erro em stderr( Unknown syscall \1 using x86_64 lookup table
) e imprime a b c SYSCALL= success=yes
em stdout.
Ele falha ao passar o valor capturado para ausyscall. Tentei com aspas simples, mas a chamada para ausyscall não é feita.
É possível usar sed dessa maneira?
- Só estou interessado em saber se é esperado que isso seja possível com sed .
- Sei que isso pode ser feito por outros meios (perl, script python, gawk, etc.), mas quero ver se é possível com sed e se o problema está relacionado a aspas ou algo assim.
É possível com sed ? Se sim, o que estou esquecendo?
Não é esperado que
sed
possa fazer isso. Não pode! A execução real do comando é algo que seu shell faz, nãosed
, então isso não é um recurso desed
, mas outro programa, o shellVocê já está abordando dessa forma! Você está usando um interpretador de linguagem de script como mecanismo de substituição e, dentro dele, está usando
sed
para fazer algumas operações elementares. Seu shell (seja bash, ash, zsh, csh, cmd, …) não é diferente de, digamos, o interpretador python.O GNU sed pode fazer isso se você estiver disposto a usar a extensão GNU sed
e
para os
comando:A
e
extensão paras
bifurcar um shell e avaliars
o espaço de padrões resultante de e substitui o espaço de padrões pelo resultado do comando executado. Para mitigar quaisquer problemas potenciais de injeção de código, o regex para extrair o número do syscall é muito cuidadoso para corresponder apenas a dígitos numéricos. não é usado, pois pode corresponder a outras coisas em vários locais. O número resultante é então passado para um comando[0-9]
construído e executado.ausyscall
O restante dos
sed
comandos serve para garantir que, se houver linhas de entrada que não contenham números de chamada de sistema, elas não sejam modificadas.Nota lateral - Usuários do Ubuntu podem instalar o
ausyscall
comando instalando oauditd
pacote:Observe também - sempre que você vir a palavra
evaluate
, considere isso como um grande aviso de possíveis bugs de injeção de código. Não use comandos como esse em entradas de usuário não verificadas. Como esse caso funciona em dados estritamente numéricos, é simples de validar, mas muito mais cuidado deve ser tomado com casos mais gerais.Não creio que
sed
seja possível fazer isso, mas o Perl pode e é apenas um pouco mais complexo:Embora, isso provavelmente adicionará uma nova linha extra ali que você não quer. Então, você pode precisar disto em vez disso:
O operador do Perl
s
funciona praticamente da mesma forma que o do sed. A única diferença aqui é que, ao usar oe
sinalizador no final (s:old:new:e
), isso nos permite executar código perl no lado da substituição e usar o resultado do código. O código em questão é:`ausyscall $1`
: executeausyscall
passando-o$1
(isso é o equivalente ao \1 do sed — embora o Perl também possa trabalhar com \1, mas não com oe
sinalizador — então é o que foi capturado pelo primeiro conjunto de parênteses) como um argumento. Note que o comando é executado no shell padrão do sistema (geralmentesh
).chomp($v=`...`)
: remove quebras de linha finais. Isso remove a quebra de linha retornada peloausyscall
comando. O resultado é armazenado na variável$v
."SYSCALL=$v"
: isso retorna a saída desejada.Note que essa é uma abordagem arriscada. Ela está boa aqui, nesse caso específico, já que você está explicitamente capturando apenas dígitos numéricos, mas, como regra geral, você não quer executar entrada arbitrária como um comando, pois isso o torna vulnerável a um ataque de injeção de código.
Você poderia facilmente usar
sed
para traduzir a linha de entrada em um comando shell que seria então capaz de produzir a saída desejada. Oeval
comando do shell, combinado com a substituição de comando, deve fazer o truque para processar uma linha de cada vez, como no seu exemplo. Diga, algo assim:No entanto, como outros responderam, dadas as especificidades da sua aplicação e dependendo de quantas vezes você precisa fazer isso (ou seja, quantas linhas de entrada você deseja processar a qualquer momento), usar
ausyscall
é provavelmente a maneira menos eficiente e eficaz de fazer isso.É isso que a
-i
opçãoausearch
faz (e muito mais):Veja como o número da chamada de sistema foi traduzido, mas também o timestamp¹, arquitetura, modo, uids, gids, alguns argumentos para a chamada de sistema...
Executar
ausyscall
para cada ocorrência desyscall=<numbers>
na entrada seria muito ineficiente, especialmente considerando que tanto o GNUsed
quantoperl
o usado em algumas outras respostas também executam ou podem executar um shell para interpretar o comando. O comandosed
do GNUe
ee
o sinalizador dos
comando também são virtualmente impossíveis de usar com segurança, eu recomendo fortemente não usá-lo, nunca.Aqui, se você quiser traduzir apenas os números de syscall e não os outros IDs como
ausearch
faz, o melhor seria usar a saída deausyscall --dump
(run once) que fornece o mapeamento completo:Isso pressupõe que você esteja em um sistema de arquitetura única, já que os números de syscall são dependentes da arquitetura. Por exemplo, em um PC moderno onde você pode ter aplicativos rodando em modo x86 ou amd64 (também conhecido como x86_64), isso não funcionará corretamente se houver chamadas de sistema feitas por aplicativos x86, pois
ausyscall
fornece as traduções para syscalls amd64.ausearch -i
faz isso corretamente, mas para fazer o mesmo, você precisaria construir dois mapas, um para x86 e outro para amd64, e extrair a arquitetura do registro de auditoria.Exemplo, usando uma compilação estática do busybox x86 aqui:
Essas são duas
openat
chamadas de sistema, a primeira sendo a amd64 docat
, a segunda a x86 do busybox-x86.ausearch -i
traduz corretamente:Mas o
perl
código acima está errado (e sua tentativa também):Como 295 é o número da
preadv
chamada de sistema amd64 e daopenat
chamada de sistema x86.Então, nesse sistema multi-arquitetura, eu precisaria de algo como:
O que corretamente me dá:
Se
ausyscall
não houver suporte--dump
, você pode pelo menos armazenar o resultado em cache para evitar ter que executá-lo várias vezes para o mesmo valor:(aqui também lidando com arquiteturas amd64 e x86).
¹ usando hora local (usar
TZ=UTC0
para hora UTC) e formatado comostrftime("%x %T")
, dependente da localidade; use uma localidade como csb_PL de_AT de_BE de_LU en_CA en_DK eo fr_CA hu_HU kv_RU lt_LT se_NO si_LK sv_SE wae_CH para obter um registro de data e hora menos ambíguo, semelhante ao ISO8601:sudo TZ=UTC0 LC_ALL= LC_TIME=en_DK.UTF-8 ausearch -i ...
; certifique-se de que a localidade esteja disponível no seu sistema, caso contrário, você obterá registros de data e hora no estilo dos EUA da localidade C no%m/%d/%y %H:%M:%S
formato.