我从 SELinux 收到审核消息,说它拒绝 Apache 执行 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
PID 是 Apache PID 之一,它在进程之间不断循环。
据我所知,Apache 的 execmem 通常是不正常和一个坏主意™,这是有道理的。
我尝试过通过计算 Apache 日志的时间戳来跟踪来源,但是如果影响各个站点的各种请求(基于 PHP 的带或不带 MySQL、基于 Python/mod_wsgi 以及内部 Apache“OPTION”请求),我就无法找到任何一致的东西。
与其试图解释我的设置来让人们调试它,我想知道的是如何确定 execmem 调用来自哪里,以便我可以确定它是否重要?
(注意:我知道有一个 SELinux 布尔值可以设置为允许它,但我不想在没有首先了解它为什么要尝试它的情况下这样做。如果你要将它变成一个筛子,就像没有必要拥有防火墙然后打开每个抱怨的端口而不检查它是否重要)。
答案1
我最近在使用 PHP7 的 Amazon Linux 上使用 SELinux 时遇到了这个问题。我使用了以下组合拉塞尔·科克的绝妙LD_PRELOAD
技巧(拦截mmap()
调用并触发断言失败)和gdb(触发断言失败后立即查看调用堆栈)检查哪个函数想要执行内存。
我还得出结论,PHP7 PCRE JIT 是罪魁祸首。为我解决pcre.jit=0
了php.ini
它。
详细步骤
- 以 root 身份登录到您的计算机
mmap.c
从下载源代码这里进入/root/mmap.c- 构建代码
gcc -shared -g -fPIC mmap.c -o mmap.so
- 现在通过 gdb 运行 Apache,拦截 mmap() 调用:
LD_PRELOAD=/root/mmap.so gdb /usr/sbin/httpd
- 你被扔进了gdb。由于 Apache 会分叉子进程,因此通过在提示符
set follow-fork-mode child
后键入来告诉 gdb 跳转到这些子进程非常重要(gdb)
- 现在通过在提示
run
后键入来启动 Apache(gdb)
- 耐心等待,直到某个 HTTP 请求触发代码,进而触发 中的断言
mmap()
,然后您就回到了 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);
</pre>
8. Type `bt` (backtrace) to see the call stack:
<pre>(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 <__PRETTY_FUNCTION__.2774> "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 <__PRETTY_FUNCTION__.2774> "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
<...>
- 罪魁祸首很容易被发现。堆栈条目 11 提示您检查 PCRE,而条目 5 是实际出错的调用。