/var/tmp にプログラムを置くのはまずい話

Red Hatの森若です。

今日は /var/tmp にプログラムを置いて使うのはまずいという話です。

うちの /var/tmp/hoge.py 動いてるよ?

日常的な操作の中で特にひっかかることもなく /var/tmp/hoge.py のようなスクリプトを作成して実行できます。 そのため「標準的なディレクトリじゃないから『お作法としてよくない』って話でしょ」と思われる方もいるかもしれません。

しかしファイルシステム上のパスによって決まった動作をする仕組みがいくつかあるので、実際上の問題が懸念されます。

systemd-tmpfiles による削除

systemd-tmpfiles は設定に従ってファイルの作成や削除を行うプログラムです。 systemd-tmpfiles の設定内容は各パッケージが追加できるため、特に設定を変更していなくてもシステムにより異なります。 現在の設定を取得するには systemd-tmpfiles --cat-config とします。systemd-tmpfilesの設定は1行ずつ独立したフォーマットなので、grepなどで関連する項目を搾り込めます。

$ systemd-tmpfiles --cat-config | grep /var/tmp
R /var/tmp/dnf*/locks/*
R! /var/tmp/ostree-unlock-ovl.*
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp
R! /var/tmp/systemd-private-*
q /var/tmp 1777 root root 30d

最後の q /var/tmp 1777 root root 30d という行が /var/tmp についての設定です。 man systemd-tmpfiles から辿って man tmpfiles.d を見ると設定内容を読みとけます。

  • q は、 ディレクトリを作成することを示しています。後述のクリーンアップではディレクトリそのものではなくディレクトリ以下にあるファイルやディレクトリ等が削除対象になります。
  • /var/tmp 1777 root root は作成するディレクトリの名前とパーミッション設定とUID, GIDです。
  • 30d は、30日以上アクセスされていないファイルやディレクトリがクリーンアップ対象となることを意味します。

systemd-tmpfiles によるファイル作成はシステム起動直後に実施します。 systemd-tmpfiles によるクリーンアップはシステム起動後15分経過したタイミングと、その後1日おきに実施されます。

/var/tmp/hoge.py が起動時に1回実行されるだけだとすると、30日経過後のクリーンアップで削除されます。 システム構築時には「プログラムにアクセスせずに30日以上経過する」ことは稀でしょうから、気付きにくい問題と言っていいかと思います。

SELinuxによる実行拒否

SELinuxのtargeted policyが有効な場合、 /var/tmp/ 以下に作成されたファイルは tmp_t または user_tmp_t になります。targeted policyでは対話的に利用しているユーザによる操作はほぼ制限されませんので気付きにくいですが、systemdからサービスとして呼び出すような利用を行うと実行に失敗します。

タイプがuser_tmp_tになっています。

$ ls -lZ /var/tmp/hoge.py 
-rwxr-xr-x. 1 moriwaka moriwaka unconfined_u:object_r:user_tmp_t:s0 34 Oct  5 14:06 /var/tmp/hoge.py

一般のユーザとして実行すると成功します。

$ /var/tmp/hoge.py
hoge

systemdから実行させるため systemd-run で実行を指示します。

$ systemd-run /var/tmp/hoge.py 
Running as unit: run-u11294.service

ログを見るとPermission deniedで失敗したことがわかります。

$ journalctl -u run-u11294.service
Oct 05 14:06:27 turtle systemd[1]: Started run-u11294.service - /var/tmp/hoge.py.
Oct 05 14:06:27 turtle systemd[994555]: run-u11294.service: Failed to locate executable /var/tmp/hoge.py: Permission denied
Oct 05 14:06:27 turtle systemd[994555]: run-u11294.service: Failed at step EXEC spawning /var/tmp/hoge.py: Permission denied
Oct 05 14:06:27 turtle systemd[1]: run-u11294.service: Main process exited, code=exited, status=203/EXEC
Oct 05 14:06:27 turtle systemd[1]: run-u11294.service: Failed with result 'exit-code'.

こちらは明確に失敗しますから、問題自体には簡単に気付けます。 systemdがuser_tmp_tのファイルを実行しようとして失敗するので、journalctl _PID=994555 のように検索するとSELinuxが実行を拒否しているログを発見できます。

Oct 05 14:06:27 turtle audit[994555]: AVC avc:  denied  { execute } for  pid=994555 comm="(hoge.py)" name="hoge.py" dev="dm-0" ino=9766447 scontext=system_u:system_r:init_t:s0 tcontext=unconfined_u:object_r:user_tmp_t:s0 tclass=file permissive=0

まとめ

/var/tmpにプログラムを配置すると、 systemd-tmpfilesによるファイル削除やSELinuxによる実行拒否の問題があります。 /usr/local/bin または /opt/ 以下に置きましょう。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。