coreファイルを生成,参照する方法


#1 はじめに　
systemdから起動されたプロセスのcoreファイル生成と、
systemdから起動されていないプロセスのcoreファイル生成方法について説明します。


#2 環境
VMware Workstation 12 Player上のゲストマシンを使っています。

```
[root@client ~]#cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)

[root@client ~]# uname -r
3.10.0-514.el7.x86_64
```

#3 systemdが起動したプロセスのcoreファイル生成方法

下記手順に従っても、coreファイルが出力されない場合、SELinuxのポリシー違反の可能性があります。
そのような場合、文末の手順に従ってルールを作成することで、coreファイルが出力されるようになります。

##3.1 一時的な設定方法

```console:実行結果
[root@client ~]# mkdir /var/lib/coredumps
[root@client ~]# ls -ld /var/lib/coredumps
drwxr-xr-x 2 root root 31  1月 21 09:16 /var/lib/coredumps

[root@client ~]# sysctl -w kernel.core_pattern="/var/lib/coredumps/core.%e.%p"
kernel.core_pattern = /var/lib/coredumps/core.%e.%p
[root@client ~]# sysctl -n kernel.core_pattern
/var/lib/coredumps/core.%e.%p

[root@client ~]# sysctl -w fs.suid_dumpable=2
fs.suid_dumpable = 2
[root@client ~]# sysctl -n fs.suid_dumpable
2

ユニット定義ファイルのServiceセクションにLimitCORE=infinity(★)を追加する。
[root@client ~]# cp /usr/lib/systemd/system/chronyd.service /etc/systemd/system
[root@client ~]# vi /etc/systemd/system/chronyd.service
[root@client ~]# cat /etc/systemd/system/chronyd.service
-中略-
[Service]
Type=forking
PIDFile=/var/run/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
ExecStartPost=/usr/libexec/chrony-helper update-daemon
LimitCORE=infinity ★
-以下、略-

ユニット定義ファイルの変更をsystemdに通知する。
[root@client ~]# systemctl daemon-reload

chronydを再起動する。
[root@client ~]# systemctl restart chronyd
[root@client ~]# ps -C chronyd
   PID TTY          TIME CMD
  1302 ?        00:00:00 chronyd

[root@client ~]# pkill -SIGSEGV chronyd
[root@client ~]# ps -C chronyd
   PID TTY          TIME CMD

coreファイルを確認する。PID=1302のcoreファイルが生成されていることがわかる。
[root@client ~]# ls -la /var/lib/coredumps/core.chronyd.1302
-rw------- 1 root chrony 9093120  1月 21 09:16 /var/lib/coredumps/core.chronyd.1302
```



##3.2 恒久的な方法
ここでは、OSがリブートしても、設定が有効になったままにする方法について説明します。


```console:実行結果
coreファイルを保存するディレクトリを作成する。
[root@client ~]# mkdir /var/lib/coredumps

[root@client ~]# vi /etc/sysctl.d/core.conf
[root@client ~]# cat /etc/sysctl.d/core.conf
kernel.core_pattern = /var/lib/coredumps/core.%e.%p
fs.suid_dumpable = 2

[root@client ~]# sysctl --system

設定を確認する。
[root@client ~]# sysctl -n kernel.core_pattern
/var/lib/coredumps/core.%e.%p

設定を確認する。
[root@client ~]# sysctl -n fs.suid_dumpable
2

ユニット定義ファイルのServiceセクションにLimitCORE=infinity(★)を追加する。
[root@client ~]# cp /usr/lib/systemd/system/chronyd.service /etc/systemd/system
[root@client ~]# vi /etc/systemd/system/chronyd.service
[root@client ~]# cat /etc/systemd/system/chronyd.service
-中略-
[Service]
Type=forking
PIDFile=/var/run/chronyd.pid
EnvironmentFile=-/etc/sysconfig/chronyd
ExecStart=/usr/sbin/chronyd $OPTIONS
ExecStartPost=/usr/libexec/chrony-helper update-daemon
LimitCORE=infinity ★
-以下、略-

OSを再起動する。
[root@client ~]# shutdown -r now

OS再起動後のSELinuxのモードを確認する。
[root@client ~]# getenforce
Permissive

プロセスの状態を確認する。
[root@client ~]# ps -C chronyd
   PID TTY          TIME CMD
   616 ?        00:00:00 chronyd

chronydプロセスにシグナル(SIGSEGV)を送信する。
[root@client ~]# pkill -SIGSEGV chronyd
[root@client ~]# ps -C chronyd
   PID TTY          TIME CMD

coreファイルを確認する。
[root@client ~]# ls -la /var/lib/coredumps/core.chronyd.613
-rw-------. 1 root chrony 9265152  5月 14 23:16 /var/lib/coredumps/core.chronyd.613
```


