第656回ではChromeベースのEPUBリーダーをsnapパッケージ化してみました。今回はsnapパッケージ作成における最大のハードルと言える
snapパッケージにおけるセキュリティモデル
snapパッケージではアプリケーションを
- 古くから存在するディレクトリのパーミッションなどの任意アクセス制御
(DAC:Discretionary Access Controls) - AppArmorを活用した強制アクセス制御
(MAC:Mandatory Access Control) - seccompを利用したシステムコールの利用制限
- cgroupを利用したハードウェアリソースへのアクセス制御
つまりいわゆる
どれくらい隔離するかは、snapcraft.
に記述する
- devmode
-
パッケージの開発時にのみ利用する、
まったく隔離せずアクセスログのみを残すモード - strict
-
システムからは完全に隔離された状態で、
アクセスが必要な場合は個別に許可しなければならないモード - classic
-
従来のdebパッケージのように、
システムへのアクセスを許容するモード
このうちclassicは特殊なモードです。作ろうとしているsnapパッケージが、/media
にマウントされた)
つまりsnapパッケージを作るなら、
strictなパッケージが、
ネットワーク接続したいならnetworkインターフェース、
インターフェースは
言い換えるとsnapシステムに存在しないスロットに対するプラグは作れません。もしスロットが存在しないリソースを使いたいなら、
「strictに対応する」
Thorium Readerパッケージをstrictモードに変更する
第656回に引き続き
前回までの設定でdevmodeでなら動作することを確認しました。その時点でのコードはGitLabにアップロードしてあります。今回はここから進めましょう。
$ git clone https://gitlab.com/mtyshibata/thorium-reader-snap.git $ cd thorium-reader-snap $ git checkout -b v0.1 v0.1
strictモードへの対応は大まかに次の2つの手法が存在します。
- devmodeのまま動かしてシステムログから必要なリソースアクセスを洗い出す
- strictに変更して何が動かないかを確認する
strictモードでブロックされる挙動は、
$ sudo journalctl --since=now -f | grep thorium
その状態でThorium Readerを起動すると、
3月 13 16:55:45 nuc systemd[2904]: Started snap.thorium-reader-snap.thorium.940ea09d-aa26-4bf3-92d5-b7abb9eaa924.scope. 3月 13 16:55:45 nuc systemd[2904]: app-gnome-thorium\x2dreader\x2dsnap_thorium-86679.scope: Succeeded. 3月 13 16:55:45 nuc audit[86760]: AVC apparmor="ALLOWED" operation="open" profile="snap.thorium-reader-snap.thorium" (以下略)
特に
ただしシンプルなツールならこの方法でもなんとかなるのですが、
ちなみに今回のパッケージは、
strictモードの有効化
まずはsnap/
からstrictモードを有効化しましょう。
grade: devel
confinement: strict
confinement
をdevmode
からstrict
に変えるだけです。第656回の手順に従って、
$ snapcraft --debug --enable-experimental-extensions $ sudo snap install thorium-reader-snap_0.1_amd64.snap --dangerous thorium-reader-snap 0.1 installed
前回と異なるのはインストール時に--devmode
」
それでは実際に起動してみましょう。GUIシェルから起動すると、
$ thorium-reader-snap.thorium [126296:0313/173222.838179:FATAL:setuid_sandbox_host.cc(158)] The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now. You need to make sure that /snap/thorium-reader-snap/x5/opt/Thorium/chrome-sandbox is owned by root and has mode 4755. Trace/breakpoint trap (コアダンプ)
あっさりエラー終了してしまいました。
SUID sandboxに対応する
これは何のエラーかというとChromiumのLinux SUID Sandbox機能です。ThoriumはバックエンドにChromiumを利用しています。Chromiumにはセキュアなウェブブラウジングを実現するための機能の一つとして、setuid()
等を利用したLinux SUID Sandbox機能が存在します。
しかしながらsnap環境の中ではいくつかのシステムコールが制限されているため、
通常snapパッケージの中で使われるChromiumバイナリはこの機能を切ってビルドすることになります。今回はビルド済みのdebパッケージのバイナリをそのままもってきているため、--no-sandbox
」
試しにオプションを付けて起動してみましょう。
$ thorium-reader-snap.thorium --no-sandbox Gtk-Message: 17:51:53.911: Failed to load module "canberra-gtk-module" Gtk-Message: 17:51:53.912: Failed to load module "canberra-gtk-module" 中止 (コアダンプ)
別のところでエラー終了したものの、--no-sandbox
」snap/
を変更します。
変更するのは2箇所です。まず端末から実行するコマンドでも必ずオプションが付くように、
apps:
thorium:
command: opt/Thorium/thorium --no-sandbox
extensions: [gnome-3-38]
desktop: usr/share/applications/thorium.desktop
command
フィールドが変更された箇所です。これにより端末からthorium-reader-snap.
」--no-sandbox
」
もうひとつがデスクトップファイル側の対応です。GUIシェルから検索して起動する場合、thorium.
のようなデスクトップファイルのExec
フィールドが参照されます。ここのフィールドはthorium-reader-snap.
ではなく、
方法はいくつかあるものの、
parts:
thorium-reader:
source: https://github.com/edrlab/thorium-reader/releases/download/v1.6.0/EDRLab.ThoriumReader_1.6.0_amd64.deb
source-type: deb
plugin: dump
override-build: |
snapcraftctl build
sed -i 's|Icon=.*|Icon=/usr/share/icons/hicolor/0x0/apps/thorium.png|g' \
$SNAPCRAFT_PART_INSTALL/usr/share/applications/thorium.desktop
sed -i 's|/opt/Thorium/thorium|/opt/Thorium/thorium --no-sandbox|g' \
$SNAPCRAFT_PART_INSTALL/usr/share/applications/thorium.desktop
stage-packages:
- libnss3
override-build
フィールドの末尾に2行のコマンドを追加しています。やっていることはsed
で置き換えている、
あとは先ほどと同じようにビルド&インストールすれば、
エラーログから要因を探る
新しいエラーメッセージは次の内容でした。
$ thorium-reader-snap.thorium --no-sandbox Gtk-Message: 17:51:53.911: Failed to load module "canberra-gtk-module" Gtk-Message: 17:51:53.912: Failed to load module "canberra-gtk-module" 中止 (コアダンプ)
「canberra」sudo journalctl --since=now -f | grep thorium
」
たくさんセキュリティ関係のメッセージが表示されるはずです。そのまま貼り付けるには紙幅が足りないので、
SECCOMP syscall=41 compat=0 ip=0x7f4b81ed490b code=0x50000 apparmor="DENIED" operation="dbus_method_call" name="org.bluez" SECCOMP syscall=314 compat=0 ip=0x7f4b81ecc89d code=0x50000 apparmor="DENIED" operation="open" name="/etc/hosts" comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" apparmor="DENIED" operation="open" name="/etc/host.conf" comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" apparmor="DENIED" operation="open" name="/run/systemd/resolve/stub-resolv.conf" comm="ThreadPoolForeg" requested_mask="r" denied_mask="r" apparmor="DENIED" operation="mknod" name="/dev/shm/.org.chromium.Chromium.iKxChM" comm="Chrome_IOThread" requested_mask="c" denied_mask="c"
seccompはsyscall番号でログを表示します。syscall番号と実際の関数の対応を調べる方法はいろいろありますが、scmp_
コマンドを使ってみましょう。
$ sudo apt install seccomp $ scmp_sys_resolver 41 socket $ scmp_sys_resolver 314 sched_setattr
どうやらソケットを作るのとスケジューリングの設定関連の何かが呼ばれているようですmknod
ですね。
Bluetooth関連はPCによって実装されているかまちまちであるため、
ネットワーク通信関連はnetworkインターフェースを利用することで許可できます。snapパッケージは何も設定しないとネットワーク通信の権限がありません。networkインターフェースを追加することではじめて、
試しにインターフェースを追加してみましょう。前述したようにsnapパッケージ側のインターフェースは
apps:
thorium:
command: opt/Thorium/thorium --no-sandbox
extensions: [gnome-3-38]
plugs:
- network
desktop: usr/share/applications/thorium.desktop
「このsnapパッケージはnetworkプラグを利用します」
$ snap connections thorium-reader-snap Interface Plug Slot Notes (中略) network thorium-reader-snap:network :network - (後略)
networkプラグがスロットに追加されていますね。ちなみに他のインターフェースはgnomeエクステンションが自動的に追加したものです。
インターフェースは
手動で接続許可するものは
$ sudo snap connect thorium-reader-snap:<インターフェース名>
networkが繋がった状態でThoriumを起動し直してみましょう。引き続き起動しない状態ではあるものの、
browser-supportの有効化
残っているのはBluetoothとmknod
です。Bluetoothはbluezインターフェースが該当しそうですが、
検索してみると--no-sandbox
」
bluezとbrowser-supportを有効化しましょう。
apps:
thorium:
command: opt/Thorium/thorium --no-sandbox
extensions: [gnome-3-38]
plugs:
- bluez
- browser-support
- network
desktop: usr/share/applications/thorium.desktop
インストールしたあとはまずインターフェースの状態を確認してみます。
$ snap connections thorium-reader-snap Interface Plug Slot Notes bluez thorium-reader-snap:bluez - - browser-support thorium-reader-snap:browser-support :browser-support - (中略) network thorium-reader-snap:network :network - (後略)
期待通りに設定が行われていますね。bluezのみ接続されていません。必要なら次の方法で接続してください。
$ sudo snap connect thorium-reader-snap:bluez
もう一度Thorium Readerを起動してみましょう。今度は無事に起動できるようになっているはずです。
残りのログを確認する
無事に起動するようになったので、
まずは普通に動くようになった状態で、
/usr/share/libdrm/amdgpu.ids: No such file or directory (node:257885) electron: The default of contextIsolation is deprecated and will be changing from false to true in a future release of Electron. See https://github.com/electron/electron/issues/23506 for more information
後半のメッセージはElectron側の通知メッセージなので、/usr/
を読み込もうとします。snapパッケージの中にはこのファイルがないため、
実際のところ読めなくても実害はないものの、stage-packages
に追加しておくと良いでしょう。
layout:
/usr/share/libdrm:
bind: $SNAP/usr/share/libdrm
parts:
(中略)
stage-packages:
- libdrm-common
- libnss3
layoutはsnapパッケージ内部のファイルレイアウトのマッピングをコントロールする設定です。今回のThorium Readerのようにビルド済みバイナリを使う場合、/usr/
」/usr/
」
layoutは大変強力な機能なので、
もうひとつ確認すべきなのがjorunalctl側のログです。普通に動くようになったため、
sched_
setaffinity() sched_
setattr() org.
freedesktop. DBus. ListNames
最初の2つはChromiumによるプロセス優先度管理のために必要な機能です。実はChromiumでこの機能を使うためには、
今回はそこまですることのものでもないため、
後者については、
ホームディレクトリを読み書きできるようにする
snapパッケージはそのまままだとsnapパッケージディレクトリ/snap/パッケージ名/
)/var/
)、$HOME/
)
今回のように
これを実現できるのがhomeインターフェースとなります。ちなみにhomeインターフェースは隠しディレクトリは参照できません。設定によって参照できるようになるものの、
システムディレクトリを参照できるもう一つのインターフェースがremovable-mediaインターフェースです。こちらはより大容量のデータ置き場を使用したいsnapパッケージに向いているインターフェースとなります。
今回設定したプラグをまとめると次のような結果になります。
apps:
thorium:
command: opt/Thorium/thorium --no-sandbox
extensions: [gnome-3-38]
plugs:
- bluez
- browser-support
- home
- network
- system-observe
desktop: usr/share/applications/thorium.desktop
これでstrictモードでも、
ここまでのsnap/
の全体像はこちらのリポジトリから参照できます。
次回はSnap Storeに公開する話です。