一般ユーザー権限で chroot を使う

# chroot を使いたい

chroot 環境を作成し、一般ユーザー権限で使用するまでの手順をまとめます。
一般ユーザー権限での chroot を制限されている環境では、ファイルケーパビリティを設定した chroot (→mychroot) を作成して、制限を回避します。

```shell

$ cp -a /usr/sbin/chroot mychroot
$ sudo setcap cap_sys_chroot+ep mychroot

→chroot の代わりに mychroot を使う。
$ mychroot NEWROOT COMMAND
```

## どういうこと?

そもそもは、リモートからアップロードされたアーカイヴファイルを展開するのに、chroot を使いたいな…と思ったことが発端です。

例えば、こういう処理のとき:

```shell

$ cd /var/spool/upload/
$ tar xf ./archive.tar
$ unzip ./archive.zip
```

ここで、`/var/spool/upload/` に chroot して、tar や unzip を実行すれば、
悪意で作りこまれたアーカイヴで親ディレクトリを攻められも大丈夫だろう…という目算です。つまり

+ パストラヴァーサル攻撃への対策

を想定しています。

## 環境

CentOS 7 で確認しました。


# まずは chroot 環境を作成する

chroot するディレクトリを作り、その配下に chroot 環境下で使用するコマンドと、コマンドが使用する shared library を集めれば良いです。
例えば bash、touch、ls、rm だけ使える chroot 環境をざっくり作るには、以下のようにします。

```shell

chr="/path/to/testroot/"
mkdir -p $chr
mkdir -p $chr/{bin,lib,lib64}
cd $chr
cp -v /bin/{bash,touch,ls,rm} $chr/bin

for F in bin/*
do
    list="$(ldd ${F} | egrep -o '/lib.*\.[0-9]')"
    for i in $list; do cp -v --parents "$i" "${chr}"; done
done
```