#4 systemdから起動しないプロセスのcoreファイル生成方法
##4.1 基本的な使い方

```
coreファイルのサイズを無制限に変更する。
[root@client core]# ulimit -c unlimited
[root@client core]# ulimit -c
unlimited

ここでは、core_patternをデフォルトのままで使用してみる。
デフォルトの場合、プログラムが実行されたディレクトリにcoreファイルが生成されます。
[root@client core]# cat /proc/sys/kernel/core_pattern
core

sleepプロセスを起動する。PIDは8783であることがわかる。
[root@client core]# sleep 300&
[1] 8783

sleepプロセスのulimitを確認する。coreファイルサイズが無制限(★)になっていることがわかる。
[root@client core]# cat /proc/8783/limits
Limit                     Soft Limit           Hard Limit           Units
Max core file size      ★unlimited            unlimited            bytes

sleepプロセスにシグナル(SIGSEGV)を送信する。
[root@client core]# pkill -SIGSEGV sleep

ファイルを確認する。coreファイルが生成されたことがわかる。
[root@client core]# ls
core.8783
[1]+  Segmentation fault      (コアダンプ) sleep 300
```

##4.2 coreファイルの格納場所や名前を変更する方法

```
coreファイルのサイズを無制限に変更する。
[root@client core]# ulimit -c unlimited
[root@client core]# ulimit -c
unlimited

coreファイルの格納場所を/tmp、coreファイルの名前はプロセス名(%e).プロセスID(%p)にする。
[root@client core]# echo '/tmp/core.%e.%p' > /proc/sys/kernel/core_pattern
[root@client core]# cat  /proc/sys/kernel/core_pattern
/tmp/core.%e.%p


sleepプロセスを起動する。PIDは8861であることがわかる。
[root@client core]# sleep 300&
[1] 8861

sleepプロセスのulimitを確認する。coreファイルサイズが無制限(★)になっていることがわかる。
[root@client core]# cat /proc/8861/limits
Limit                     Soft Limit           Hard Limit           Units
Max core file size      ★unlimited            unlimited            bytes

sleepプロセスにシグナル(SIGSEGV)を送信する。
[root@client core]# pkill -SIGSEGV sleep

ファイルを確認する。coreファイルが生成されたことがわかる。
[root@client core]# ls /tmp/core.sleep.8861
/tmp/core.sleep.8861
[1]+  Segmentation fault      (コアダンプ) sleep 300
```

#5 coreファイルの参照方法
ここでは、生成したcoreファイルをgdbで参照する方法について説明します。
gdbでcoreファイルを参照するには、debuginfoパッケージをインストールする必要があります。

##5.1 chronyd
ここでは、chronydのcoreファイルをgdbで参照してみます。

```console:debuginfoパッケージのインストール
chronyパッケージの版数を確認する。
[root@client ~]# rpm -qa|grep chrony
chrony-2.1.1-4.el7.centos.x86_64

chronyパッケージと同じ版数のdebuginfoパッケージをインストールする。
[root@client ~]# yum --disablerepo=* --enablerepo=base-debuginfo install chrony-debuginfo-2.1.1-4.el7.centos.x86_64

chronyのdebuginfoパッケージ(★)がインストールされたことがわかる。
[root@client ~]# rpm -qa|grep chrony
chrony-2.1.1-4.el7.centos.x86_64
chrony-debuginfo-2.1.1-4.el7.centos.x86_64 ★
```

