SELinux有効時に、MariaDBの起動に失敗する件

MariaDB新規インストール時にはまったので、そのメモです。

環境です。

以下の条件時に発生するようです。

  • SELinux有効時
  • データファイルのパスをデフォルトから変更している
  • OS上のファイルアクセスのパーミッションは正しく与えている

何も考えずに起動しようとすると失敗します。rootで作業してます。

# systemctl start mariadb
Job for mariadb.service failed because the control process exited with error code. See "systemctl status mariadb.service" and "journalctl -xe" for details.

言われたとおり、journalctlコマンドを実行します。このjournalctlコマンドは、systemdで追加されたjournalというログ管理ツールのコマンドです。journalは、従来のrsyslogと並列してシステムログを管理しています。

# journalctl -xe
(中略)
 2月 02 03:11:37 localhost.localdomain systemd[1]: mariadb.service: main process exited, code=exited, status=1/FAILURE
 2月 02 03:11:37 localhost.localdomain systemd[1]: Failed to start MariaDB database server.
-- Subject: Unit mariadb.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit mariadb.service has failed.
--
-- The result is failed.
 2月 02 03:11:37 localhost.localdomain systemd[1]: Unit mariadb.service entered failed state.
 2月 02 03:11:37 localhost.localdomain systemd[1]: mariadb.service failed.
 2月 02 03:11:37 localhost.localdomain dbus-daemon[665]: dbus[665]: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servic
 2月 02 03:11:37 localhost.localdomain dbus[665]: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servicehelper)
 2月 02 03:11:37 localhost.localdomain polkitd[729]: Unregistered Authentication Agent for unix-process:58679:29284458 (system bus name :1.1259, objec
 2月 02 03:11:40 localhost.localdomain dbus[665]: [system] Successfully activated service 'org.fedoraproject.Setroubleshootd'
 2月 02 03:11:40 localhost.localdomain dbus-daemon[665]: dbus[665]: [system] Successfully activated service 'org.fedoraproject.Setroubleshootd'
 2月 02 03:11:41 localhost.localdomain setroubleshoot[58817]: SELinux is preventing /usr/sbin/mysqld from write access on the directory db. For comple
 2月 02 03:11:41 localhost.localdomain python[58817]: SELinux is preventing /usr/sbin/mysqld from write access on the directory db.

                                                       *****  Plugin catchall_labels (83.8 confidence) suggests   *******************

                                                       If you want to allow mysqld to have write access on the db directory
                                                       Then you need to change the label on db
                                                       Do
                                                       # semanage fcontext -a -t FILE_TYPE 'db'
                                                       where FILE_TYPE is one of the following: faillog_t, krb5_host_rcache_t, mysqld_db_t, mysqld_log
                                                       Then execute:
                                                       restorecon -v 'db'


                                                       *****  Plugin catchall (17.1 confidence) suggests   **************************

                                                       If you believe that mysqld should be allowed write access on the db directory by default.
                                                       Then you should report this as a bug.
                                                       You can generate a local policy module to allow this access.
                                                       Do
                                                       allow this access for now by executing:
                                                       # ausearch -c 'mysqld' --raw | audit2allow -M my-mysqld
                                                       # semodule -i my-mysqld.pp

従来のシスログのほうもみてみます。

# tail -n 50 /var/log/messages
(中略)
Feb  2 03:11:37 localhost mysqld: 2017-02-02 03:11:37 7ff596fac900  InnoDB: Operating system error number 13 in a file operation.
Feb  2 03:11:37 localhost mysqld: InnoDB: The error means mysqld does not have the access rights to
Feb  2 03:11:37 localhost mysqld: InnoDB: the directory.
Feb  2 03:11:37 localhost mysqld: 2017-02-02 03:11:37 7ff596fac900  InnoDB: Operating system error number 13 in a file operation.
Feb  2 03:11:37 localhost mysqld: InnoDB: The error means mysqld does not have the access rights to
Feb  2 03:11:37 localhost mysqld: InnoDB: the directory.
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [ERROR] InnoDB: Creating or opening /data/mariadb/db/ibdata1 failed!
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [ERROR] InnoDB: Could not open or create the system tablespace. If you tried to add new data files to the system tablespace, and it failed here, you should now edit innodb_data_file_path in my.cnf back to what it was, and remove the new ibdata files InnoDB created in this failed attempt. InnoDB only wrote those files full of zeros, but did not yet use them in any way. But be careful: do not remove old data files which contain your precious data!
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [ERROR] Plugin 'InnoDB' init function returned error.
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [Note] Plugin 'FEEDBACK' is disabled.
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [ERROR] Unknown/unsupported storage engine: InnoDB
Feb  2 03:11:37 localhost mysqld: 2017-02-02  3:11:37 140692776732928 [ERROR] Aborting
Feb  2 03:11:37 localhost systemd: mariadb.service: main process exited, code=exited, status=1/FAILURE
Feb  2 03:11:37 localhost systemd: Failed to start MariaDB database server.
Feb  2 03:11:37 localhost systemd: Unit mariadb.service entered failed state.
Feb  2 03:11:37 localhost systemd: mariadb.service failed.
Feb  2 03:11:37 localhost dbus-daemon: dbus[665]: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servicehelper)
Feb  2 03:11:37 localhost dbus[665]: [system] Activating service name='org.fedoraproject.Setroubleshootd' (using servicehelper)
Feb  2 03:11:40 localhost dbus[665]: [system] Successfully activated service 'org.fedoraproject.Setroubleshootd'
Feb  2 03:11:40 localhost dbus-daemon: dbus[665]: [system] Successfully activated service 'org.fedoraproject.Setroubleshootd'
Feb  2 03:11:41 localhost setroubleshoot: SELinux is preventing /usr/sbin/mysqld from write access on the directory db. For complete SELinux messages. run sealert -l 1e6eff03-fa03-4e93-892e-475cc9082d34
Feb  2 03:11:41 localhost python: SELinux is preventing /usr/sbin/mysqld from write access on the directory db.#012#012*****  Plugin catchall_labels (83.8 confidence) suggests   *******************#012#012If you want to allow mysqld to have write access on the db directory#012Then you need to change the label on db#012Do#012# semanage fcontext -a -t FILE_TYPE 'db'#012where FILE_TYPE is one of the following: faillog_t, krb5_host_rcache_t, mysqld_db_t, mysqld_log_t, mysqld_tmp_t, mysqld_var_run_t, tmp_t, var_lib_t, var_log_t, var_run_t.#012Then execute:#012restorecon -v 'db'#012#012#012*****  Plugin catchall (17.1 confidence) suggests   **************************#012#012If you believe that mysqld should be allowed write access on the db directory by default.#012Then you should report this as a bug.#012You can generate a local policy module to allow this access.#012Do#012allow this access for now by executing:#012# ausearch -c 'mysqld' --raw | audit2allow -M my-mysqld#012# semodule -i my-mysqld.pp#012

