web-dev-qa-db-ja.com

Apacheが「execmem」を試行している理由を理解するにはどうすればよいですか?

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の1つであり、プロセス間を循環し続けます。

私が読んだことから、Apacheのexecmemは一般的に 通常ではない および Bad Idea™ であり、それは理にかなっています。

Apacheログでタイムスタンプを集計してOriginを追跡しようとしましたが、さまざまなサイト(MySQLの有無にかかわらずPHPベース、Python/mod_wsgiベース、および内部Apache "OPTION"リクエスト)のさまざまなリクエストに影響し、一貫性のあるものを見つけます。

私が知りたいのは、execmem呼び出しがどこから来ているのかを確認して、それがそうであるかどうかを確認できるようにする方法です。重要ですか?

(注:許可するように設定するSELinuxブール値があることはわかっていますが、それを試行する理由を最初に理解しないと、そうしたくないのです。SELinuxを使用する場合は、SELinuxを使用しても意味がありません。ふるい。ファイアウォールを設定して、重要であるかどうかを確認せずに文句を言うすべてのポートを開いても意味がないようなものです。

5
IBBoard

最近、PHP7を使用するAmazon Linux上のSELinuxでこの問題に遭遇しました。 Russell Cokerの優れたLD_PRELOADトリック(mmap()呼び出しをインターセプトしてアサーションエラーをトリガーする)とgdb(アサーションエラーがトリガーされるとすぐにコールスタックを表示する)を組み合わせて、実行する関数を確認しました。

また、PHP7 PCRE JITが原因であるという結論にも達しました。 php.iniにpcre.jit = 0を置くと、修正されました。

詳細な手順

  1. rootとしてマシンにログインします
  2. https://etbe.coker.com.au/2010/07/12/write-execute-mmap-ld-preload/ からmmap.cソースコードを/root/mmap.cにダウンロードします
  3. gcc -shared -g -fPIC mmap.c -o mmap.soでコードをビルドする
  4. mmap()呼び出しをインターセプトして、gdbを介してApacheを実行します:LD_PRELOAD=/root/mmap.so gdb /usr/sbin/httpd
  5. あなたはgdbに投げ込まれます。 Apacheは子プロセスをフォークするため、(gdb)プロンプトの後にset follow-fork-mode childと入力して、gdbに子プロセスにジャンプするように指示することが重要です。
  6. (gdb)プロンプトの後にrunと入力してApacheを開始します
  7. いくつかのHTTP要求がコードをトリガーするまで辛抱強く待って、次にmmapでアサーションをトリガーすると、gdbに戻ります。
プログラムはシグナルSIGABRT、Abortedを受け取りました。
 
 [スレッド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. bt(バックトレース)と入力して、コールスタックを表示します。
(gdb)../nptl/sysdeps/unix/sysv/linux/raise.c:56[.____にある__GI_raise(sig = sig @ entry = 6)のbt 
 
#0 0x00007ffff638d5f7 。] 
#1 0x00007ffff638ece8 in __GI_abort()at abort.c:90 
 
#2 0x00007ffff6386566 in __assert_fail_base(fmt = 0x7ffff64d6ca8 "%s%s%s:%u: %s%sAssertion `%s 'が失敗しました。\ 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 __GI___assert_failの0x00007ffff6386612(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/sljitExecAllocator.c:204 
 
#7 sljit_generate_code(compiler = compiler @ entry = 0x555555b14ad0)at sljit/sljitNativeX86_common.c:296 
のsljit_malloc_exec(size = 4440) .____。 external_re @ entry = 0x555555b14650、options = 1、errorptr = errorptr @ entry = 0x7fffffffa3c8)at pcre_study.c:1354 
 
#10 0x00007fffed2edcbc in pcre_get_compiled_regex_cache(regex = 0x7fffd8a/0x7rcfd8a/0)/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) /debug/php-7.0.9/ext/pcre/php_pcre.c:655


  1. 犯人は簡単に特定できます。スタックエントリ11はPCREを確認するためのヒントを提供し、エントリ5は失敗する実際のコールです。
6
Edward