```console:gdbによるcoreファイル参照
[root@client ~]# gdb /var/lib/coredumps/core.chronyd.1302
-中略-
(gdb) set pagination off
(gdb) bt full
#0  0x00007fc672386ba3 in select () from /lib64/libc.so.6
No symbol table info available.
#1  0x00007fc6731aedf9 in SCH_MainLoop () at sched.c:650
        rd = {fds_bits = {6, 0 <repeats 15 times>}}
        status = <optimized out>
        errsv = <optimized out>
        tv = {tv_sec = 0, tv_usec = 127043}
        saved_tv = {tv_sec = 0, tv_usec = 167708}
        ptv = 0x7ffdc1a5ff40
        now = {tv_sec = 1516493770, tv_usec = 715689}
        saved_now = {tv_sec = 1516493770, tv_usec = 715689}
        cooked = {tv_sec = 1516493770, tv_usec = 714225}
        err = 0
        __PRETTY_FUNCTION__ = "SCH_MainLoop"
        __FUNCTION__ = "SCH_MainLoop"
#2  0x00007fc6731a48a4 in main (argc=0, argv=0x7ffdc1a60200) at main.c:534
        conf_file = <optimized out>
        progname = 0x7ffdc1a60f8c "/usr/sbin/chronyd"
        user = 0x7fc674728460 "chrony"
        debug = 0
        nofork = 0
        address_family = 0
        do_init_rtc = 0
        restarted = 0
        other_pid = <optimized out>
        lock_memory = 0
        sched_priority = 0
        system_log = 1
        config_args = <optimized out>
        __FUNCTION__ = "main"
```


##5.2 httpd
ここでは、httpdのcoreファイルをgdbで参照してみます。

```console:debuginfoパッケージのインストール(httpd)
httpdパッケージの版数を確認する。
[root@client ~]# rpm -qa|grep httpd
httpd-2.4.6-67.el7.centos.6.x86_64
httpd-tools-2.4.6-67.el7.centos.6.x86_64

[root@client ~]# yum --disablerepo=* --enablerepo=base-debuginfo install httpd-debuginfo-2.4.6-67.el7.centos.6.x86_64

httpdのdebuginfoパッケージ(★)がインストールされたことがわかる。
[root@client ~]# rpm -qa|grep httpd
httpd-2.4.6-67.el7.centos.6.x86_64
httpd-tools-2.4.6-67.el7.centos.6.x86_64
httpd-debuginfo-2.4.6-67.el7.centos.6.x86_64 ★
```

```console:debuginfoパッケージのインストール(glibc)
glibcパッケージの版数を確認する。
[root@client ~]# rpm -qa|grep glibc
glibc-common-2.17-157.el7.x86_64
glibc-2.17-157.el7.x86_64
glibc-devel-2.17-157.el7.x86_64
glibc-headers-2.17-157.el7.x86_64

[root@client ~]# yum --disablerepo=* --enablerepo=base-debuginfo install glibc-debuginfo-2.17-157.el7.x86_64

glibcのdebuginfoパッケージ(★)がインストールされたことがわかる。
[root@client ~]# rpm -qa|grep glibc
glibc-common-2.17-157.el7.x86_64
glibc-debuginfo-common-2.17-157.el7.x86_64
glibc-2.17-157.el7.x86_64
glibc-devel-2.17-157.el7.x86_64
glibc-debuginfo-2.17-157.el7.x86_64 ★
glibc-headers-2.17-157.el7.x86_64
```

