Pacman: Landlock関連エラーの調査
What is this
Pacmanでのパッケージ更新時に出力された表題のエラーについて調査した際のメモ。
Stackable Linux Security Module(LSM)であるLandlockについても概要をまとめている。
背景
ArchLinuxを使っている中、pacmanでパッケージを更新しようとした際に以下のようなエラーメッセージが出力された。
error: restricting filesystem access failed because the landlock rule for the temporary download directory could not be added!
問題なくパッケージの更新は進んだように見えるがエラー発生の理由が判然としないため調査した。
環境
- OS: Arch Linux on WSL2(GNU/Linux 5.15.153.1-microsoft-standard-WSL2 x86_64)
- Pacman: Pacman v7.0.0 - libalpm v15.0.0
結論
Landlock ABIがv3未満の場合でもv3の機能をPacmanが利用してしまうことがエラーの原因だった。
現時点で修正コードが取り込まれているため、今後Pacman自体のアップデートで修正される見込み。
アップデートが来るまでは、pacmanコマンドに対して--disable-sandbox
オプションを付与してエラー出力を回避できる。
調査方法
以下のようにしてエラーの原因を調査した
- Landlockについて、そもそもどのような機能なのかドキュメントから調べた
- pacmanでのLandlockの使用方法についてRelease noteなどから調べた
- pacmanのどの箇所でエラーが出力されているかを調べた
- pacman(libalpm)をビルドし直してエラーの原因を調べた
調査結果
Landlockとは
本家ドキュメントやヘッダーファイルを読んでまとめた内容を示す。
本家ドキュメントは以下の通り。
概要
Linux Kernel 5.13から導入されたサンドボックス機能で、プロセスびその子孫プロセスのシステムリソース(ファイルシステムおよびTCPポート)に関する権限を制限することができる。
Stackable Linux Security Moduleの名の通り、既存のアクセス制限設定に重ねてアクセス制限を設定できる。
重ねてアクセスを制限するのみで、他の機能(AppArmorやseccomp等)でかけたアクセス制限を緩和するものではない。
Landlockにおいて各アクセス権はルールと呼ばれそれをまとめたものがルールセットと呼ばれる。
Landlock機能の有効化確認
Landlockが有効か無効かはカーネルログに"landlock: Up and running"と出力されているか否かで判断できる。
Linux Kernelのバージョンが5.13以上なのに上記ログが出力されていない場合、カーネルビルド時にCONFIG_SECURITY_LANDLOC=y
となっていない可能性がある。
アクセスの制限方法
ここでは対象をファイルシステムに限り、ざっくりとしたアクセスの制限方法を示す。
-
struct landlock_ruleset_attr
にデフォルトで許可しないルールを列挙する
ファイルシステムに関するルールはhandled_access_fs
というメンバにビットマスクで設定する -
landlock_create_ruleset()
に上記構造体を渡してルールセットを定義する -
struct landlock_path_beneath_attr
に許可するルールと対象のパスを定義する
ルールはallowed_access
というメンバにビットマスクを渡すことで設定する
対象のパスはparent_fd
というメンバにファイルディスクリプタを渡すことで設定する。 -
landlock_add_rule()
を用いてルールを適用する - 必要に応じ3,4を繰り返し、複数のパスに対してルールを適用する。
-
landlock_restrict_self()
を用いて自らのプロセスにルールセットを適用する。
PacmanでのLandlockの使用方法について
パッケージ関連ファイルをダウンロードする時、
ダウンロードを行うプロセスがダウンロードディレクトリ以外の場所にファイルをダウンロードさせないようLandlockが使われている。
この仕組みはPackman v7.0.0で導入されており、Release Notesの以下記載が該当する。
- Add DownloadUser configuation option used to drop-privileges when downloading files.
- Download files to a temporary directory owned by DownloadUser
- On Linux systems, ensure the download process does not write outside the download directory
- Add DisableSandbox option and --disable-sandbox flag to disable the download write restrictions on Linux systems
pacmanでのエラーメッセージ出力箇所について
今回のエラーメッセージは pacman/lib/libalpm/sandbox_fs.c
で出力されている。
$ git clone https://gitlab.archlinux.org/pacman/pacman.git -b v7.0.0 && cd pacman
$ rg 'restricting filesystem access failed because the landlock rule for the temporary download directory could not be added!' .
./lib/libalpm/sandbox_fs.c
160: _alpm_log(handle, ALPM_LOG_ERROR, _("restricting filesystem access failed because the landlock rule for the temporary download directory could not be added!\n"));
libalpmをビルドしエラーの原因を調査
sandbox_fs.c
を読むと、今回のエラーはlandlock_add_rule(2)
の戻り値が0でなかったためにエラーが出力されている。
sandbox_fs.c
を修正し、landlock_add_rule(2)
の戻り値を出力させたところ22になっていた。
landlock_add_rule(2)
のmanには生じうる戻り値が記載されており、22に該当するのはEINVALである。
EINVALの説明は以下の通り。
EINVAL: flags is not 0, or the rule accesses are inconsistent(i.e., rule_attr->allowed_access is not a subset of the ruleset handled accesses).
landlock_add_rule(2)
に渡しているflags
は0決め打ちなので、ruleset_attr.handled_access_fs
もしくは
path_beneath.allowed_access
が適切でなさそう。
実際両bitmaskを出力させてみると、以下のようにやはりpath_beneath.allowed_access
がruleset_attr.handled_access_fs
のサブセットになっていなかった。
struct | bitmask |
---|---|
ruleset_attr.handled_access_fs |
0001111111111111 |
path_beneath.allowed_access |
0101111111111110 |
太字で示しているLANDLOCK_ACCESS_FS_TRUNCATE
のフラグ(15bit目)がpath_beneath.allowed_access
で立っている。
sandbox_fs.c
において、landlock ABIがv3未満だとruleset_attr.handled_access_fs
からLANDLOCK_ACCESS_FS_TRUNCATE
のビットを消す処理がある一方でpath_beneath.allowed_access
からは消していないため不整合が起きていた。
対処
Pacmanのリポジトリでは既にMerge Requestがmasterに取り込まれているので、アップデートを待てばエラーは出力されなくなる見込み。
アップデート前に出力を抑えたい場合以下の方法がある。
-
--disable-sandbox
オプションをpacmanコマンドに付与する - カーネルをアップデートしLandlock ABIv3を利用可能にする
補足
この節でアクセス権はビットマスクで設定すると記載した。
ここではアクセス権とビットマスクの対応を示す。
ファイルシステムフラグ
Landlockで制限可能なファイルシステムへのアクセス権は以下の通り。
landlock_ruleset_attr.handled_access_fs
に渡すことでルールセットを定義する。
Name | Bitmask | 備考 |
---|---|---|
LANDLOCK_ACCESS_FS_EXECUTE |
0000000000000001 | |
LANDLOCK_ACCESS_FS_WRITE_FILE |
0000000000000010 | |
LANDLOCK_ACCESS_FS_READ_FILE |
0000000000000100 | |
LANDLOCK_ACCESS_FS_READ_DIR |
0000000000001000 | |
LANDLOCK_ACCESS_FS_REMOVE_DIR |
0000000000010000 | |
LANDLOCK_ACCESS_FS_REMOVE_FILE |
0000000000100000 | |
LANDLOCK_ACCESS_FS_MAKE_CHAR |
0000000001000000 | |
LANDLOCK_ACCESS_FS_MAKE_DIR |
0000000010000000 | |
LANDLOCK_ACCESS_FS_MAKE_REG |
0000000100000000 | |
LANDLOCK_ACCESS_FS_MAKE_SOCK |
0000001000000000 | |
LANDLOCK_ACCESS_FS_MAKE_FIFO |
0000010000000000 | |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
0000100000000000 | |
LANDLOCK_ACCESS_FS_MAKE_SYM |
0001000000000000 | |
LANDLOCK_ACCESS_FS_REFER |
0010000000000000 | Landlock ABIv2から利用可能 |
LANDLOCK_ACCESS_FS_TRUNCATE |
0100000000000000 | Landlock ABIv3から利用可能 |
LANDLOCK_ACCESS_FS_IOCTL_DEV |
1000000000000000 | Landlock ABIv5から利用可能 |
ネットワークフラグ
Landlockで制限可能なファイルシステムへのアクセス権は以下の通り。
landlock_ruleset_attr.handled_access_net
に渡すことでルールセットを定義する。
Name | Bitmask | 備考 |
---|---|---|
LANDLOCK_ACCESS_NET_BIND_TCP |
01 | Landlock ABIv4から利用可能 |
LANDLOCK_ACCESS_NET_CONNECT_TCP |
10 | Landlock ABIv4から利用可能 |
Discussion