詳細は伏せますがImageMagickを使っているウェブサービスで脆弱性報告がありまして、ImageMagickのコマンドを隔離したファイルシステムで動かせないかと考えました。
考えた方法
- docker
- アプリケーションを実行するユーザーにdocker権限をつけたくない
- アプリケーションサーバーでdocker-daemonを動かしたくない
- ただし
--net=noneはImageTragickみたいなのには効果的
-
droot, jailing
- アプリケーションを実行するユーザーでsudoしたくない
- (実行できるコマンドを絞ればいいのかもしれないが…)
- systemd-nspawn
- アプリケーションを実行するユーザーでsudoしたくない
- まだsystemdじゃないので…
- dockerの
--net=none相当があれば良いけど、無いっぽい?
- fakechroot
- runC
- sudoなしで実行できるようになるまではまだかかりそう
- https://github.com/opencontainers/runc/pull/774
- https://www.cyphar.com/blog/post/rootless-containers-with-runc
-
PRoot
- →試してみた
PRootとは
fakechrootがlibcの関数を置き換えるのに対し、PRootはptraceという仕組みを使ってファイルシステム関連のシステムコールを乗っ取るらしい
ビルドする
マニュアルによるとバイナリもあるみたいだけど、HTTPだし、そのサイトも無くなってるし、微妙かと思ってビルドしたらすんなりいけた。
$ sudo apt-get install libtalloc-dev
$ git clone https://github.com/proot-me/PRoot.git
$ cd PRoot/src
$ make
$ ./proot --help
使ってみる
例えばidentifyコマンド
$ mkdir -p /tmp/usr/bin
$ cp /usr/bin/identify /tmp/usr/bin/identify
$ proot --rootfs=/tmp --mount=/bin --mount=/lib --mount=/lib64 --mount=/usr/lib --pwd=/ identify --version
Version: ImageMagick 6.7.7-10 2014-03-08 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP
ただし、これだと他にマウントしないといけないディレクトリがあるかもしれないし、 /usr/bin とかを全部見せてしまっているのが気になる。
dockerを使ってrootfsを作る
$ docker run --name imagemagick alpine apk --no-cache add imagemagick
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.4/community/x86_64/APKINDEX.tar.gz
(1/25) Installing expat (2.1.1-r1)
(2/25) Installing libpng (1.6.21-r0)
(3/25) Installing freetype (2.6.3-r0)
(4/25) Installing fontconfig (2.12.1-r0)
(5/25) Installing libgomp (5.3.0-r0)
(6/25) Installing dbus-libs (1.10.8-r1)
(7/25) Installing libintl (0.19.7-r3)
(8/25) Installing avahi-libs (0.6.32-r0)
(9/25) Installing libgcc (5.3.0-r0)
(10/25) Installing gmp (6.1.0-r0)
(11/25) Installing nettle (3.2-r0)
(12/25) Installing libffi (3.2.1-r2)
(13/25) Installing libtasn1 (4.8-r0)
(14/25) Installing p11-kit (0.23.2-r0)
(15/25) Installing gnutls (3.4.15-r0)
(16/25) Installing libstdc++ (5.3.0-r0)
(17/25) Installing cups-libs (2.1.3-r1)
(18/25) Installing jbig2dec (0.12-r0)
(19/25) Installing libjpeg-turbo (1.4.2-r0)
(20/25) Installing lcms2 (2.7-r0)
(21/25) Installing tiff (4.0.6-r3)
(22/25) Installing ghostscript (9.19-r1)
(23/25) Installing libltdl (2.4.6-r0)
(24/25) Installing libwebp (0.5.0-r0)
(25/25) Installing imagemagick (6.9.5.9-r1)
Executing busybox-1.24.2-r11.trigger
Executing fontconfig-2.12.1-r0.trigger
OK: 65 MiB in 36 packages
$ docker export imagemagick | gzip > imagemagick.tar.gz
$ mkdir ~/imagemagick-rootfs
$ tar xzvf imagemagick.tar.gz -C ~/imagemagick-rootfs
.dockerenv
bin/
bin/ash
bin/base64
bin/bbconfig
bin/busybox
bin/cat
...
$ proot --rootfs=$HOME/imagemagick-rootfs --pwd=/ identify --version
Version: ImageMagick 6.9.5-9 Q16 x86_64 2016-10-21 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2016 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher Modules
Delegates (built-in): fontconfig freetype gslib jng jpeg lcms ltdl png ps tiff webp zlib
例えば /tmp/img/cat.jpg を変換したいとすると、
$ proot --rootfs=$HOME/imagemagick-rootfs --mount=/tmp/img --pwd=/ identify /tmp/img/cat.jpg
/tmp/img/cat.jpg JPEG 200x138 200x138+0+0 8-bit sRGB 6.23KB 0.000u 0:00.000
$ proot --rootfs=$HOME/imagemagick-rootfs --mount=/tmp/img --pwd=/tmp/img convert -resize 100x100 cat.jpg cat100.jpg
$ proot --rootfs=$HOME/imagemagick-rootfs --mount=/tmp/img --pwd=/ identify /tmp/img/cat100.jpg
/tmp/img/cat100.jpg JPEG 100x69 100x69+0+0 8-bit Gray 256c 2.16KB 0.010u 0:00.000
こうなる。
policy.xmlは外から指定できたほうがいいよねってことで、
$ proot --rootfs=$HOME/imagemagick-rootfs --mount=$HOME/my-policy.xml:/etc/ImageMagick-6/policy.xml --mount=/tmp/img --mount=/ --pwd=/tmp/img convert -resize 100x100 cat.jpg cat100.jpg
こうなる。
あと /dev /proc /sys あたりはマウントしておいたほうが良さそう。(何かの変換で Error in GnuTLS initialization: Failed to acquire random data. が出たので /dev をマウントした)