```console:gdbによるcoreファイル参照
[root@client ~]# ls -l /var/lib/coredumps/core.httpd.*
-rw------- 1 root root   2678784  1月 21 09:38 /var/lib/coredumps/core.httpd.1393
-rw------- 1 root apache 2678784  1月 21 09:38 /var/lib/coredumps/core.httpd.1394
-rw------- 1 root apache 2678784  1月 21 09:38 /var/lib/coredumps/core.httpd.1395
-rw------- 1 root apache 2678784  1月 21 09:38 /var/lib/coredumps/core.httpd.1396
-rw------- 1 root apache 2678784  1月 21 09:38 /var/lib/coredumps/core.httpd.1397
-rw------- 1 root apache 2678784  1月 21 09:38 /var/lib/coredumps/core.httpd.1398

[root@client ~]# gdb /var/lib/coredumps/core.httpd.1393
-中略-
(gdb) set pagination off
(gdb) bt full
#0  0x00007f85c9e88b83 in __select_nocancel () at ../sysdeps/unix/syscall-template.S:81
No locals.
#1  0x00007f85ca59f585 in apr_sleep () from /lib64/libapr-1.so.0
No symbol table info available.
#2  0x00007f85cb8c2971 in ap_wait_or_timeout (status=status@entry=0x7ffef45e7608, exitcode=exitcode@entry=0x7ffef45e760c, ret=ret@entry=0x7ffef45e7610, p=<optimized out>, s=<optimized out>) at mpm_common.c:195
        rv = <optimized out>
#3  0x00007f85c14dc13e in prefork_run (_pconf=<optimized out>, plog=<optimized out>, s=<optimized out>) at prefork.c:1016
        status = 32645
        pid = {pid = -1, in = 0x7f8500000000, out = 0x7f85cc390450, err = 0x3}
        child_slot = <optimized out>
        exitwhy = (APR_PROC_SIGNAL_CORE | unknown: 3228138712)
        processed_status = <optimized out>
        index = <optimized out>
        remaining_children_to_start = 0
        rv = <optimized out>
#4  0x00007f85cb8c215e in ap_run_mpm (pconf=pconf@entry=0x7f85cc2f8138, plog=0x7f85cc325358, s=0x7f85cc31f310) at mpm_common.c:96
        pHook = <optimized out>
        n = 0
        rv = -1
#5  0x00007f85cb8baed6 in main (argc=2, argv=0x7ffef45e7908) at main.c:783
        c = 68 'D'
        showcompile = 0
        showdirectives = 0
        confname = 0x7f85cb8f95cf "conf/httpd.conf"
        def_server_root = 0x7f85cb8f95c4 "/etc/httpd"
        temp_error_log = 0x0
        error = <optimized out>
        process = 0x7f85cc2f6218
        pconf = 0x7f85cc2f8138
        plog = 0x7f85cc325358
        ptemp = 0x7f85cc323348
        pcommands = 0x7f85cc31a248
        opt = 0x7f85cc31a338
        rv = <optimized out>
        mod = 0x7f85cbb18098 <ap_prelinked_modules+24>
        opt_arg = 0x7ffef45e7f7d "FOREGROUND"
        signal_server = <optimized out>
```


#Y SELinuxのルール作成方法


##Y.1 ポリシー違反時のエラーメッセージ
coreファイルが出力されない原因の1つに、SELinuxのポリシーに違反している可能性があります。
そのような場合、/var/log/audit/audit.logに下記エラーメッセージが出力されます。

```
type=ANOM_ABEND msg=audit(1526305553.727:554): auid=4294967295 uid=998 gid=996 ses=4294967295 subj=system_u:system_r:chronyd_t:s0 pid=24252 comm="chronyd" reason="memory violation" sig=11
type=AVC msg=audit(1526305553.728:555): avc:  denied  { create } for  pid=24252 comm="chronyd" name="core.chronyd.24252" scontext=system_u:system_r:chronyd_t:s0 tcontext=system_u:object_r:var_lib_t:s0 tclass=file
type=SERVICE_STOP msg=audit(1526305553.736:556): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=chronyd comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=failed'
```

##Y.2 ルールの作成方法

```console:ppファイルの作成
[root@centos74 ~]# audit2allow -M test < /var/log/audit/audit.log
******************** IMPORTANT ***********************
To make this policy package active, execute:

semodule -i test.pp
```

```console:audit2allowにより生成したファイル
[root@centos74 ~]# ls test.*
test.pp  test.te
```

```console:test.ppの中身の確認
[root@centos74 ~]# cat test.te

module test 1.0;

require {
        type chronyd_t;
        type tmp_t;
        type var_lib_t;
        class file { create open read write };
        class dir write;
}

#============= chronyd_t ==============

#!!!! WARNING: 'tmp_t' is a base type.
allow chronyd_t tmp_t:dir write;

#!!!! WARNING 'chronyd_t' is not allowed to write or create to var_lib_t.  Change the label to chronyd_var_lib_t.
allow chronyd_t var_lib_t:file { create open read write };
```

```console:モジュールのインストール
[root@centos74 ~]# semodule -i test.pp
[root@centos74 ~]# semodule -l|grep -w test
test    1.0
```


#Z 参考
[Enable Core Dump systemd](https://pve.proxmox.com/wiki/Enable_Core_Dump_systemd)
[CentOS7の/etc/sysctl.d/以下の設定ファイルの反映方法](http://tsunokawa.hatenablog.com/entry/2015/09/02/175619)
[Enable core dumps for systemd services on CentOS 7](http://wangpidong.blogspot.jp/2016/06/enable-core-dumps-for-systemd-services.html)