SELinuxに関するメッセージを見つけられます。SELinuxのアラート識別子が指定されれいるので、詳細を確認します。

# LANG=C sealert -l 1e6eff03-fa03-4e93-892e-475cc9082d34
SELinux is preventing /usr/sbin/mysqld from write access on the directory db.

*****  Plugin catchall_labels (83.8 confidence) suggests   *******************

If you want to allow mysqld to have write access on the db directory
Then you need to change the label on db
Do
# semanage fcontext -a -t FILE_TYPE 'db'
where FILE_TYPE is one of the following: faillog_t, krb5_host_rcache_t, mysqld_db_t, mysqld_log_t, mysqld_tmp_t, mysqld_var_run_t, tmp_t, var_lib_t, var_log_t, var_run_t.
Then execute:
restorecon -v 'db'

SELinux側にて、ファイルアクセスを防いでいる旨のメッセージが表示されます。SELinuxでは、すべてのプロセスとそのプロセスの関わるファイルを紐づけて管理しています。SELinuxコンテキストという概念らしいです。なので、勝手にデータファイルのパスを変更すると、そのSELinuxコンテキストが怒っちゃうんですね。解決手段も表示されているので、その通りに実行してあげます。

「semanage fcontext」コマンドは、そのSELinuxコンテキストの設定を恒久的に変更するためのコマンドです。FILE_TYPEには「mysqld_db_t」を指定し、データファイルのパスを引数に指定します。今回はデータファイルとREDOログのディレクトリが異なるので、以下の2行を実行。