※この手順は、[How to Use the chroot Command on Linux](https://www.howtogeek.com/441534/how-to-use-the-chroot-command-on-linux/) を参考にし、一部改変したものです。

この後、`chroot "${chr}"` で、chroot 環境に入ります。

…言うまでもありませんが、実運用に供するには、shell を削除する、パーミッションを厳しく設定する、など調整が必要ですよ。この chroot 環境では出来ることが多すぎて chroot の有難みが薄いです。


# 一般ユーザー権限で chroot 環境を使用するには

ところが一般ユーザー権限での chroot は、多くの環境で制限されています。
CentOS 7 で試したところ、以下のエラーが出ました。

```shell

$ chroot ./testroot
chroot: cannot change root directory to ./testroot: Operation not permitted
$
```

もちろん sudo が適切に設定されていれば `sudo chroot ./testroot` で入れますが…root 権限で  chroot 環境に入っても嬉しさ半減ですね。もっと小さい権限で入りたいところです。

さて、CentOS 7 において chroot のこの制限は、ケーパビリティの機能によって実現されています。なので一般ユーザーが chroot するには、**ケーパビリティ `cap_sys_chroot+ep` を追加した chroot を使う**手があります。

```shell

$ cp -a /usr/sbin/chroot mychroot
$ sudo setcap cap_sys_chroot+ep mychroot	# setcap には root 権限が必要です

# 確認:
$ getcap -v /usr/sbin/chroot
/usr/sbin/chroot
$ getcap -v ./mychroot
./mychroot = cap_sys_chroot+ep
$
```

この mychroot (=ケーパビリティ `cap_sys_chroot+ep` を追加した chroot)を使えば、一般ユーザー権限で chroot 環境を使用できます。

```shell

$ mychroot ./testroot
bash-4.2$

# 確認:
bash-4.2$ pwd
/
bash-4.2$ ls -lia .
total 0
 9623382 drwxrwxr-x. 4 1000 1000  30 Jan 12 01:27 .
 9623382 drwxrwxr-x. 4 1000 1000  30 Jan 12 01:27 ..  # inode が . と同じですね
19648905 drwxrwxr-x. 2 1000 1000  67 Jan 12 01:49 bin
26370704 drwxrwxr-x. 2 1000 1000 214 Jan 12 01:27 lib64
bash-4.2$
```

`/usr/sbin/chroot` に直接ファイルケーパビリティを設定するのは避けるべきでしょう。影響の範囲が OS 全体に及び、どこにどんな影響が出るのか把握が困難になるためです。代わりに、chroot をコピーした mychroot にファイルケーパビリティを追加し使用する方が、より良い方法です。

# その他

ファイルケーパビリティを設定したファイルは、`ls --color=auto` で色が付きます。

![dircolors.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/174932/cc7631ff-b91a-9b07-22e5-37c7b88e02b6.png)

dircolors に `CAPABILITY 30;41 # file with capability` の設定があります。`dircolors --print-database` で確認できます。

# 資料

## getcap / setcap

[linux - How to run a command in a chroot jail not as root and without sudo? - Stack Overflow](https://stackoverflow.com/questions/3737008/how-to-run-a-command-in-a-chroot-jail-not-as-root-and-without-sudo) の、Corey Henderson 氏のコメントが参考になりました。

> You can make use of linux capabilities to give your binary the ability to call chroot() w/o being root. As an example, you can do this to the `chroot` binary. As non\-root, normally you'd get this:
> 
> ```
> $ chroot /tmp/
> chroot: cannot change root directory to /tmp/: Operation not permitted
> ```
> 
> But after you run the `setcap` command:
> 
> ```
> sudo setcap cap_sys_chroot+ep /usr/sbin/chroot
> ```
> 
> It will let you do the chroot call.
> 
> I don't recommend you do this to the system's `chroot`, that you instead do it to your own program and call chroot. That way you have more control over what is happening, and you can even drop the cap\_sys\_chroot privilege after you call it, so successive calls to chroot in your program will fail.
> 
> ref. [linux - How to run a command in a chroot jail not as root and without sudo? - Stack Overflow](https://stackoverflow.com/questions/3737008/how-to-run-a-command-in-a-chroot-jail-not-as-root-and-without-sudo)



## capabilities / ケーパビリティ

man 7 capabilities から抜粋します。ケーパビリティがどんな要請から出来上がったものか良くわかります。

> 権限のチェックを行う観点から見ると、伝統的な UNIX の実装では プロセスは二つのカテゴリーに分類できる: 特権 プロセス (実効ユーザーID が 0 のプロセス。ユーザーID 0 は スーパーユーザーや root と呼ばれる) と 非特権 プロセス (実効ユーザーID が 0 以外のプロセス) である。 非特権プロセスでは、プロセスの資格情報 (通常は、実効UID 、実効GID と追加のグループリスト) に基づく権限チェックが行われるのに対し、 特権プロセスでは全てのカーネルの権限チェックがバイパスされる。
>
> バージョン 2.2 以降の Linux では、 これまでスーパーユーザーに結び付けられてきた権限を、 いくつかのグループに分割している。これらのグループは ケーパビリティ(capability) と呼ばれ、グループ毎に独立に有効、無効を設定できる。 ケーパビリティはスレッド単位の属性である。  
>
> **CAP\_SYS\_CHROOT**
>
> **[chroot](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/chroot.2.html)**(2). を呼び出す。
>
> ref. [Man page of CAPABILITIES](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/capabilities.7.html)

関連コマンド:

+ [getcap(8): examine file capabilities - Linux man page](https://linux.die.net/man/8/getcap)
+ [getpcaps(1) — libcap2-bin — Debian unstable — Debian Manpages](https://manpages.debian.org/unstable/libcap2-bin/getpcaps.1.en.html)
+ [setcap(8): set file capabilities - Linux man page](https://linux.die.net/man/8/setcap)
+ [capsh(1): capability shell wrapper - Linux man page](https://linux.die.net/man/1/capsh)

## fakeroot / fakechroot

fakeroot / fakechroot というコマンドがあるらしいです(未調査)。

> fakechroot - gives a fake chroot environment
>
> fakechroot runs a command in an environment were is additional possibility to use chroot(8) command without root privileges. This is useful for allowing users to create own chrooted environment with possibility to install another packages without need for root privileges.
>
> ref. [fakechroot(1): gives fake chroot environment - Linux man page](https://linux.die.net/man/1/fakechroot)


# 参考文献

+ [How to Use the chroot Command on Linux](https://www.howtogeek.com/441534/how-to-use-the-chroot-command-on-linux/)
+ [linux - How to run a command in a chroot jail not as root and without sudo? - Stack Overflow](https://stackoverflow.com/questions/3737008/how-to-run-a-command-in-a-chroot-jail-not-as-root-and-without-sudo)

capabilities:

+ [Man page of CAPABILITIES](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/capabilities.7.html)
+ [ケイパビリティ - ArchWiki](https://wiki.archlinux.jp/index.php/%E3%82%B1%E3%82%A4%E3%83%91%E3%83%93%E3%83%AA%E3%83%86%E3%82%A3)
+ [ケイパビリティ - mrtc0.log](http://mrtc0.hateblo.jp/entry/2015/12/08/204126)
+ [ケーパビリティ で権限を少しだけ与える - いますぐ実践! Linuxシステム管理 / Vol.183](http://www.usupi.org/sysad/183.html)