Como descobrir por que o Apache está tentando “execmem”?

5

Estou recebendo mensagens de auditoria do SELinux dizendo que ele negou o Apache fazendo execmem:

type=AVC msg=audit(05/06/16 19:51:43.058:181060) : avc:  denied  { execmem } for  pid=123456 comm=httpd scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:httpd_t:s0 tclass=process 

O PID é um dos Apache PIDs e continua circulando entre os processos.

Pelo que eu li, o execmem para o Apache é geralmente não normal e uma Bad Idea ™ , e isso faz sentido.

Eu tentei rastrear uma origem registrando registros de data e hora com logs do Apache, mas se ela afeta várias solicitações em vários sites (baseada em PHP com e sem MySQL, baseada em Python / mod_wsgi, além de solicitações internas de "OPTION") e Não consigo encontrar nada consistente.

Em vez de tentar explicar minha configuração para levar as pessoas a depurá-la, o que eu quero saber é como faço para descobrir de onde vem a chamada execmem para que eu possa descobrir se é importante?

(Nota: Eu sei que existe um booleano do SELinux para permitir, mas eu não quero fazer isso sem primeiro entender por que ele está tentando. Não faz sentido ter o SELinux se você estiver indo transformá-lo em uma peneira, bem como não há nenhum sentido ter um firewall e, em seguida, abrir todas as portas que nunca se queixam, sem verificar se é importante ou não).

    
por IBBoard 05.06.2016 / 21:01

1 resposta

6

Recentemente, deparei com esse problema com o SELinux no Amazon Linux com PHP7. Eu usei uma combinação do excelente truque LD_PRELOAD de Russell Coker (para interceptar chamadas mmap () e disparar uma falha de asserção) e gdb (para visualizar a pilha de chamadas assim que a falha de asserção é acionada) para verificar qual função deseja executar.

Eu também cheguei à conclusão de que o PHP7 PCRE JIT foi o culpado. Colocar pcre.jit = 0 no php.ini corrigiu para mim.

Etapas detalhadas

  1. faça login em sua máquina como root
  2. faça o download do código-fonte mmap.c em link em /root/mmap.c
  3. crie o código com gcc -shared -g -fPIC mmap.c -o mmap.so
  4. agora execute o Apache através do gdb, interceptando as chamadas mmap (): LD_PRELOAD=/root/mmap.so gdb /usr/sbin/httpd
  5. você é lançado no gdb. Como o Apache bifurca os processos filhos, é importante informar ao gdb para entrar neles digitando set follow-fork-mode child após o prompt (gdb)
  6. agora inicie o Apache digitando run após o prompt (gdb)
  7. aguarde com paciência até que alguma solicitação HTTP dispare o código que, por sua vez, aciona a asserção no mmap, e você volta ao gdb.
Program received signal SIGABRT, Aborted.

[Switching to Thread 0x7ffff7fe9840 (LWP 28370)]

0x00007ffff638d5f7 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56

56        return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
  1. Digite bt (backtrace) para ver a pilha de chamadas:
(gdb) bt

#0  0x00007ffff638d5f7 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56

#1  0x00007ffff638ece8 in __GI_abort () at abort.c:90

#2  0x00007ffff6386566 in __assert_fail_base (fmt=0x7ffff64d6ca8 "%s%s%s:%u: %s%sAssertion '%s' failed.\n%n", assertion=assertion@entry=0x7ffff7bda990 "!(prot & 0x4) || !(prot & 0x2)",

    file=file@entry=0x7ffff7bda985 "mmap.c", line=line@entry=27, function=function@entry=0x7ffff7bda9af  "mmap") at assert.c:92

#3  0x00007ffff6386612 in __GI___assert_fail (assertion=0x7ffff7bda990 "!(prot & 0x4) || !(prot & 0x2)", file=0x7ffff7bda985 "mmap.c", line=27, function=0x7ffff7bda9af  "mmap")

    at assert.c:101

#4  0x00007ffff7bda93e in mmap (addr=0x0, length=65536, prot=7, flags=34, fd=-1, offset=0) at mmap.c:27

#5  0x00007ffff79a6b86 in alloc_chunk (size=65536) at sljit/sljitExecAllocator.c:101

#6  sljit_malloc_exec (size=4440) at sljit/sljitExecAllocator.c:204

#7  sljit_generate_code (compiler=compiler@entry=0x555555b14ad0) at sljit/sljitNativeX86_common.c:296

#8  0x00007ffff79bf74e in _pcre_jit_compile (re=re@entry=0x555555b14650, extra=extra@entry=0x555555b14750) at pcre_jit_compile.c:6434

#9  0x00007ffff79c1fc3 in pcre_study (external_re=external_re@entry=0x555555b14650, options=1, errorptr=errorptr@entry=0x7fffffffa3c8) at pcre_study.c:1354

#10 0x00007fffed2edcbc in pcre_get_compiled_regex_cache (regex=0x7fffd8a04000) at /usr/src/debug/php-7.0.9/ext/pcre/php_pcre.c:487

#11 0x00007fffed2ef21f in php_do_pcre_match (execute_data=0x7fffec419ab0, return_value=0x7fffec419870, global=1) at /usr/src/debug/php-7.0.9/ext/pcre/php_pcre.c:655


  1. o culpado é facilmente identificado. A entrada de pilha 11 dá-lhe uma sugestão para verificar o PCRE e a entrada 5 é a chamada real que dá errado.
por 28.08.2016 / 08:41