# semanage fcontext -a -t mysqld_db_t '/data/mariadb/db(/.*)?'
# semanage fcontext -a -t mysqld_db_t '/data/mariadb/log(/.*)?'

restoreconコマンドで設定内容を反映させます。

# restorecon -v '/data/mariadb/db'
restorecon reset /data/mariadb/db context unconfined_u:object_r:unlabeled_t:s0->unconfined_u:object_r:mysqld_db_t:s0
# restorecon -v '/data/mariadb/log'
restorecon reset /data/mariadb/log context unconfined_u:object_r:unlabeled_t:s0->unconfined_u:object_r:mysqld_db_t:s0

設定内容は-lオプションで表示できます。

# semanage fcontext -l | grep mysqld
/etc/mysql(/.*)?                                   all files          system_u:object_r:mysqld_etc_t:s0
/etc/my\.cnf\.d(/.*)?                              all files          system_u:object_r:mysqld_etc_t:s0
/var/log/mysql.*                                   regular file       system_u:object_r:mysqld_log_t:s0
/var/lib/mysql(/.*)?                               all files          system_u:object_r:mysqld_db_t:s0
/var/run/mysqld(/.*)?                              all files          system_u:object_r:mysqld_var_run_t:s0
/var/log/mariadb(/.*)?                             all files          system_u:object_r:mysqld_log_t:s0
/var/run/mariadb(/.*)?                             all files          system_u:object_r:mysqld_var_run_t:s0
/usr/sbin/mysqld(-max)?                            regular file       system_u:object_r:mysqld_exec_t:s0
/var/run/mysqld/mysqlmanager.*                     regular file       system_u:object_r:mysqlmanagerd_var_run_t:s0
/usr/lib/systemd/system/mysqld.*                   regular file       system_u:object_r:mysqld_unit_file_t:s0
/usr/lib/systemd/system/mariadb.*                  regular file       system_u:object_r:mysqld_unit_file_t:s0
/etc/my\.cnf                                       regular file       system_u:object_r:mysqld_etc_t:s0
/root/\.my\.cnf                                    regular file       system_u:object_r:mysqld_home_t:s0
/usr/sbin/ndbd                                     regular file       system_u:object_r:mysqld_exec_t:s0
/usr/libexec/mysqld                                regular file       system_u:object_r:mysqld_exec_t:s0
/usr/bin/mysqld_safe                               regular file       system_u:object_r:mysqld_safe_exec_t:s0
/usr/bin/mysql_upgrade                             regular file       system_u:object_r:mysqld_exec_t:s0
/etc/rc\.d/init\.d/mysqld                          regular file       system_u:object_r:mysqld_initrc_exec_t:s0
/var/lib/mysql/mysql\.sock                         socket             system_u:object_r:mysqld_var_run_t:s0
/usr/libexec/mysqld_safe-scl-helper                regular file       system_u:object_r:mysqld_safe_exec_t:s0
/data/mariadb/db(/.*)?                             all files          system_u:object_r:mysqld_db_t:s0
/data/mariadb/log(/.*)?                            all files          system_u:object_r:mysqld_db_t:s0

間違えてしまった場合は-dオプションで削除できます。

# semanage fcontext -d '/data/mariadb/db(/.*)?'

これでSELinuxコンテキストの問題が解決したので、mariadbが起動できます。