マウントプロパゲーション(4)〜 unbindable mount 〜
引き続きマウントプロパゲーションについて書いていきます。完全に私個人が理解するための資料です。間違いの指摘は大歓迎です。そもそも、このシリーズ、カーネル付属ドキュメントと mount_namespaces(7) に書いてあるんですよねw
unbindableは、そのマウント自身が他でバインドマウントできないようにするための指定です。マウントプロパゲーションとは少し違うものに見えます。しかし、これはprivateと同じでさらにバインドマウントを禁止するフラグがついたものと考えることができます。
unbindableはセキュリティ対策的な意味合いがあります。配下に多数のマウントを持ったマウントポイントがあったとします(例えば /
なんかは通常はそうですよね)。その多数のマウントを持ったマウントを再帰的にバインドマウントするオプション(--rbind
)を指定して何度もバインドマウントするとどうでしょう? 配下には大量のバインドマウントが再帰的に出現することになり、「バインドマウントボム(bomb)攻撃」とも言える状態になってしまいます。これを防ぐためにこのような指定ができるようになっています。
簡単に試してみましょう。まずはトップレベルのマウントとしてtest
というディレクトリを作成し、ここをtmpfsでマウントします。このtest
というマウント配下にふたつディレクトリ(a
、b
)を作成し、その片方a
もtmpfsをマウントします。
# mkdir test # mount -t tmpfs tmpfs test (ディレクトリtestをtmpfsマウントする) # mkdir test/a # mount -t tmpfs tmpfs test/a (test/aディレクトリを作成しtmpfsマウントする) # mkdir test/b # tree . . └── test (←tmpfsマウント) ├── a (←tmpfsマウント) └── b (←ディレクトリ) 3 directories, 0 files
上のようにtmpfs配下にtmpfsとディレクトリがひとつずつある状態になります。
ここでディレクトリb
に親ディレクトリであるtest
をバインドマウントします。この際、再帰的にマウントするように--rbind
を指定します。
# mount --rbind test test/b # tree . . └── test ├── a (←tmpfsマウント) └── b (←バインドマウント) ├── a (←tmpfsマウント) └── b 5 directories, 0 files
再帰的にマウントしていますので、b
配下のa
(test/b/a
)はtmpfsとしてマウントされたまま見えています。
ここでtest
配下にc
というディレクトリを作成し、ここも上で行ったb
のように再帰的にマウントします。
# mkdir test/c # mount --rbind test test/c
再帰的にマウントしていますので、c
配下にはさきほど再帰的にマウントしたb
配下のマウントもすべて再帰的にマウントされています。そして、先に行ったバインドマウントb
以下にもc
が出現し、その配下でもb
配下のマウントが見えています。
# tree . . └── test ├── a (←tmpfsマウント) ├── b (←バインドマウント) │ ├── a (←tmpfsマウント) │ ├── b │ └── c (←バインドマウント) │ ├── a │ ├── b (←バインドマウント) │ │ ├── a (←tmpfsマウント) │ │ ├── b │ │ └── c │ └── c └── c (←バインドマウント) ├── a (←tmpfsマウント) ├── b (←バインドマウント) │ ├── a │ ├── b │ └── c └── c 19 directories, 0 files
これが繰り返されると、延々と再帰的なマウントが出現することになり、リソースを食いつぶすDoS攻撃が成り立ちます。このようなことを防ぐためにunbindableが存在します。
# mount -t tmpfs tmpfs test # mkdir test/{a,b} # mount -t tmpfs tmpfs test/a
ここまでは先程の例と同じです。さきほどの例では--rbind
とだけ指定したところで同時に--make-unbindable
を指定してバインドマウントします。
# mount --rbind --make-unbindable test test/b # tree . . └── test ├── a (←tmpfsマウント) └── b (←バインドマウント) ├── a (←tmpfsマウント,unbindable) └── b 5 directories, 0 files
ここでさきほどと同様にtest/c
を作成し、test
を--make-unbindable
でバインドマウントします。
# mkdir test/c # mount --rbind --make-unbindable test test/c # tree . . └── test ├── a (←tmpfsマウント) ├── b (←バインドマウント) │ ├── a (←tmpfsマウント,unbindable) │ ├── b │ └── c └── c (←バインドマウント) ├── a (←tmpfsマウント) ├── b └── c 10 directories, 0 files
unbindableを指定した以外は同じ操作を行っていますが、test/b
配下もtest/c
配下でもバインドマウントは再帰的に行われていません(tmpfsはマウントされています)。
このようにunbindableを指定すると爆発的にバインドマウントが増殖することを防げます。