Linux: コマンドのパーミッションは正しいはずなのにsystemdからの起動で「Permission denied」が出た話

ソフトウェアの自動起動登録で地味に嵌ったのでメモ。

###### 実施環境：

```Linux:Linux
[root@testhost ~]# uname -a
Linux testhost 4.18.0-331.el8.x86_64 #1 SMP Thu Aug 19 16:49:03 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[root@testhost ~]# echo $SHELL
/bin/bash
```

###### 事象

最近のLinuxでは、サービス管理は systemd で行われるのが主流です。
そこで、以下のようにして自作のサービスを登録してみます。

```Linux:Linux
[root@testhost ~]# ls -l /usr/lib/systemd/system/test.service
-rw-r--r--. 1 root root 131 Aug 25 21:51 /usr/lib/systemd/system/test.service
[root@testhost ~]# cat /usr/lib/systemd/system/test.service
[Unit]
Description = TEST

[Service]
ExecStart   = /usr/local/test/test.sh
Type        = simple

[Install]
WantedBy    = default.target

[root@testhost ~]# ls -ld /usr/local/test
drwxrwxrwx. 2 root root 21 Aug 25 21:48 /usr/local/test
[root@testhost ~]# ls -l /usr/local/test/test.sh
-rwxrwxrwx. 1 root root 54 Aug 25 21:48 /usr/local/test/test.sh
[root@testhost ~]# cat /usr/local/test/test.sh
#!/bin/bash

while true
do
    sleep 10
done

exit 0

```

設定ファイルを読み込み、早速起動! ... と思いきや、なぜか上手くいきません。

```Linux:Linux
[root@testhost ~]# systemctl daemon-reload
[root@testhost ~]# systemctl start test.service
[root@testhost ~]# systemctl status test.service
• test.service - TEST
   Loaded: loaded (/usr/lib/systemd/system/test.service: disabled: vendor preset: disabled)
   Active: failed (Result: exitcode) since Wed 2021-08-25 21:57:22 EDT; 6s ago
  Process: 2518 ExecStart=/usr/local/test/test.sh (code=exited, status=203/EXEC)
 Main PID: 2518 (code=exited, status=203/EXEC)

Aug 25 21:57:22 testhost systemd[1]: started TEST.
Aug 25 21:57:22 testhost systemd[1]: test.service: Main process exited. code=exited status=203/EXEC
Aug 25 21:57:22 testhost systemd[1]: test.service: Failed with result 'exit-code'.
```

ステータスの日時で mesasges ログを確認してみると、「Permission denied」、すなわち起動コマンドに権限が足りていないようです。

```Linux:Linux
[root@testhost ~]# grep "Aug 25 21:57:22" /var/log/messages
Aug 25 21:57:22 testhost systemd[1]: started TEST.
Aug 25 21:57:22 testhost systemd[2518]: test.service: Failed to execute command: Permission denied
Aug 25 21:57:22 testhost systemd[2518]: test.service: Failed at step EXEC spawing /usr/local/test/test.sh: Permission denied
Aug 25 21:57:22 testhost systemd[1]: test.service: Main process exited. code=exited status=203/EXEC
Aug 25 21:57:22 testhost systemd[1]: test.service: Failed with result 'exit-code'.
Aug 25 21:57:22 testhost dbus-daemon[936]: [system] Activating service name='org.fedoraproject.Setroubleshootd' requested by ':1.21' (uid=0 pid=901 comm="/usr/sbin/sedispatch " label="system_u:system_r:auditd_t:s0") (using servicehelper)
```

あれっ、でも上で確認した通りパーミッションは 777 のはずでは...?

###### 原因

答えは、「 SELinux のパーミッションが足りない」でした。
ホームディレクトリで作成したものを /usr に移動したため、  SELinux のパーミッションがホームディレクトリ向けとなっていたのが原因です。

```Linux:Linux
[root@testhost ~]# ls -dZ /usr/local/test
unconfined_u:object_r:admin_home_t:s0 /usr/local/test
[root@testhost ~]# ls -Z /usr/local/test/test.sh
unconfined_u:object_r:admin_home_t:s0 /usr/local/test/test.sh
```

###### 解決方法

「 SELinux 自体を停止する」でもよいのですが、今回は SELinux を動かしたままなんとかしたいです。
そこで、 restorecon コマンドを使って SELinux のパーミッションを更新します。

```Linux:Linux
[root@testhost ~]# restorecon -R /usr/local/test
[root@testhost ~]# ls -dZ /usr/local/test
unconfined_u:object_r:usr_t:s0 /usr/local/test
[root@testhost ~]# ls -Z /usr/local/test/test.sh
unconfined_u:object_r:usr_t:s0 /usr/local/test/test.sh
```

更新できたので、もう一度起動してみます。

```Linux:Linux
[root@testhost ~]# systemctl start test.service
[root@testhost ~]# systemctl status test.service
• test.service - TEST
   Loaded: loaded (/usr/lib/systemd/system/test.service: disabled: vendor preset: disabled)
   Active: active (running) since Wed 2021-08-25 22:12:24 EDT; 6s ago
 Main PID: 2727 (test.sh)
    Tasks: 2 (limit: 3355442)
   Memory: 588.0K
   CGroup: /system.slice/test.service
           ├─2727 /bin/bash /usr/local/test/test.sh
           └─2728 sleep 10

Aug 25 22:12:24 testhost systemd[1]: Started TEST.
[root@testhost ~]# 
```

今度は上手くいきました。

パーミッションが足りているのに権限不足で怒られたら、 SELinux のパーミッションも確認してみようというお話でした。